查找从给定 INamedTypeSymbol 继承的类型

Find types that inherit from given INamedTypeSymbol

给定一个 INamedTypeSymbol(来自引用的程序集,而不是源代码)我如何找到继承自的所有类型(在 源代码和引用的程序集 中)这种类型?

在我的特定情况下,我正在寻找从 NUnit.Framework.TestAttribute 继承的所有类型。我可以按如下方式访问命名类型符号:

var ws = MSBuildWorkspace.Create();
var soln = ws.OpenSolutionAsync(@"C:\Users\...\SampleInheritanceStuff.sln").Result;
var proj = soln.Projects.Single();
var compilation = proj.GetCompilationAsync().Result;

string TEST_ATTRIBUTE_METADATA_NAME = "NUnit.Framework.TestAttribute";
var testAttributeType = compilation.GetTypeByMetadataName(TEST_ATTRIBUTE_METADATA_NAME);

//Now how do I find types that inherit from this type?

我看过 SymbolFinderCompilationINamedTypeSymbol,但我没有任何运气。

编辑: FindDerivedClassesAsync method looks close to what I need. (I'm not 100% sure that it finds derived classes in referenced assemblies). However it's internal, so I've opened an issue.

FindDerivedClassesAsync正是您要找的。
它在引用的程序集中找到派生的 类,如您在 DependentTypeFinder 的源代码中所见(注意 locationsInMetadata 变量)。

至于使用它,你总是可以同时进行反射:

 private static readonly Lazy<Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>> FindDerivedClassesAsync
            = new Lazy<Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>>(() => (Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>)Delegate.CreateDelegate(typeof(Func<INamedTypeSymbol, Solution, IImmutableSet<Project>, CancellationToken, Task<IEnumerable<INamedTypeSymbol>>>), DependentTypeFinder.Value.GetMethod("FindDerivedClassesAsync", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)));

(code borrowed from Tunnel Vision Laboratories Github)

祝你好运!

更新:

这个方法现在已经public了。 (source)

您可以使用从 Compilation

公开的 SemanticModel 获取此信息
public static IEnumerable<INamedTypeSymbol> GetBaseClasses(SemanticModel model, BaseTypeDeclarationSyntax type)
    {
        var classSymbol = model.GetDeclaredSymbol(type);
        var returnValue = new List<INamedTypeSymbol>();
        while (classSymbol.BaseType != null)
        {
            returnValue.Add(classSymbol.BaseType);
            if (classSymbol.Interfaces != null)
            returnValue.AddRange(classSymbol.Interfaces);
            classSymbol = classSymbol.BaseType;
        }
        return returnValue;
    }

这将为您提供所有基础 class 的列表以及每个基础 class 实现的每个接口。然后您可以过滤到您感兴趣的 INamedTypeSymbol:

        public static IEnumerable<BaseTypeDeclarationSyntax>
              FindClassesDerivedOrImplementedByType(Compilation compilation
        , INamedTypeSymbol target)
    {
        foreach (var tree in compilation.SyntaxTrees)
        {
            var semanticModel = compilation.GetSemanticModel(tree);

            foreach (var type in tree.GetRoot().DescendantNodes()
                        .OfType<TypeDeclarationSyntax>())
            {
                var baseClasses = GetBaseClasses(semanticModel, type);
                if (baseClasses != null)
                    if (baseClasses.Contains(target))
                        yield return type;
            }
        } 
    }