使用 Roslyn 查找所有 class 声明而不是从另一个声明继承

Finding all class declarations than inherit from another with Roslyn

我有一个包含 SyntaxTree 数组的 CSharpCompilation 实例,我正在尝试查找继承自 class[=15 的所有 class 声明=]

例如

// Not in syntax tree but referenced in project
public class Base{}

// In syntax tree, how to find all such classes?
public class MyClass : Base {}

我尝试了一些方法,但对所有选项有点困惑,似乎找不到正确的方法。

我尝试获取符号,但这对继承类型不起作用

SyntaxTree[] trees = context.CSharpCompilation.SyntaxTrees;
IEnumerable<ISymbol> symbols = context.CSharpCompilation.GetSymbolsWithName(x => x == typeof(Base).Name, SymbolFilter.Type);

对 Roslyn 很陌生,对于如何实现这一点的任何建议或指示,我们将不胜感激。

首先,您需要获取 Base 的符号。如果这是您事先知道的特定类型,您可以为此使用 Compilation.GetTypeByMetadataName。 link 还将向您展示该方法的 100 多个使用示例。

从那里开始,这取决于您要做什么。如果您是从分析器内部执行此操作(我从代码中的 "context.CSharpCompilation" 怀疑),并且您正在尝试识别然后检查这些派生类型中的一些 属性,您可以使用RegisterSymbolAction for SymbolKind.NamedType, and then check each type's BaseType(可能是递归的,取决于您要完成的任务)以查看您是否找到上面的 GetTypeByMetadataName 发现的类型。

如果您在分析器的上下文之外进行解决方案范围的分析,那么有一个 helper for this in the Roslyn codebase, but it's internal. There's an existing request 来制作 ITypeSymbolExtensions public,所以我在该请求中提到了这个线程并建议将其扩展为包括 INamedTypeSymbolExtensions。

所以我想到了以下内容,它将递归检查所有 类 的继承类型

public class BaseClassRewriter : CSharpSyntaxRewriter
{
    private readonly SemanticModel _model;

    public BaseClassRewriter(SemanticModel model)
    {
        _model = model;
    }

    public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
    {
        var symbol = _model.GetDeclaredSymbol(node);
        if (InheritsFrom<BaseClass>(symbol))
        {
            // hit!
        }
    }

    private bool InheritsFrom<T>(INamedTypeSymbol symbol)
    {
        while (true)
        {
            if (symbol.ToString() == typeof(T).FullName)
            {
                return true;
            }
            if (symbol.BaseType != null)
            {
                symbol = symbol.BaseType;
                continue;
            }
            break;
        }
        return false;
    }
}
var classDecSynList = classDecSynList.Where(x=>
       (((IdentifierNameSyntax(x.BaseList.Types.FirstOrDefault()))
              .Identifier.ValueText=="Base"));

假设您拥有所有 class 声明语法列表;