Formatting 为什么这个代码修复程序会破坏我的琐事?

Formatting 为什么这个代码修复程序会破坏我的琐事?,formatting,roslyn,Formatting,Roslyn,我正在开发一个代码修复程序,使用roslyn来修复无效的抛出表达式。代码修复程序通常会执行它应该执行的操作,但是它会使我的代码变形,这将在下一个屏幕截图中显示 代码修复之前的格式 cedefix之后的格式 我尝试格式化生成语法的语法可视化 代码修复 有人知道我做错了什么吗?我曾尝试用DocumentEditor进行代码修复(通常不会给我带来这样的麻烦),但我也遇到了同样的问题。像下面这样更改一些代码是可行的,但我不喜欢。似乎奇怪的是,正确地保存琐事只能像这样工作 if (root.Find

我正在开发一个代码修复程序,使用roslyn来修复无效的抛出表达式。代码修复程序通常会执行它应该执行的操作,但是它会使我的代码变形,这将在下一个屏幕截图中显示

代码修复之前的格式

cedefix之后的格式

我尝试格式化生成语法的语法可视化

代码修复
有人知道我做错了什么吗?我曾尝试用DocumentEditor进行代码修复(通常不会给我带来这样的麻烦),但我也遇到了同样的问题。

像下面这样更改一些代码是可行的,但我不喜欢。似乎奇怪的是,正确地保存琐事只能像这样工作

if (root.FindNode(diagnostic.Location.SourceSpan) is ThrowStatementSyntax throwSyntax)
{
    var newThrowStatement = throwSyntax
        .WithExpression(SyntaxFactory.ParseExpression(""));

    var editor = await DocumentEditor.CreateAsync(context.Document, context.CancellationToken);
    editor.ReplaceNode(throwSyntax, newThrowStatement);

    return editor.GetChangedDocument();
}
1) 您是否尝试从现有的
ThrowStatementSyntax
创建一个新的
ThrowStatementSyntax
,而不是创建一个全新的<代码>throwSyntax..WithLeadingTrivia(throwSyntax.ThrowKeyword.LeadingTrivia)2)在应用新的
ThrowStatementSyntax
之后,是否尝试规范化根目录中的缩进和空白<代码>重写=重写。规范化空白(…)@GeorgeAlexandria 1)这就是我的代码看起来的样子2)这正确格式化了代码,但使用空格而不是制表符,如中配置的那样IDE@GeorgeAlexandria也不行
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class DoNotRethrowAnalyzer : DiagnosticAnalyzer
{
    public const string DiagnosticId = DiagnosticIds.DoNotRethrowAnalyzer.DoNotRethrowRule;

    // You can change these strings in the Resources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat.
    // See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Localizing%20Analyzers.md for more on localization
    private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.DoNotRethrowTitle), Resources.ResourceManager, typeof(Resources));
    private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.DoNotRethrowMessageFormat), Resources.ResourceManager, typeof(Resources));
    private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.DoNotRethrowDescription), Resources.ResourceManager, typeof(Resources));
    private const string Category = "Debuggability";

    private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning,
        isEnabledByDefault: true,
        description: Description);

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }

    public override void Initialize(AnalysisContext context)
    {
        context.RegisterSyntaxNodeAction(AnalyzeThrowExpression, SyntaxKind.ThrowStatement);
    }

    private void AnalyzeThrowExpression(SyntaxNodeAnalysisContext context)
    {
        if (context.Node is ThrowStatementSyntax throwSyntax)
        {
            if (throwSyntax.Expression == null)
                return;

            if(throwSyntax.Expression is IdentifierNameSyntax throwIdentifier 
                && ThrowIdentifierIsIdentifierOfParentClause(throwIdentifier))
                context.ReportDiagnostic(Diagnostic.Create(DoNotRethrowAnalyzer.Rule, throwSyntax.ThrowKeyword.GetLocation()));
        }
    }

    private bool ThrowIdentifierIsIdentifierOfParentClause(IdentifierNameSyntax throwIdentifier)
    {
        var parentCatch = throwIdentifier.NextParentOfType<CatchClauseSyntax>();
        if (parentCatch == null || parentCatch.Declaration == null)
            return false;

        return parentCatch.Declaration.Identifier.ValueText == throwIdentifier.Identifier.ValueText;
    }
}
[TestClass]
public class DoNotRethrowTests : CodeFixVerifier
{
    //No diagnostics expected to show up
    [TestMethod]
    public void TestEmptyFile()
    {
        var test = @"";

        VerifyCSharpDiagnostic(test);
    }

    [TestMethod]
    public void InvalidRethrow()
    {
        var test = @"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class TYPENAME
    {  
        void Offender(){
            throw new Exception(""testa"");
        } 

        void Process(Exception e){
            throw new Exception(""testa"");
        } 

        void Source()
        {
            try
            {
                Offender();
            }
            catch (Exception e)
            {
                Process(e);
                throw e;
            }
        }
    }
}";
        var expected = new[]
        {
            new DiagnosticResult
            {
                Id = DoNotRethrowAnalyzer.DiagnosticId,
                Message = Resources.DoNotRethrowMessageFormat,
                Severity = DiagnosticSeverity.Warning,
                Locations =
                    new[]
                    {
                        new DiagnosticResultLocation("Test0.cs", 30, 6)
                    }
            }
        };

        VerifyCSharpDiagnostic(test, expected);

        var expectedFix = @"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class TYPENAME
    {  
        void Offender(){
            throw new Exception(""testa"");
        } 

        void Process(Exception e){
            throw new Exception(""testa"");
        } 

        void Source()
        {
            try
            {
                Offender();
            }
            catch (Exception e)
            {
                Process(e);
                throw;
            }
        }
    }
}";
        VerifyCSharpFix(test, expectedFix);
    }

    class TYPENAME
    {
        void Offender()
        {
            throw new Exception("testa");
        }

        void Process(Exception e)
        {
            throw new Exception("testa");
        }

        void Source()
        {
            try
            {
                Offender();
            }
            catch (Exception e)
            {
                Process(e);
                throw;
            }
        }
    }

    //Diagnostic and CodeFix both triggered and checked for
    [TestMethod]
    public void ValidRethrow()
    {
        var test = @"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class TYPENAME
    {  
        void Offender(){
            throw new Exception(""testa"");
        } 

        void Source()
        {
            try
            {
                Offender();
            }
            catch (Exception e)
            {
                throw new Exception(""test"", e);
            }
        }
    }
}";
        var expected = new DiagnosticResult[0];

        VerifyCSharpDiagnostic(test, expected);
    }

    protected override CodeFixProvider GetCSharpCodeFixProvider()
    {
        return new DoNotRethrowCodeFixProvider();
    }

    protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
    {
        return new DoNotRethrowAnalyzer();
    }
}
if (root.FindNode(diagnostic.Location.SourceSpan) is ThrowStatementSyntax throwSyntax)
{
    var newThrowStatement = throwSyntax
        .WithExpression(SyntaxFactory.ParseExpression(""));

    var editor = await DocumentEditor.CreateAsync(context.Document, context.CancellationToken);
    editor.ReplaceNode(throwSyntax, newThrowStatement);

    return editor.GetChangedDocument();
}