我正在为C#代码构建一个分析器,当使用字符串文字而不是某些函数的某些参数的const字符串时,会生成错误。即
class MyClass
{
private void MyMethod(IWriter writer)
{
writer.WriteInteger("NamedValue", 4);
}
}
应该成为:
class MyClass
{
private const string IoNamedValueKey = "NamedValue";
private void MyMethod(IWriter writer)
{
writer.WriteInteger(IoNamedValueKey , 4);
}
}
我在显示错误的位置工作,但我也想提供CodeFixProvider。我遇到了两个问题:
private const string IoNamedValueKey = "NamedValue";
语句,理想情况就是在有问题的方法之上。我不完全确定CodeFixProvider的模板方法是否为我的目的使用了适当的重载(它只是用大写变体替换了类型名称),那么RegisterCodeFixesAsync方法中最好的方法是什么呢?
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
// ... now what?
}
根据roslynquoter的说法,所需的节点可以如下构建,但我仍然对如何将其注入上下文感到茫然。
CompilationUnit()
.WithMembers(
SingletonList<MemberDeclarationSyntax>(
FieldDeclaration(
VariableDeclaration(
PredefinedType(
Token(SyntaxKind.StringKeyword)))
.WithVariables(
SingletonSeparatedList<VariableDeclaratorSyntax>(
VariableDeclarator(
Identifier("IoNamedValueKey"))
.WithInitializer(
EqualsValueClause(
LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal("NamedValue")))))))
.WithModifiers(
TokenList(
new []{
Token(SyntaxKind.PrivateKeyword),
Token(SyntaxKind.ConstKeyword)}))))
.NormalizeWhitespace()
答案 0 :(得分:2)
您应该通过CodeAction
注册引入已更改文档的context
。对于
SyntaxNodes
- 您可以使用CSharp
SyntaxFactory 以下是您的代码可能类似的示例(已更新):
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
var argument = root.FindNode(diagnosticSpan);
if (!IsBadStringLiteralArgument(argument))
{
return;
}
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
CodeAction.Create(
title: title,
createChangedDocument: (ct) => InlineConstField(context.Document, root, argument, ct),
equivalenceKey: title),
diagnostic);
}
private async Task<Document> InlineConstField(Document document, SyntaxNode root, SyntaxNode argument, CancellationToken cancellationToken)
{
var stringLiteral = (argument as ArgumentSyntax).Expression as LiteralExpressionSyntax;
string suggestdName = this.GetSuggestedName(stringLiteral);
var containingMember = argument.FirstAncestorOrSelf<MemberDeclarationSyntax>();
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var containingMemberSymbol = semanticModel.GetDeclaredSymbol(containingMember);
var takenNames = containingMemberSymbol.ContainingType.MemberNames;
string uniqueName = this.GetUniqueName(suggestdName, takenNames);
FieldDeclarationSyntax constField = CreateConstFieldDeclaration(uniqueName, stringLiteral).WithAdditionalAnnotations(Formatter.Annotation);
var newRoot = root.ReplaceNode(containingMember, new[] { constField, containingMember });
newRoot = Formatter.Format(newRoot, Formatter.Annotation, document.Project.Solution.Workspace);
return document.WithSyntaxRoot(newRoot);
}
private FieldDeclarationSyntax CreateConstFieldDeclaration(string uniqueName, LiteralExpressionSyntax stringLiteral)
{
return SyntaxFactory.FieldDeclaration(
SyntaxFactory.List<AttributeListSyntax>(),
SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PrivateKeyword), SyntaxFactory.Token(SyntaxKind.ConstKeyword)),
SyntaxFactory.VariableDeclaration(
SyntaxFactory.ParseTypeName("string"),
SyntaxFactory.SingletonSeparatedList(
SyntaxFactory.VariableDeclarator(
SyntaxFactory.Identifier(uniqueName),
argumentList: null,
initializer: SyntaxFactory.EqualsValueClause(stringLiteral)))));
}