查找从给定的INamedTypeSymbol

时间:2015-08-28 01:50:46

标签: c# roslyn

给定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方法看起来接近我需要的方法。 (我不是100%确定它在引用的程序集中找到派生类)。不过它是内部的,所以我打开了an issue

2 个答案:

答案 0 :(得分:3)

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

祝你好运!

<强>更新

此方法现已公开。 (source)

答案 1 :(得分:0)

您可以使用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;
    }

这将为您提供所有基类的列表以及每个基类实现的每个接口。然后,您可以过滤到您感兴趣的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;
            }
        } 
    }