0

We have some custom roslyn analyzers for one of our .net project. Some of the rules need to analyze all base classes deep of a given ClassDeclaration. The problem is, that we also need the SematicModel which belongs to the base classes in order to resolve the GetDeclaredSymbol of that ClassDeclaration. Currently we are getting the SemanticModel by resolving it at the SyntaxNodeAnalysisContext.Compilation.

This works when compiling our project from the scratch, but when editing the code roslyn analyzers are also executed periodically. Sometimes we are getting a System.ArgumentException mentioning the SyntaxTree is not part of the compilation. Is there a save way to analyze all base classes of a given ClassDeclaration with the need to have the SemanticModel belonging to each base class as well as the SyntaxNode which is currently analysed. Please find the code below which shows how we are analyzing the base class currently.

Does anybody has an idea how to avoid the error mentioned above or what I am doing wrong?

public override void Initialize(AnalysisContext context)
{
    context.RegisterCompilationStartAction(compilationContext =>
    {
        //... here we are collecting some base stuff from the compilationContext.Compilation
        compilationContext.RegisterSyntaxNodeAction(syntaxNodeAnalysisContext => 
        {
           var classDeclaration = (ClassDeclarationSyntax)syntaxNodeAnalysisContext.Node;
           var meAndBaseClasses = GetClassDeclarationsDeep(classDeclaration, compilationContext.Compilation);
           // now we can analyze the current node because we have infos about all bases classes deep
        }, SyntaxKind.ClassDeclaration);
    });
}

protected IEnumerable<ClassDeclarationSyntax> GetClassDeclarationsDeep(ClassDeclarationSyntax classDeclaration, Compilation compilation)
{
    foreach (var type in classDeclaration.GetMeAndBaseTypes(compilation.GetSemanticModel(classDeclaration.SyntaxTree)))
    {
        foreach (var partialType in GetClassDeclarations(type, compilation))
        {
            yield return partialType;
        }
    }
}

public static IEnumerable<INamedTypeSymbol> GetMeAndBaseTypes(this ClassDeclarationSyntax classDeclaration, SemanticModel semanticModel)
{
    return GetMeAndBaseTypes(semanticModel.GetDeclaredSymbol(classDeclaration));
}

protected IEnumerable<ClassDeclarationSyntax> GetClassDeclarations(INamedTypeSymbol classType, Compilation compilation)
{
    return classType.DeclaringSyntaxReferences.SelectMany(t => t.SyntaxTree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>()).Where(t => SymbolEqualityComparer.Equals(classType, compilation.GetSemanticModel(t.SyntaxTree).GetDeclaredSymbol(t)));
}

public static IEnumerable<INamedTypeSymbol> GetMeAndBaseTypes(this INamedTypeSymbol type)
{
    List<INamedTypeSymbol> types = new List<INamedTypeSymbol>();
    while (type != null)
    {
        types.Add(type);
        type = type.BaseType;
    }

    return types;
}
Lori
  • 155
  • 8

0 Answers0