У меня есть собственный атрибут, который я использую для тестирования анализатора кода Roslyn, который я пишу:
[AttributeUsage( validOn: AttributeTargets.Class | AttributeTargets.Interface, Inherited = false, AllowMultiple = true )]
public class DummyAttribute : Attribute
{
public DummyAttribute( string arg1, Type arg2 )
{
}
public int TestField;
}
, который украшает другой тестовый класс:
[Dummy( "", typeof( string ) )]
[Dummy( "test", typeof( int ) )]
[Dummy( "test", typeof( int ) )]
public class J4JLogger<TCalling> : IJ4JLogger<TCalling>
{
Но когда я вызовите GetSymbolInfo () для него с моделью semanti c, в которой она определена:
model.GetSymbolInfo( attrNode ).Symbol
значение Symbol равно нулю.
Странно, что вызов GetSymbolInfo () работает отлично хорошо для классов атрибутов, определенных в базовой библиотеке Net (например, AttributeUsage
).
Оба Dummy
и J4JLogger
определены в одном проекте. Я создаю свой модуль компиляции, анализируя файлы по отдельности (например, J4JLogger
анализируется и анализируется отдельно от Dummy
), поэтому при анализе J4JLogger
нет ссылки на сборку, содержащую как J4JLogger
, так и Dummy
.
Может ли быть проблема в том, что model
на самом деле не содержит класс Dummy
, который, я думаю, содержит? Есть ли способ проверить, что в модели semanti c? Нужно ли включать ссылку на сборку, исходный файл которой я анализирую в модели semanti c?
Исправленный логический анализ c
My Исходные логики синтаксического анализа c анализировали каждый файл в синтаксическом дереве независимо от всех его родственных исходных файлов. Правильный способ анализа исходных файлов - по крайней мере, когда они зависят друг от друга - выглядит примерно так:
protected virtual (CompilationUnitSyntax root, SemanticModel model) ParseMultiple( string primaryPath, params string[] auxPaths )
{
if( !IsValid )
return (null, null);
CSharpCompilation compilation;
SyntaxTree primaryTree;
var auxFiles = auxPaths == null || auxPaths.Length == 0
? new List<string>()
: auxPaths.Distinct().Where( p => !p.Equals( primaryPath, StringComparison.OrdinalIgnoreCase ) );
try
{
var auxTrees = new List<SyntaxTree>();
primaryTree = CSharpSyntaxTree.ParseText( File.ReadAllText( primaryPath ) );
auxTrees.Add( primaryTree );
foreach( var auxFile in auxFiles )
{
var auxTree = CSharpSyntaxTree.ParseText( File.ReadAllText( auxFile ) );
auxTrees.Add( auxTree );
}
compilation = CSharpCompilation.Create( ProjectDocument.AssemblyName )
.AddReferences( GetReferences().ToArray() )
.AddSyntaxTrees( auxTrees );
}
catch( Exception e )
{
Logger.Error<string>( "Configuration failed, exception message was {0}", e.Message );
return (null, null);
}
return (primaryTree.GetCompilationUnitRoot(), compilation.GetSemanticModel( primaryTree ));
}
Небольшая ошибка заключается в том, что AddSyntaxTrees () не выглядит инкрементным; вам нужно добавить все соответствующие синтаксические деревья за один вызов AddSyntaxTrees ().