private static async Task <SymbolAndProjectIdSet> FindImmediatelyInheritingTypesInDocumentAsync( Document document, SymbolAndProjectIdSet typesToSearchFor, InheritanceQuery inheritanceQuery, ConcurrentSet <SemanticModel> cachedModels, ConcurrentSet <SyntaxTreeIndex> cachedInfos, Func <SymbolAndProjectIdSet, INamedTypeSymbol, bool> typeImmediatelyMatches, CancellationToken cancellationToken) { var declarationInfo = await document.GetSyntaxTreeIndexAsync(cancellationToken).ConfigureAwait(false); cachedInfos.Add(declarationInfo); var result = CreateSymbolAndProjectIdSet(); foreach (var symbolInfo in declarationInfo.DeclaredSymbolInfos) { await ProcessSymbolInfo( document, symbolInfo, typesToSearchFor, inheritanceQuery, cachedModels, typeImmediatelyMatches, result, cancellationToken).ConfigureAwait(false); } return(result); }
private static ImmutableArray <SymbolAndProjectId <INamedTypeSymbol> > ToImmutableAndFree( SymbolAndProjectIdSet set) { var array = set.ToImmutableArray(); s_setPool.ClearAndFree(set); return(array); }
public InheritanceQuery(SymbolAndProjectIdSet sourceAndMetadataTypes, StringComparer comparer) { DerivesFromSystemObject = sourceAndMetadataTypes.Any(t => t.Symbol.SpecialType == SpecialType.System_Object); DerivesFromSystemValueType = sourceAndMetadataTypes.Any(t => t.Symbol.SpecialType == SpecialType.System_ValueType); DerivesFromSystemEnum = sourceAndMetadataTypes.Any(t => t.Symbol.SpecialType == SpecialType.System_Enum); DerivesFromSystemMulticastDelegate = sourceAndMetadataTypes.Any(t => t.Symbol.SpecialType == SpecialType.System_MulticastDelegate); TypeNames = new HashSet <string>(comparer); }
private static async Task <SymbolAndProjectIdSet> ProcessSymbolInfo( Document document, DeclaredSymbolInfo info, SymbolAndProjectIdSet typesToSearchFor, InheritanceQuery inheritanceQuery, ConcurrentSet <SemanticModel> cachedModels, Func <SymbolAndProjectIdSet, INamedTypeSymbol, bool> typeImmediatelyMatches, SymbolAndProjectIdSet result, CancellationToken cancellationToken) { var projectId = document.Project.Id; // If we're searching for enums/structs/delegates, then we can just look at the kind of // the info to see if we have a match. if ((inheritanceQuery.DerivesFromSystemEnum && info.Kind == DeclaredSymbolInfoKind.Enum) || (inheritanceQuery.DerivesFromSystemValueType && info.Kind == DeclaredSymbolInfoKind.Struct) || (inheritanceQuery.DerivesFromSystemMulticastDelegate && info.Kind == DeclaredSymbolInfoKind.Delegate)) { var symbol = await ResolveAsync(document, info, cachedModels, cancellationToken).ConfigureAwait(false) as INamedTypeSymbol; if (symbol != null) { result = result ?? CreateSymbolAndProjectIdSet(); result.Add(SymbolAndProjectId.Create(symbol, projectId)); } } else if (inheritanceQuery.DerivesFromSystemObject && info.Kind == DeclaredSymbolInfoKind.Class) { // Searching for types derived from 'Object' needs to be handled specially. // There may be no indication in source what the type actually derives from. // Also, we can't just look for an empty inheritance list. We may have // something like: "class C : IFoo". This type derives from object, despite // having a non-empty list. var symbol = await ResolveAsync(document, info, cachedModels, cancellationToken).ConfigureAwait(false) as INamedTypeSymbol; if (symbol?.BaseType?.SpecialType == SpecialType.System_Object) { result = result ?? CreateSymbolAndProjectIdSet(); result.Add(SymbolAndProjectId.Create(symbol, projectId)); } } else if (AnyInheritanceNamesMatch(info, inheritanceQuery.TypeNames)) { // Looks like we have a potential match. Actually check if the symbol is viable. var symbol = await ResolveAsync(document, info, cachedModels, cancellationToken).ConfigureAwait(false) as INamedTypeSymbol; if (symbol != null) { if (typeImmediatelyMatches(typesToSearchFor, symbol)) { result = result ?? CreateSymbolAndProjectIdSet(); result.Add(SymbolAndProjectId.Create(symbol, projectId)); } } } return(result); }
private static async Task FindTypesInProjectAsync( bool searchInMetadata, SymbolAndProjectIdSet result, SymbolAndProjectIdSet currentMetadataTypes, SymbolAndProjectIdSet currentSourceAndMetadataTypes, Project project, Func <SymbolAndProjectIdSet, INamedTypeSymbol, bool> metadataTypeMatches, Func <SymbolAndProjectIdSet, INamedTypeSymbol, bool> sourceTypeImmediatelyMatches, Func <INamedTypeSymbol, bool> shouldContinueSearching, bool transitive, CancellationToken cancellationToken) { // First see what derived metadata types we might find in this project. // This is only necessary if we started with a metadata type. if (searchInMetadata) { var foundMetadataTypes = await FindAllMatchingMetadataTypesInProjectAsync( currentMetadataTypes, project, metadataTypeMatches, cancellationToken).ConfigureAwait(false); foreach (var foundTypeAndProjectId in foundMetadataTypes) { var foundType = foundTypeAndProjectId.Symbol; Debug.Assert(foundType.Locations.Any(s_isInMetadata)); // Add to the result list. result.Add(foundTypeAndProjectId); if (transitive && shouldContinueSearching(foundType)) { currentMetadataTypes.Add(foundTypeAndProjectId); currentSourceAndMetadataTypes.Add(foundTypeAndProjectId); } } } // Now search the project and see what source types we can find. var foundSourceTypes = await FindSourceTypesInProjectAsync( currentSourceAndMetadataTypes, project, sourceTypeImmediatelyMatches, shouldContinueSearching, transitive, cancellationToken).ConfigureAwait(false); foreach (var foundTypeAndProjectId in foundSourceTypes) { var foundType = foundTypeAndProjectId.Symbol; Debug.Assert(foundType.Locations.All(s_isInSource)); // Add to the result list. result.Add(foundTypeAndProjectId); if (transitive && shouldContinueSearching(foundType)) { currentSourceAndMetadataTypes.Add(foundTypeAndProjectId); } } }
private static bool TypeImplementsFrom( SymbolAndProjectIdSet metadataTypes, INamedTypeSymbol type, bool transitive) { var interfaces = transitive ? type.AllInterfaces : type.Interfaces; foreach (var interfaceType in interfaces) { if (metadataTypes.Contains(SymbolAndProjectId.Create(interfaceType.OriginalDefinition, projectId: null))) { return(true); } } return(false); }
private static bool ImmediatelyDerivesOrImplementsFrom( SymbolAndProjectIdSet typesToSearchFor, INamedTypeSymbol type) { if (typesToSearchFor.Contains(SymbolAndProjectId.Create(type.BaseType?.OriginalDefinition, projectId: null))) { return(true); } foreach (var interfaceType in type.Interfaces) { if (typesToSearchFor.Contains(SymbolAndProjectId.Create(interfaceType.OriginalDefinition, projectId: null))) { return(true); } } return(false); }
private static async Task FindImmediateMatchingMetadataTypesInMetadataReferenceAsync( SymbolAndProjectIdSet metadataTypes, Project project, Func <SymbolAndProjectIdSet, INamedTypeSymbol, bool> metadataTypeMatches, Compilation compilation, PortableExecutableReference reference, SymbolAndProjectIdSet result, CancellationToken cancellationToken) { // We store an index in SymbolTreeInfo of the *simple* metadata type name // to the names of the all the types that either immediately derive or // implement that type. Because the mapping is from the simple name // we might get false positives. But that's fine as we still use // 'metadataTypeMatches' to make sure the match is correct. var symbolTreeInfo = await SymbolTreeInfo.TryGetInfoForMetadataReferenceAsync( project.Solution, reference, loadOnly : false, cancellationToken : cancellationToken).ConfigureAwait(false); if (symbolTreeInfo == null) { return; } // For each type we care about, see if we can find any derived types // in this index. foreach (var metadataType in metadataTypes) { var baseTypeName = metadataType.Symbol.Name; // For each derived type we find, see if we can map that back // to an actual symbol. Then check if that symbol actually fits // our criteria. foreach (var derivedType in symbolTreeInfo.GetDerivedMetadataTypes(baseTypeName, compilation, cancellationToken)) { if (derivedType != null && derivedType.Locations.Any(s_isInMetadata)) { if (metadataTypeMatches(metadataTypes, derivedType)) { result.Add(SymbolAndProjectId.Create(derivedType, project.Id)); } } } } }
private static bool TypeDerivesFrom( SymbolAndProjectIdSet metadataTypes, INamedTypeSymbol type, bool transitive) { if (transitive) { for (var current = type.BaseType; current != null; current = current.BaseType) { if (metadataTypes.Contains( SymbolAndProjectId.Create(current.OriginalDefinition, projectId: null))) { return(true); } } return(false); } else { return(metadataTypes.Contains( SymbolAndProjectId.Create(type.BaseType?.OriginalDefinition, projectId: null))); } }
private static async Task <IEnumerable <SymbolAndProjectId <INamedTypeSymbol> > > FindAllMatchingMetadataTypesInProjectAsync( SymbolAndProjectIdSet metadataTypes, Project project, Func <SymbolAndProjectIdSet, INamedTypeSymbol, bool> metadataTypeMatches, CancellationToken cancellationToken) { if (metadataTypes.Count == 0) { return(SpecializedCollections.EmptyEnumerable <SymbolAndProjectId <INamedTypeSymbol> >()); } var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var result = CreateSymbolAndProjectIdSet(); // Seed the current set of types we're searching for with the types we were given. var currentTypes = metadataTypes; while (currentTypes.Count > 0) { var immediateDerivedTypes = CreateSymbolAndProjectIdSet(); foreach (var reference in compilation.References.OfType <PortableExecutableReference>()) { await FindImmediateMatchingMetadataTypesInMetadataReferenceAsync( currentTypes, project, metadataTypeMatches, compilation, reference, immediateDerivedTypes, cancellationToken).ConfigureAwait(false); } // Add what we found to the result set. result.AddRange(immediateDerivedTypes); // Now keep looping, using the set we found to spawn the next set of searches. currentTypes = immediateDerivedTypes; } return(result); }
private static ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>> ToImmutableAndFree( SymbolAndProjectIdSet set) { var array = set.ToImmutableArray(); s_setPool.ClearAndFree(set); return array; }
private static async Task<ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>> FindAllMatchingMetadataTypesInProjectAsync( SymbolAndProjectIdSet metadataTypes, Project project, Func<SymbolAndProjectIdSet, INamedTypeSymbol, bool> metadataTypeMatches, CancellationToken cancellationToken) { if (metadataTypes.Count == 0) { return ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>.Empty; } var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var result = CreateSymbolAndProjectIdSet(); // Seed the current set of types we're searching for with the types we were given. var currentTypes = metadataTypes; while (currentTypes.Count > 0) { var immediateDerivedTypes = CreateSymbolAndProjectIdSet(); foreach (var reference in compilation.References.OfType<PortableExecutableReference>()) { await FindImmediateMatchingMetadataTypesInMetadataReferenceAsync( currentTypes, project, metadataTypeMatches, compilation, reference, immediateDerivedTypes, cancellationToken).ConfigureAwait(false); } // Add what we found to the result set. result.AddRange(immediateDerivedTypes); // Now keep looping, using the set we found to spawn the next set of searches. currentTypes = immediateDerivedTypes; } return ToImmutableAndFree(result); }
private static async Task FindImmediateMatchingMetadataTypesInMetadataReferenceAsync( SymbolAndProjectIdSet metadataTypes, Project project, Func<SymbolAndProjectIdSet, INamedTypeSymbol, bool> metadataTypeMatches, Compilation compilation, PortableExecutableReference reference, SymbolAndProjectIdSet result, CancellationToken cancellationToken) { // We store an index in SymbolTreeInfo of the *simple* metadata type name // to the names of the all the types that either immediately derive or // implement that type. Because the mapping is from the simple name // we might get false positives. But that's fine as we still use // 'metadataTypeMatches' to make sure the match is correct. var symbolTreeInfo = await SymbolTreeInfo.GetInfoForMetadataReferenceAsync( project.Solution, reference, loadOnly: false, cancellationToken: cancellationToken).ConfigureAwait(false); // For each type we care about, see if we can find any derived types // in this index. foreach (var metadataType in metadataTypes) { var baseTypeName = metadataType.Symbol.Name; // For each derived type we find, see if we can map that back // to an actual symbol. Then check if that symbol actually fits // our criteria. foreach (var derivedType in symbolTreeInfo.GetDerivedMetadataTypes(baseTypeName, compilation, cancellationToken)) { if (derivedType != null && derivedType.Locations.Any(s_isInMetadata)) { if (metadataTypeMatches(metadataTypes, derivedType)) { result.Add(SymbolAndProjectId.Create(derivedType, project.Id)); } } } } }
private static async Task AddSourceTypesInProjectAsync( SymbolAndProjectIdSet sourceAndMetadataTypes, Project project, Func <SymbolAndProjectIdSet, INamedTypeSymbol, bool> sourceTypeImmediatelyMatches, Func <INamedTypeSymbol, bool> shouldContinueSearching, bool transitive, SymbolAndProjectIdSet finalResult, CancellationToken cancellationToken) { // We're going to be sweeping over this project over and over until we reach a // fixed point. In order to limit GC and excess work, we cache all the sematic // models and DeclaredSymbolInfo for hte documents we look at. // Because we're only processing a project at a time, this is not an issue. var cachedModels = new ConcurrentSet <SemanticModel>(); var cachedInfos = new ConcurrentSet <SyntaxTreeIndex>(); var typesToSearchFor = CreateSymbolAndProjectIdSet(); typesToSearchFor.AddAll(sourceAndMetadataTypes); var comparer = project.LanguageServices.GetService <ISyntaxFactsService>().StringComparer; var inheritanceQuery = new InheritanceQuery(sourceAndMetadataTypes, comparer); var schedulerPair = new ConcurrentExclusiveSchedulerPair( TaskScheduler.Default, maxConcurrencyLevel: Math.Max(1, Environment.ProcessorCount)); // As long as there are new types to search for, keep looping. while (typesToSearchFor.Count > 0) { // Compute the set of names to look for in the base/interface lists. inheritanceQuery.TypeNames.AddRange(typesToSearchFor.Select(c => c.Symbol.Name)); // Search all the documents of this project in parallel. var tasks = project.Documents.Select( d => Task.Factory.StartNew( () => FindImmediatelyInheritingTypesInDocumentAsync( d, typesToSearchFor, inheritanceQuery, cachedModels, cachedInfos, sourceTypeImmediatelyMatches, cancellationToken), cancellationToken, TaskCreationOptions.None, schedulerPair.ConcurrentScheduler).Unwrap()).ToArray(); await Task.WhenAll(tasks).ConfigureAwait(false); // Clear out the information about the types we're looking for. We'll // fill these in if we discover any more types that we need to keep searching // for. typesToSearchFor.Clear(); inheritanceQuery.TypeNames.Clear(); foreach (var task in tasks) { var result = await task.ConfigureAwait(false); foreach (var derivedType in result) { if (finalResult.Add(derivedType)) { if (transitive && shouldContinueSearching(derivedType.Symbol)) { typesToSearchFor.Add(derivedType); } } } s_setPool.ClearAndFree(result); } } }
private static bool TypeDerivesFrom( SymbolAndProjectIdSet metadataTypes, INamedTypeSymbol type, bool transitive) { if (transitive) { for (var current = type.BaseType; current != null; current = current.BaseType) { if (metadataTypes.Contains( SymbolAndProjectId.Create(current.OriginalDefinition, projectId: null))) { return true; } } return false; } else { return metadataTypes.Contains( SymbolAndProjectId.Create(type.BaseType?.OriginalDefinition, projectId: null)); } }
private static bool TypeImplementsFrom( SymbolAndProjectIdSet metadataTypes, INamedTypeSymbol type, bool transitive) { var interfaces = transitive ? type.AllInterfaces : type.Interfaces; foreach (var interfaceType in interfaces) { if (metadataTypes.Contains(SymbolAndProjectId.Create(interfaceType.OriginalDefinition, projectId: null))) { return true; } } return false; }
private static async Task<ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>> FindSourceTypesInProjectAsync( SymbolAndProjectIdSet sourceAndMetadataTypes, Project project, Func<SymbolAndProjectIdSet, INamedTypeSymbol, bool> sourceTypeImmediatelyMatches, Func<INamedTypeSymbol, bool> shouldContinueSearching, bool transitive, CancellationToken cancellationToken) { // We're going to be sweeping over this project over and over until we reach a // fixed point. In order to limit GC and excess work, we cache all the sematic // models and DeclaredSymbolInfo for hte documents we look at. // Because we're only processing a project at a time, this is not an issue. var cachedModels = new ConcurrentSet<SemanticModel>(); var cachedInfos = new ConcurrentSet<IDeclarationInfo>(); var finalResult = CreateSymbolAndProjectIdSet(); var typesToSearchFor = CreateSymbolAndProjectIdSet(); typesToSearchFor.AddAll(sourceAndMetadataTypes); var inheritanceQuery = new InheritanceQuery(sourceAndMetadataTypes); // As long as there are new types to search for, keep looping. while (typesToSearchFor.Count > 0) { // Compute the set of names to look for in the base/interface lists. inheritanceQuery.TypeNames.AddRange(typesToSearchFor.Select(c => c.Symbol.Name)); // Search all the documents of this project in parallel. var tasks = project.Documents.Select(d => FindImmediatelyInheritingTypesInDocumentAsync( d, typesToSearchFor, inheritanceQuery, cachedModels, cachedInfos, sourceTypeImmediatelyMatches, cancellationToken)).ToArray(); await Task.WhenAll(tasks).ConfigureAwait(false); // Clear out the information about the types we're looking for. We'll // fill these in if we discover any more types that we need to keep searching // for. typesToSearchFor.Clear(); inheritanceQuery.TypeNames.Clear(); foreach (var task in tasks) { var result = await task.ConfigureAwait(false); if (result != null) { foreach (var derivedType in result) { if (finalResult.Add(derivedType)) { if (transitive && shouldContinueSearching(derivedType.Symbol)) { typesToSearchFor.Add(derivedType); } } } } } } return ToImmutableAndFree(finalResult); }
private static async Task <IEnumerable <SymbolAndProjectId <INamedTypeSymbol> > > FindSourceTypesInProjectAsync( SymbolAndProjectIdSet sourceAndMetadataTypes, Project project, Func <SymbolAndProjectIdSet, INamedTypeSymbol, bool> sourceTypeImmediatelyMatches, Func <INamedTypeSymbol, bool> shouldContinueSearching, bool transitive, CancellationToken cancellationToken) { // We're going to be sweeping over this project over and over until we reach a // fixed point. In order to limit GC and excess work, we cache all the sematic // models and DeclaredSymbolInfo for hte documents we look at. // Because we're only processing a project at a time, this is not an issue. var cachedModels = new ConcurrentSet <SemanticModel>(); var cachedInfos = new ConcurrentSet <IDeclarationInfo>(); var finalResult = CreateSymbolAndProjectIdSet(); var typesToSearchFor = CreateSymbolAndProjectIdSet(); typesToSearchFor.AddAll(sourceAndMetadataTypes); var inheritanceQuery = new InheritanceQuery(sourceAndMetadataTypes); // As long as there are new types to search for, keep looping. while (typesToSearchFor.Count > 0) { // Compute the set of names to look for in the base/interface lists. inheritanceQuery.TypeNames.AddRange(typesToSearchFor.Select(c => c.Symbol.Name)); // Search all the documents of this project in parallel. var tasks = project.Documents.Select(d => FindImmediatelyInheritingTypesInDocumentAsync( d, typesToSearchFor, inheritanceQuery, cachedModels, cachedInfos, sourceTypeImmediatelyMatches, cancellationToken)).ToArray(); await Task.WhenAll(tasks).ConfigureAwait(false); // Clear out the information about the types we're looking for. We'll // fill these in if we discover any more types that we need to keep searching // for. typesToSearchFor.Clear(); inheritanceQuery.TypeNames.Clear(); foreach (var task in tasks) { if (task.Result != null) { foreach (var derivedType in task.Result) { if (finalResult.Add(derivedType)) { if (transitive && shouldContinueSearching(derivedType.Symbol)) { typesToSearchFor.Add(derivedType); } } } } } } return(finalResult); }
private static bool ImmediatelyDerivesOrImplementsFrom( SymbolAndProjectIdSet typesToSearchFor, INamedTypeSymbol type) { if (typesToSearchFor.Contains(SymbolAndProjectId.Create(type.BaseType?.OriginalDefinition, projectId: null))) { return true; } foreach (var interfaceType in type.Interfaces) { if (typesToSearchFor.Contains(SymbolAndProjectId.Create(interfaceType.OriginalDefinition, projectId: null))) { return true; } } return false; }
private static async Task FindTypesInProjectAsync( bool searchInMetadata, SymbolAndProjectIdSet result, SymbolAndProjectIdSet currentMetadataTypes, SymbolAndProjectIdSet currentSourceAndMetadataTypes, Project project, Func<SymbolAndProjectIdSet, INamedTypeSymbol, bool> metadataTypeMatches, Func<SymbolAndProjectIdSet, INamedTypeSymbol, bool> sourceTypeImmediatelyMatches, Func<INamedTypeSymbol, bool> shouldContinueSearching, bool transitive, CancellationToken cancellationToken) { // First see what derived metadata types we might find in this project. // This is only necessary if we started with a metadata type. if (searchInMetadata) { var foundMetadataTypes = await FindAllMatchingMetadataTypesInProjectAsync( currentMetadataTypes, project, metadataTypeMatches, cancellationToken).ConfigureAwait(false); foreach (var foundTypeAndProjectId in foundMetadataTypes) { var foundType = foundTypeAndProjectId.Symbol; Debug.Assert(foundType.Locations.Any(s_isInMetadata)); // Add to the result list. result.Add(foundTypeAndProjectId); if (transitive && shouldContinueSearching(foundType)) { currentMetadataTypes.Add(foundTypeAndProjectId); currentSourceAndMetadataTypes.Add(foundTypeAndProjectId); } } } // Now search the project and see what source types we can find. var foundSourceTypes = await FindSourceTypesInProjectAsync( currentSourceAndMetadataTypes, project, sourceTypeImmediatelyMatches, shouldContinueSearching, transitive, cancellationToken).ConfigureAwait(false); foreach (var foundTypeAndProjectId in foundSourceTypes) { var foundType = foundTypeAndProjectId.Symbol; Debug.Assert(foundType.Locations.All(s_isInSource)); // Add to the result list. result.Add(foundTypeAndProjectId); if (transitive && shouldContinueSearching(foundType)) { currentSourceAndMetadataTypes.Add(foundTypeAndProjectId); } } }
public InheritanceQuery(SymbolAndProjectIdSet sourceAndMetadataTypes) { DerivesFromSystemObject = sourceAndMetadataTypes.Any(t => t.Symbol.SpecialType == SpecialType.System_Object); DerivesFromSystemValueType = sourceAndMetadataTypes.Any(t => t.Symbol.SpecialType == SpecialType.System_ValueType); DerivesFromSystemEnum = sourceAndMetadataTypes.Any(t => t.Symbol.SpecialType == SpecialType.System_Enum); DerivesFromSystemMulticastDelegate = sourceAndMetadataTypes.Any(t => t.Symbol.SpecialType == SpecialType.System_MulticastDelegate); TypeNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); }
private static async Task ProcessSymbolInfo( Document document, DeclaredSymbolInfo info, SymbolAndProjectIdSet typesToSearchFor, InheritanceQuery inheritanceQuery, ConcurrentSet<SemanticModel> cachedModels, Func<SymbolAndProjectIdSet, INamedTypeSymbol, bool> typeImmediatelyMatches, SymbolAndProjectIdSet result, CancellationToken cancellationToken) { var projectId = document.Project.Id; // If we're searching for enums/structs/delegates, then we can just look at the kind of // the info to see if we have a match. if ((inheritanceQuery.DerivesFromSystemEnum && info.Kind == DeclaredSymbolInfoKind.Enum) || (inheritanceQuery.DerivesFromSystemValueType && info.Kind == DeclaredSymbolInfoKind.Struct) || (inheritanceQuery.DerivesFromSystemMulticastDelegate && info.Kind == DeclaredSymbolInfoKind.Delegate)) { var symbol = await ResolveAsync(document, info, cachedModels, cancellationToken).ConfigureAwait(false) as INamedTypeSymbol; if (symbol != null) { result.Add(SymbolAndProjectId.Create(symbol, projectId)); } } else if (inheritanceQuery.DerivesFromSystemObject && info.Kind == DeclaredSymbolInfoKind.Class) { // Searching for types derived from 'Object' needs to be handled specially. // There may be no indication in source what the type actually derives from. // Also, we can't just look for an empty inheritance list. We may have // something like: "class C : IFoo". This type derives from object, despite // having a non-empty list. var symbol = await ResolveAsync(document, info, cachedModels, cancellationToken).ConfigureAwait(false) as INamedTypeSymbol; if (symbol?.BaseType?.SpecialType == SpecialType.System_Object) { result.Add(SymbolAndProjectId.Create(symbol, projectId)); } } else if (AnyInheritanceNamesMatch(info, inheritanceQuery.TypeNames)) { // Looks like we have a potential match. Actually check if the symbol is viable. var symbol = await ResolveAsync(document, info, cachedModels, cancellationToken).ConfigureAwait(false) as INamedTypeSymbol; if (symbol != null) { if (typeImmediatelyMatches(typesToSearchFor, symbol)) { result.Add(SymbolAndProjectId.Create(symbol, projectId)); } } } }
private static async Task<ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>> FindImmediatelyInheritingTypesInDocumentAsync( Document document, SymbolAndProjectIdSet typesToSearchFor, InheritanceQuery inheritanceQuery, ConcurrentSet<SemanticModel> cachedModels, ConcurrentSet<IDeclarationInfo> cachedInfos, Func<SymbolAndProjectIdSet, INamedTypeSymbol, bool> typeImmediatelyMatches, CancellationToken cancellationToken) { var declarationInfo = await document.GetDeclarationInfoAsync(cancellationToken).ConfigureAwait(false); cachedInfos.Add(declarationInfo); var result = CreateSymbolAndProjectIdSet(); foreach (var symbolInfo in declarationInfo.DeclaredSymbolInfos) { await ProcessSymbolInfo( document, symbolInfo, typesToSearchFor, inheritanceQuery, cachedModels, typeImmediatelyMatches, result, cancellationToken).ConfigureAwait(false); } return ToImmutableAndFree(result); }