internal static async Task <ImmutableArray <ISymbol> > FindSymbolsAsync( Project project, SymbolFinderOptions options = null, IFindSymbolsProgress progress = null, CancellationToken cancellationToken = default) { Compilation compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); INamedTypeSymbol generatedCodeAttribute = compilation.GetTypeByMetadataName("System.CodeDom.Compiler.GeneratedCodeAttribute"); ImmutableArray <ISymbol> .Builder symbols = null; var namespaceOrTypeSymbols = new Stack <INamespaceOrTypeSymbol>(); namespaceOrTypeSymbols.Push(compilation.Assembly.GlobalNamespace); while (namespaceOrTypeSymbols.Count > 0) { INamespaceOrTypeSymbol namespaceOrTypeSymbol = namespaceOrTypeSymbols.Pop(); foreach (ISymbol symbol in namespaceOrTypeSymbol.GetMembers()) { SymbolKind kind = symbol.Kind; if (kind == SymbolKind.Namespace) { var namespaceSymbol = (INamespaceSymbol)symbol; SymbolFilterReason reason = options.GetReason(namespaceSymbol); if (reason == SymbolFilterReason.None) { namespaceOrTypeSymbols.Push(namespaceSymbol); } continue; } bool isUnused = false; if (!options.UnusedOnly || UnusedSymbolUtility.CanBeUnusedSymbol(symbol)) { SymbolFilterReason reason = options.GetReason(symbol); switch (reason) { case SymbolFilterReason.None: { if (options.IgnoreGeneratedCode && GeneratedCodeUtility.IsGeneratedCode(symbol, generatedCodeAttribute, MefWorkspaceServices.Default.GetService <ISyntaxFactsService>(compilation.Language).IsComment, cancellationToken)) { continue; } if (options.UnusedOnly && !symbol.IsImplicitlyDeclared) { isUnused = await UnusedSymbolUtility.IsUnusedSymbolAsync(symbol, project.Solution, cancellationToken).ConfigureAwait(false); } if (!options.UnusedOnly || isUnused) { progress?.OnSymbolFound(symbol); (symbols ?? (symbols = ImmutableArray.CreateBuilder <ISymbol>())).Add(symbol); } break; } case SymbolFilterReason.Visibility: case SymbolFilterReason.WithoutAttibute: case SymbolFilterReason.ImplicitlyDeclared: { continue; } case SymbolFilterReason.SymbolGroup: case SymbolFilterReason.Ignored: case SymbolFilterReason.WithAttibute: case SymbolFilterReason.Other: { break; } default: { Debug.Fail(reason.ToString()); break; } } } if (!isUnused && kind == SymbolKind.NamedType) { namespaceOrTypeSymbols.Push((INamedTypeSymbol)symbol); } } } return(symbols?.ToImmutableArray() ?? ImmutableArray <ISymbol> .Empty); }