Roslyn: добавить операторы using в синтаксическое дерево

#c# #roslyn #roslyn-code-analysis

#c# #roslyn #roslyn-анализ кода

Вопрос:

Я успешно создал codefix, который генерирует фабричные методы, если они отсутствуют в общем классе factory. Когда я просматриваю исправленный файл, я получаю ряд ошибок из-за отсутствия инструкций using.

Я смог создать список UsingDirectives, которые я хочу добавить в свой переработанный файл. Как я могу добавить эти инструкции usings в файл?

     private async Task<Solution> FixUpFactory(Document document, TypeDeclarationSyntax typeDecl, CancellationToken cancellationToken)
        {
...
var factorySyntaxTree = factoryClass.DeclaringSyntaxReferences.Select(x => x.SyntaxTree);
var factoryDocument = document.Project.GetDocument(factorySyntaxTree.FirstOrDefault());
var usingDirectives = FindUsingDirectives(factorySyntaxTree.FirstOrDefault());
var methodUsingDirectives = FindMethodUsingDirectives(createMethods);
var usingDirectivesToAdd = new SyntaxList<UsingDirectiveSyntax>(methodUsingDirectives.Except(usingDirectives).Distinct());
...
//replace 
var factoryTree = await factoryDocument.GetSyntaxTreeAsync();
var compUnitSyntax = factoryTree.GetCompilationUnitRoot();
var newCompUnitSyntax = compUnitSyntax.WithUsings(usingDirectivesToAdd);

var documentRoot = await factoryDocument.GetSyntaxRootAsync().ConfigureAwait(false);
//newRoot comes out the same as the documentRoot
var newRoot= documentRoot.ReplaceNode(compUnitSyntax, newCompUnitSyntax);
var factorySolution = document.Project.Solution.WithDocumentSyntaxRoot(factoryDocument.Id, newRoot);
}
  

Итак, как я могу заставить newRoot отражать новые директивы using, которые я хотел бы добавить?

Ответ №1:

В итоге я немного разбил свой код. Оба они сработали:

 private SyntaxTree UpdateUsingDirectives(SyntaxTree originalTree, UsingDirectiveSyntax[] newUsings)
{
    var rootNode = originalTree.GetRoot() as CompilationUnitSyntax;
    rootNode = rootNode.AddUsings(newUsings).NormalizeWhitespace();
    return rootNode.SyntaxTree;
}
  
 private SyntaxTree UpdateUsingDirectives(SyntaxTree originalTree, SyntaxList<UsingDirectiveSyntax> newUsings)
{
    var rootNode = originalTree.GetRoot() as CompilationUnitSyntax;
    rootNode = rootNode.WithUsings(newUsings).NormalizeWhitespace();
    return rootNode.SyntaxTree;
}
  

Обратите внимание, что вторая инструкция заменяет инструкции usings.

После этого вы можете сделать что-то вроде:

 var newFactory = UpdateUsingDirectives(factoryTree, newUsings);
var newFactoryRoot = newFactory.GetRoot();

var documentRoot = await factoryDocument.GetSyntaxRootAsync().ConfigureAwait(false);

var newRoot= documentRoot.ReplaceNode(document.getRoot(), newFactoryRoot);
var factorySolution = document.Project.Solution.WithDocumentSyntaxRoot(factoryDocument.Id, newRoot);