获取当前项目中的所有IDeclaredType-s(用于ReSharper Generator插件)

时间:2015-01-18 02:30:22

标签: c# resharper-plugins resharper-sdk

我正在编写ReSharper 7.1 Generator插件,需要获取IDeclaredType-s方法在当前项目中声明的所有类型的列表(类,接口和结构 - GeneratorProviderBase<CSharpGeneratorContext>.Populate)。

通过定期反思,它就像Assembly.GetTypes()一样简单,但在这里它被证明是一个非常大的挑战。有没有办法做到这一点?

我搜索过高低,文档和示例没有帮助,然后浏览了每个*Extensions*Util类,但找不到任何有用的内容...

2 个答案:

答案 0 :(得分:0)

我设法做了我需要的事,但我不确定它是否是正确/最好的方法:

[GeneratorElementProvider("MyGeneratorProvider", typeof(CSharpLanguage))]
public class MyGeneratorProvider : GeneratorProviderBase<CSharpGeneratorContext>
{
    public override double Priority
    {
        get { return 0; }
    }

    public override void Populate(CSharpGeneratorContext context)
    {
        var projectCsFiles = GetAllCSharpFilesInProject(context.PsiModule);
        var declarations = projectCsFiles.SelectMany(GetDeclarationsFromCSharpFile).ToList();
        context.ProvidedElements.AddRange(declarations.Select(d => new GeneratorDeclarationElement(d)));
    }

    private static IEnumerable<ICSharpFile> GetAllCSharpFilesInProject(IPsiModule projectModule)
    {
        PsiManager psiManager = projectModule.GetPsiServices().PsiManager;
        return projectModule.SourceFiles.SelectMany(f => psiManager.GetPsiFiles<CSharpLanguage>(f).OfType<ICSharpFile>());
    }

    private static IEnumerable<ITypeDeclaration> GetDeclarationsFromCSharpFile(ICSharpFile file)
    {
        return file.NamespaceDeclarationNodes.SelectMany(GetDeclarationsFromCSharpNamespace);
    }

    private static IEnumerable<ITypeDeclaration> GetDeclarationsFromCSharpNamespace(ICSharpNamespaceDeclaration namespaceDeclaration)
    {
        foreach (var namespaceChild in namespaceDeclaration.Body.Children())
        {
            var classDeclaration = namespaceChild as IClassDeclaration;
            if (classDeclaration != null)
            {
                yield return classDeclaration;
            }
            else
            {
                var childNamespace = namespaceChild as ICSharpNamespaceDeclaration;
                if (childNamespace != null)
                {
                    foreach (var declaration in GetDeclarationsFromCSharpNamespace(childNamespace))
                    {
                        yield return declaration;
                    }
                }
            }
        }
    }
}

任何评论或更简单(甚至可能是内置)的方式吗?

答案 1 :(得分:0)

这是我使用缓存提出的。它似乎仍然不对,但我希望它比以前的方法更好。这仍然来自GeneratorProvider.Populate

public static IEnumerable<ICSharpTypeDeclaration> GetAllPublicTypeDeclarations(this IPsiModule module)
{
    var declarationCache = module.GetPsiServices().CacheManager.GetDeclarationsCache(module, false, true);
    var declarations = new List<ICSharpTypeDeclaration>();

    foreach (var shortName in declarationCache.GetAllShortNames())
    {
        var declaredElements = declarationCache.GetElementsByShortName(shortName).OfType<ITypeElement>().Where(e => 
        {
            var elementType = e.GetElementType();
            return elementType == CLRDeclaredElementType.CLASS || elementType == CLRDeclaredElementType.INTERFACE || elementType == CLRDeclaredElementType.ENUM;
        });

        foreach (ITypeElement declaredElement in declaredElements)
        {
            var declaration = declaredElement.GetDeclarations().OfType<ICSharpTypeDeclaration>().FirstOrDefault(d => d.GetAccessRights() == AccessRights.PUBLIC);
            if (declaration != null)
            {
                declarations.Add(declaration);
            }
        }
    }

    return declarations;
}

注意:结果与第一个答案中的结果不同,因为我改变了一些限制。此外,在这两种情况下,我都不关心部分课程。