我正在编写使用.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/
答案 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;
另请注意,此转换可能会破坏您的代码。例如,如果您将字段作为ref
或out
传递,那么它就无法更改为属性。