В обратном вызове действия DiagnosticAnalyzer, как мне получить документ или проект, из которого был получен SyntaxNode?

#roslyn-code-analysis

#roslyn-code-analysis

Вопрос:

я пишу DiagnosticAnalyzer и регистрирую SyntaxNode действие SyntaxKind.Attribute . Атрибут называет какой-либо другой файл в проекте.

Например, анализируемый код может включать


[RelatedFile("otherFileName.foo")]
interface Whatever {...}

В моем обратном вызове анализа я хочу иметь доступ к содержимому связанного файла с точки зрения анализируемого проекта. Итак, мне нужно:

  1. Извлеките имя файла из SyntaxNode . Я могу это сделать.
  2. Получить объект, описывающий документ, содержащий анализируемый код. Я не знаю, как это сделать.
  3. Получить объект, описывающий проект, содержащий анализируемый код. Я не знаю, как это сделать.
  4. Узнайте, содержит ли проект документ с указанным именем. Я могу это сделать.
  5. Откройте и проанализируйте или обновите содержимое этого файла. Я думаю, что смогу это сделать.

Я застрял на шагах (2) и (3). (Да, возможно, мне не обязательно выполнять шаг 2, но я все равно хотел бы знать, как.)

Из SyntaxNodeAnalysisContext параметра я могу получить Workspace объект, а из него Solution объект, а из него коллекцию Project объектов. Но я не вижу способа связать конкретное SyntaxNode обратно с Project или Document , из которого оно пришло.

Любые идеи о том, как это сделать, будут оценены.

Ответ №1:

Я его нашел:

 Workspace workspace = ...;
SyntaxNode node = ...;
Document document = workspace.Solution.GetDocument(node.SyntaxTree);
Project project = document.Project;
 

Я не знаю, почему я не видел этого раньше.
Редактировать: теперь я знаю, почему я не видел его раньше. Получение Workspace доступа к требует использования непубличного свойства AnalyzerOptions .

Вы можете получить Workspace от SyntaxNodeAnalysisContext через…

 SyntaxNodeAnalysisContext context = ...;
AnalyzerOptions options = context.Options;
Workspace workspace = (Workspace)
    (options.GetType().GetRuntimeProperty("Workspace").GetValue(options));
 

Это не красиво, но это работает. Хотелось бы, чтобы был лучший способ.

Комментарии:

1. Джим, не мог бы ты объяснить, как ты получаешь рабочую область из syntaxnodeanalysisiscontext ?

2. Спасибо, Джим. Я не знаю, лучший ли это способ, но вы также можете получить рабочее пространство, как описано Джошем Варти . Если вы не находитесь в VSPackage, вы можете вызвать GetService с помощью ServiceProvider . GlobalProvider в Microsoft.VisualStudio. Оболочка. Для этого могут потребоваться ссылки, которые вы строго не должны использовать при анализе кода. В исправлении кода (но не в анализе кода) вы можете импортировать рабочую область как компонент MEF.