У меня есть специальный анализатор roslyn, который применяет правила именования на основе определенных деталей реализации метода в его родительском классе, т.е.
public abstract class ChildEntity : ParentEntity;
public abstract class ParentEntity
{
protected void IsAwesome()
{
...
}
}
В этом случае мой анализатор создаст диагностику, что-то вроде «ChildEntity следует переименовать, чтобы оно начиналось с «Awesome», поскольку оно наследуется от Awesome Parent». Это правило и диагностика работают правильно и создают ошибки как при анализе кода Intellisense, так и при попытке построить проект, которому принадлежат ChildEntity
и ParentEntity
.
Однако если ParentEntity
находится в другом проекте, чем ChildEntity
, и на него ссылаются через PackageReference, только Intellisense показывает ошибку, но сборка проекта проходит. Почему расположение ParentEntity
влияет на это? Мне нужно, чтобы сборка не удалась независимо от того, в каком проекте ParentEntity
находится.
Мой семантический анализатор проверяет символ NamedType
(например, ChildEntity
), находит его родительский класс и оттуда оценивает его методы, если таковые имеются. Если ему необходимо создать ошибку, он создает ее в расположении класса ChildEntity
и только там.
Сначала я не понимал, в каких случаях сборки проходят/не работают, но ошибки Intellisense всегда отображались. Я пытался принудительно запустить анализаторы, используя различные реквизиты в файле .csproj и Director.build.props, но ничего не дало никаких результатов. Наконец, после того, как я заметил, что виновато расположение родительской сущности, я создал небольшой тестовый проект, чтобы проверить, является ли поведение последовательным в более простой форме, и так оно и было. Я не уверен, отличается ли компиляция roslyn между Intellisense и фактической сборкой, похоже, что это так. Подробные результаты сборки показывают, что CoreCompile запускается для каждого случая. Другие анализаторы, такие как StyleCop, также запускаются для каждого случая.
Мой анализатор устанавливается как пакет nuget, а не как установка VSIX. Версия целевой платформы анализатора — .Net Standard 2.0, и я использую анализатор в проектах, работающих с той же версией, и .Net Framework 4.7.2.
Каковы шаги по созданию собственного анализатора Roslyn? Если вы следите за определенными документами, не могли бы вы поделиться ссылкой на документ? Можно ли поделиться воспроизводимым примером без личной информации (шаги и код), чтобы я мог воспроизвести проблему?
Кажется, я разобрался с проблемой, но все еще работаю над решением. Итак, как выяснилось, свойство DeclaringSyntaxReferences
объекта ISymbol
, расположенного снаружи, возвращает пустое значение, поскольку компиляция исходного кода roslyn во время сборки имеет доступ только к ссылочным DLL, а не к самому синтаксическому дереву. Однако в Intellisense в IDE, похоже, есть доступ ко всем проектам, на которые имеются ссылки, поскольку они не были упакованы каким-либо конкретным образом. Мой анализатор необходимо переписать или применить новый, совершенно другой подход. Я буду обновлять то, что найду.
Анализаторы Roslyn имеют доступ только к синтаксическому дереву в исходном коде, поэтому мой анализатор при проверке символа внешнего INamedTypeSymbol
(родительского класса вне проекта, который анализатор запускал) не смог вызвать свойство DeclaringSyntaxReferenced
для проверки метода. Это свойство вернет значение NULL или пустой массив, поэтому ошибка не возникнет. Поскольку символы родительского класса поступают как «Метаданные» через ссылку на сборку или проект, они не имеют синтаксической информации, предоставляемой после их упаковки или компиляции в библиотеку или DLL. Однако Intellisense собирает синтаксическую информацию в IDE и может генерировать необходимую диагностику.
Таким образом, обходное решение, которое я реализовал, состоит в том, чтобы проверить свойства символа IsInMetadata
и IsInSource
и обработать случай сборки (когда IsInMetadata
имеет значение TRUE, а IsInSource
имеет значение FALSE), чтобы проверить имя родительского класса, которое начинается с «Awesome», а не пытаюсь синтаксически проанализировать метод «IsAwesome». В обратном случае, например, для Intellisense (когда IsInMetadata
имеет значение FALSE, а IsInSource
имеет значение TRUE), мы выполняем синтаксический анализ, поскольку у нас есть доступ к синтаксическому дереву в компиляции исходного кода.
Похоже, что диагностика, сгенерированная вашим анализатором, подхватывается IntelliSense, но она не приводит к сбою сборки при компиляции проекта. Это может произойти по нескольким причинам. Различия в конфигурации сборки. Конфигурация сборки, используемая Visual Studio во время анализа IntelliSense, может отличаться от той, которая использовалась во время фактической сборки. Контекст выполнения анализатора. Контекст, в котором выполняются анализаторы Roslyn, может отличаться в зависимости от IntelliSense и процесса сборки.