Получить все IDeclaredType-s в текущем проекте (для плагина ReSharper Generator)

1

Я пишу плагин ReSharper 7.1 Generator и должен получить список всех типов, объявленных в текущем проекте (классы, интерфейсы и структуры - IDeclaredType-s) для метода GeneratorProviderBase<CSharpGeneratorContext>.Populate.

С регулярным отражением это было бы так же просто, как Assembly.GetTypes(), но здесь это оказалось довольно сложной задачей. Есть ли способ сделать это?

Я искал высоко и низко, документы и образцы не помогли, затем просмотрели все *Extensions и *Util class, но не смогли найти ничего полезного...

Теги:
resharper-sdk

2 ответа

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;
}

Примечание. Результаты не будут такими же, как в первом ответе, потому что я изменил некоторые ограничения. Кроме того, в обоих случаях меня не интересуют частичные классы.

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;
                    }
                }
            }
        }
    }
}

Любые комментарии или более простые (возможно, даже встроенные) способы сделать это?

  • 0
    Это, конечно, урезанная версия, все проверки и дополнительные условия и преобразования были удалены для краткости.
  • 0
    Это будет очень медленно, чем больше становится проект - вы просматриваете каждый файл. Я не имею 7.1 передать больше, но вы должны быть в состоянии получить эту информацию от ReSharper в тайниках
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню