2015-01-18 3 views
1

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

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

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

ответ

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

Это, конечно, лишенная версия, все проверки и дополнительные условия и преобразования были удалены для краткости. – mbinic

+0

Это будет очень медленно, чем больше проект, тем больше вы просматриваете каждый файл. У меня больше нет 7.1, но вы можете получить эту информацию из [Cache] ReSharper (https://confluence.jetbrains.com/display/NETCOM/4.01+Caches+%28R7%29) – citizenmatt

+0

Спасибо для вашего входа Мэтт! Кэш - это первое, на что я смотрел, но он не казался слишком полезным с его короткими именами: во время сеанса отладки я видел, что у него было 8000+ элементов для проекта, содержащего только 2 файла cs. Большинство имен были из ссылочных ассамблей, а не классов, поэтому я чувствовал, что получить их и пройти через них будет медленно. Во всяком случае, я попробую еще раз. – mbinic