Reputation: 639
I'm trying to find all symbols of interfaces which are inheriting from a specific interface, in the solution as well as referenced assemblies. My goal is to do that as efficient and clean as possible.
At the time of doing that, I have the following things at hand:
Solution
.SymbolFinder
, but the following approaches did not work:SymbolFinder.FindImplementationsAsync(interfaceSymbol, solution)
=> This approach does not work, as it's only returning classes, but no interfaces.SymbolFinder.FindDerivedClassesAsync(interfaceSymbol, solution)
=> This is also just returning classes (as the method name already states)SymbolFinder.FindReferencesAsync(interfaceSymbol, solution)
=> This is just returning references in the current solution, but not in referenced assemblies.IAssemblySymbols
, iterating over all types and checking for the interface (done recursively, with a SymbolVisitor
).SymbolFinder
SymbolFinder
already provides)?Upvotes: 1
Views: 548
Reputation: 639
As there are no proposed improvements so far, here is my initial working approach - just for the sake of completeness:
private static ConcurrentBag<INamedTypeSymbol> GetImplementingSymbols(Project project)
{
var compilation = project.GetCompilationAsync().Result;
var typeToLookFor = compilation.GetTypeByMetadataName(typeof(IAnyInterface).FullName);
var assemblySymbols =
project.MetadataReferences
.Select(compilation.GetAssemblyOrModuleSymbol)
.OfType<IAssemblySymbol>()
.ToList();
assemblySymbols.Add(compilation.Assembly);
var foundSymbols = new ConcurrentBag<INamedTypeSymbol>();
Parallel.ForEach(assemblySymbols, symbol =>
{
var getAllSymbolsVisitor = new GetAllSymbolsVisitor(typeToLookFor, foundSymbols);
getAllSymbolsVisitor.Visit(symbol.GlobalNamespace);
});
return foundSymbols;
}
private class GetAllSymbolsVisitor : SymbolVisitor
{
private readonly ConcurrentBag<INamedTypeSymbol> _symbols;
private INamedTypeSymbol _type;
public GetAllSymbolsVisitor(INamedTypeSymbol type, ConcurrentBag<INamedTypeSymbol> symbols)
{
_symbols = symbols;
_type = type;
}
public override void VisitNamespace(INamespaceSymbol symbol)
{
foreach (var namespaceOrTypeSymbol in symbol.GetMembers())
{
namespaceOrTypeSymbol.Accept(this);
}
}
public override void VisitNamedType(INamedTypeSymbol symbol)
{
if (symbol.Interfaces.Any(interfaceType => SymbolEqualityComparer.Default.Equals(_type, interfaceType)))
{
_symbols.Add(symbol);
}
}
}
Upvotes: 1