如何在roslyn中将字段声明转换为单独的自动属性?

时间:2017-02-09 07:45:13

标签: c# roslyn roslyn-code-analysis

我正在编写使用.NET编译器平台(Roslyn)进行代码修复的代码分析器。我需要将所有(非密封的)公共字段转换为单独的自动属性,因为我知道FieldDeclarationSyntax可以在一行中有多个字段声明,基于下面的Stackoverflow问题中的代码示例。

此处讨论了多字段声明的这一事实:How to get a Roslyn FieldSymbol from a FieldDeclarationSyntax node?

我要分析的示例代码是:

    public int AnyNumericField = 0;
    public string AnyStringField = "";
    // multiple field declaration sample
    public int field1, field2, field3 = 0;
    public StringBuilder sb1 = new StringBuilder();

我希望将代码修复程序纳入其中:

    public int AnyNumericField { get; set; } = 0;
    public string AnyStringField { get; set; } = "";
    // multiple field declaration sample
    public int field1 { get; set; } = 0; 
    public int field2 { get; set; } = 0; 
    public int field3 { get; set; } = 0;
    public StringBuilder sb1 { get; set; } = new StringBuilder();

我目前的分析器代码是:

    private void AnalyzePublicField(SymbolAnalysisContext context)
    {
        var aPublicField = (IFieldSymbol)context.Symbol;
        if ((aPublicField.DeclaredAccessibility == Accessibility.Public) && (!aPublicField.IsSealed))
        {
            var diagnostic = Diagnostic.Create(RuleCA1501, aPublicField.Locations[0], aPublicField.Name);

            context.ReportDiagnostic(diagnostic);
        }
    }

我的问题是,如何为此编写代码修复程序?我是否需要更改分析器以传递FieldDeclarationSyntax而不是字段符号? 我找不到任何具体的示例,说明如何将多行字段声明转换/转换为单独的自动属性。

更新1: 到目前为止,我的理解是使用此代码构建一个auto属性:

                PropertyDeclarationSyntax @propSymbol = SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName(fieldSymbol.MetadataName), memberName).AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword));

                @propSymbol = @propSymbol.AddAccessorListAccessors(
                    SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
                        .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)
                        ));
                @propSymbol = @propSymbol.AddAccessorListAccessors(
                    SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
                    .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)
                    ));

PropertyDeclarationSyntax的代码受本文的启发:https://dogschasingsquirrels.com/2014/08/04/code-generation-with-roslyn-fields-and-properties/

1 个答案:

答案 0 :(得分:1)

在codefix中,您可以使用以下代码访问VariableDeclarationSyntax

var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
var syntaxNode = root.FindNode(diagnosticSpan);
var variableDeclarator = syntaxNode.FirstAncestorOrSelf<VariableDeclaratorSyntax>();
var variableDeclaration = variableDeclarator?.Parent as VariableDeclarationSyntax;

此声明可能有许多声明符,但它们共享相同的可见性和修饰符,因此您需要全部修复它们。这意味着您将为它们生成相应的属性,然后您需要将上述variableDeclaration替换为生成的属性。

您可能希望查看此示例,了解同一声明中的多个变量如何分成各自的声明:https://github.com/SonarSource-VisualStudio/sonaranalyzer-dotnet/blob/master/src/SonarAnalyzer.CSharp/Rules/MultipleVariableDeclarationCodeFixProvider.cs

BTW,我想

public int field1, field2, field3 = 0;

应转换为

public int field1 { get; set; }
public int field2 { get; set; }
public int field3 { get; set; } = 0;

而不是

public int field1 { get; set; } = 0; 
public int field2 { get; set; } = 0; 
public int field3 { get; set; } = 0;

另请注意,此转换可能会破坏您的代码。例如,如果您将字段作为refout传递,那么它就无法更改为属性。