Я занимаюсь анализатором кода, но не могу найти способ изменить класс и члены, к которым обращаются при вызове метода. Например, если у меня есть
public class FirstClass
{
public static void DoSomething(object SomeParameter)
{
//method body
}
}
public class SecondClass
{
public static void ReplaceDoSomething(object SomeParameter)
{
//other method's body
}
}
Как я могу изменить свое исправление кода FirstClass.DoSomething(new object());
на SecondClass.ReplaceDoSomething(new object());
?
Я пытался использовать SyntaxFactory
, но я не могу понять, какие параметры ожидаются для большинства методов, и MSDN почти не предоставляет подробностей о них ...
Анализатор кода
public override void Initialize(AnalysisContext context)
{
context.RegisterOperationAction(Analyze, OperationKind.Invocation);
}
private void Analyze(OperationAnalysisContext context)
{
IInvocationOperation operation = (IInvocationOperation)context.Operation;
if (operation.TargetMethod.Name == "DoSomething" && operation.TargetMethod.ContainingNamespace.Name == "FirstNamespace" && operation.TargetMethod.ContainingType.Inherits("FirstNamespace.FirstClass"))
{
//Rule is an automaticaly generated variable by visual studio when you create the analyzer
Diagnostic diagnostic = Diagnostic.Create(Rule, operation.Syntax.GetLocation());
context.ReportDiagnostic(diagnostic);
}
}
public static class INamedTypeSymbolExtensions
{
public static bool Inherits(this INamedTypeSymbol first, string otherFullName)
{
if (first.GetFullName() == otherFullName)
{
return true;
}
else if (typeof(object).FullName == first.GetFullName())
{
return false;
}
else
{
return first.BaseType.Inherits(otherFullName);
}
}
public static string GetFullName(this INamedTypeSymbol element)
{
StringBuilder ret = new StringBuilder(element.Name);
INamespaceSymbol ContainingNamespace = element.ContainingNamespace;
while (ContainingNamespace.ContainingNamespace != null)
{
ret.Insert(0, ContainingNamespace.Name + ".");
ContainingNamespace = ContainingNamespace.ContainingNamespace;
}
return ret.ToString();
}
}
РЕДАКТИРОВАТЬ : лучший результат, который я получил, был с
private async Task<Document> ProvideCodeFix(Document document, InvocationExpressionSyntax invocation, CancellationToken cancellationToken)
{
SyntaxToken replaced = invocation.GetFirstToken();
SyntaxToken replacing = SyntaxFactory.IdentifierName("SecondClass").GetFirstToken().WithLeadingTrivia(replaced.LeadingTrivia));
return document.WithSyntaxRoot((await document.GetSyntaxRootAsync()).ReplaceToken(replaced, replacing);
}
при этом изменится FirstClass.DoSomething(new object());
на SecondClass.DoSomething(new object());
Но главная проблема с этим подходом заключается в том, что если бы мне пришлось изменить FirstNamespace.FirstClass.DoSomething(new object());
на SecondClass.ReplaceDoSomething(new object());
, тогда он не работал бы
PS: я использую .WithLeadingTrivia(...)
, чтобы сохранить комментарии и такие вещи, которые были написаны до FirstClass