Exemple #1
0
        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);
        }
Exemple #2
0
        private static ImmutableArray <SymbolAndProjectId <INamedTypeSymbol> > ToImmutableAndFree(
            SymbolAndProjectIdSet set)
        {
            var array = set.ToImmutableArray();

            s_setPool.ClearAndFree(set);
            return(array);
        }
Exemple #3
0
 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);
 }
Exemple #4
0
        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);
        }
Exemple #5
0
        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);
                }
            }
        }
Exemple #6
0
        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);
        }
Exemple #7
0
        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);
        }
Exemple #8
0
        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));
                        }
                    }
                }
            }
        }
Exemple #9
0
        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)));
            }
        }
Exemple #10
0
        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));
                        }
                    }
                }
            }
        }
Exemple #14
0
        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);
        }
Exemple #18
0
        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);
        }