private void CascadeBetweenAnonymousFunctionParameters(
            Document document,
            SemanticModel semanticModel,
            SyntaxNode container,
            SymbolAndProjectId <IParameterSymbol> parameterAndProjectId,
            ITypeSymbol convertedType1,
            ArrayBuilder <SymbolAndProjectId> results,
            CancellationToken cancellationToken)
        {
            var parameter   = parameterAndProjectId.Symbol;
            var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>();

            foreach (var token in container.DescendantTokens())
            {
                if (IdentifiersMatch(syntaxFacts, parameter.Name, token))
                {
                    var symbol = semanticModel.GetDeclaredSymbol(token.Parent, cancellationToken);
                    if (symbol is IParameterSymbol &&
                        symbol.ContainingSymbol.IsAnonymousFunction() &&
                        SignatureComparer.Instance.HaveSameSignatureAndConstraintsAndReturnTypeAndAccessors(parameter.ContainingSymbol, symbol.ContainingSymbol, syntaxFacts.IsCaseSensitive) &&
                        ParameterNamesMatch(syntaxFacts, (IMethodSymbol)parameter.ContainingSymbol, (IMethodSymbol)symbol.ContainingSymbol))
                    {
                        var lambdaNode     = symbol.ContainingSymbol.DeclaringSyntaxReferences.Select(r => r.GetSyntax(cancellationToken)).FirstOrDefault();
                        var convertedType2 = semanticModel.GetTypeInfo(lambdaNode, cancellationToken).ConvertedType;

                        if (convertedType1.Equals(convertedType2))
                        {
                            results.Add(parameterAndProjectId.WithSymbol(symbol));
                        }
                    }
                }
            }
        }
Beispiel #2
0
        protected override async Task <ImmutableArray <SymbolAndProjectId> > DetermineCascadedSymbolsAsync(
            SymbolAndProjectId <IMethodSymbol> symbolAndProjectId,
            Solution solution,
            IImmutableSet <Project> projects,
            FindReferencesSearchOptions options,
            CancellationToken cancellationToken)
        {
            // If it's a delegate method, then cascade to the type as well.  These guys are
            // practically equivalent for users.
            var symbol = symbolAndProjectId.Symbol;

            if (symbol.ContainingType.TypeKind == TypeKind.Delegate)
            {
                return(ImmutableArray.Create(
                           symbolAndProjectId.WithSymbol((ISymbol)symbol.ContainingType)));
            }
            else
            {
                var otherPartsOfPartial = GetOtherPartsOfPartial(symbolAndProjectId);
                var baseCascadedSymbols = await base.DetermineCascadedSymbolsAsync(
                    symbolAndProjectId, solution, projects, options, cancellationToken).ConfigureAwait(false);

                if (otherPartsOfPartial == null && baseCascadedSymbols == null)
                {
                    return(ImmutableArray <SymbolAndProjectId> .Empty);
                }

                return(otherPartsOfPartial.Concat(baseCascadedSymbols));
            }
        }
        protected override async Task <ImmutableArray <SymbolAndProjectId> > DetermineCascadedSymbolsAsync(
            SymbolAndProjectId <IMethodSymbol> symbolAndProjectId,
            Solution solution,
            IImmutableSet <Project> projects,
            FindReferencesSearchOptions options,
            CancellationToken cancellationToken)
        {
            var result = ImmutableArray.CreateBuilder <SymbolAndProjectId>();

            var symbol      = symbolAndProjectId.Symbol;
            var beginInvoke = symbol.ContainingType.GetMembers(WellKnownMemberNames.DelegateBeginInvokeName).FirstOrDefault();

            if (beginInvoke != null)
            {
                result.Add(symbolAndProjectId.WithSymbol(beginInvoke));
            }

            // All method group references
            foreach (var project in solution.Projects)
            {
                foreach (var document in project.Documents)
                {
                    var changeSignatureService = document.GetLanguageService <AbstractChangeSignatureService>();
                    result.AddRange(await changeSignatureService.DetermineCascadedSymbolsFromDelegateInvoke(
                                        symbolAndProjectId, document, cancellationToken).ConfigureAwait(false));
                }
            }

            return(result.ToImmutable());
        }
        protected override async Task <IEnumerable <SymbolAndProjectId> > DetermineCascadedSymbolsAsync(
            SymbolAndProjectId <IMethodSymbol> symbolAndProjectId,
            Solution solution,
            IImmutableSet <Project> projects,
            CancellationToken cancellationToken)
        {
            // If it's a delegate method, then cascade to the type as well.  These guys are
            // practically equivalent for users.
            var symbol = symbolAndProjectId.Symbol;

            if (symbol.ContainingType.TypeKind == TypeKind.Delegate)
            {
                return(SpecializedCollections.SingletonEnumerable(
                           symbolAndProjectId.WithSymbol((ISymbol)symbol.ContainingType)));
            }
            else
            {
                var otherPartsOfPartial = GetOtherPartsOfPartial(symbolAndProjectId);
                var baseCascadedSymbols = await base.DetermineCascadedSymbolsAsync(symbolAndProjectId, solution, projects, cancellationToken).ConfigureAwait(false);

                if (otherPartsOfPartial == null && baseCascadedSymbols == null)
                {
                    return(null);
                }

                otherPartsOfPartial = otherPartsOfPartial ?? SpecializedCollections.EmptyEnumerable <SymbolAndProjectId>();
                baseCascadedSymbols = baseCascadedSymbols ?? SpecializedCollections.EmptyEnumerable <SymbolAndProjectId>();

                return(otherPartsOfPartial.Concat(baseCascadedSymbols));
            }
        }
 private void Add <TSymbol>(
     ArrayBuilder <SymbolAndProjectId> result,
     SymbolAndProjectId symbolAndProjectId,
     ImmutableArray <TSymbol> enumerable) where TSymbol : ISymbol
 {
     result.AddRange(enumerable.Select(
                         s => symbolAndProjectId.WithSymbol((ISymbol)s)));
 }
        private ImmutableArray <SymbolAndProjectId> GetOtherPartsOfPartial(
            SymbolAndProjectId <IMethodSymbol> symbolAndProjectId)
        {
            var symbol = symbolAndProjectId.Symbol;

            if (symbol.PartialDefinitionPart != null)
            {
                return(ImmutableArray.Create(
                           symbolAndProjectId.WithSymbol((ISymbol)symbol.PartialDefinitionPart)));
            }

            if (symbol.PartialImplementationPart != null)
            {
                return(ImmutableArray.Create(
                           symbolAndProjectId.WithSymbol((ISymbol)symbol.PartialImplementationPart)));
            }

            return(ImmutableArray <SymbolAndProjectId> .Empty);
        }
        private IEnumerable <SymbolAndProjectId> GetOtherPartsOfPartial(
            SymbolAndProjectId <IMethodSymbol> symbolAndProjectId)
        {
            var symbol = symbolAndProjectId.Symbol;

            if (symbol.PartialDefinitionPart != null)
            {
                return(SpecializedCollections.SingletonEnumerable(
                           symbolAndProjectId.WithSymbol((ISymbol)symbol.PartialDefinitionPart)));
            }

            if (symbol.PartialImplementationPart != null)
            {
                return(SpecializedCollections.SingletonEnumerable(
                           symbolAndProjectId.WithSymbol((ISymbol)symbol.PartialImplementationPart)));
            }

            return(null);
        }
            internal static async Task <SymbolAndProjectId> GetPropertyFromAccessorOrAnOverride(
                SymbolAndProjectId symbolAndProjectId, Solution solution, CancellationToken cancellationToken)
            {
                var symbol = symbolAndProjectId.Symbol;

                if (symbol.IsPropertyAccessor())
                {
                    return(symbolAndProjectId.WithSymbol(
                               ((IMethodSymbol)symbol).AssociatedSymbol));
                }

                if (symbol.IsOverride && symbol.OverriddenMember() != null)
                {
                    var originalSourceSymbol = await SymbolFinder.FindSourceDefinitionAsync(
                        symbolAndProjectId.WithSymbol(symbol.OverriddenMember()),
                        solution, cancellationToken).ConfigureAwait(false);

                    if (originalSourceSymbol.Symbol != null)
                    {
                        return(await GetPropertyFromAccessorOrAnOverride(originalSourceSymbol, solution, cancellationToken).ConfigureAwait(false));
                    }
                }

                if (symbol.Kind == SymbolKind.Method &&
                    symbol.ContainingType.TypeKind == TypeKind.Interface)
                {
                    var methodImplementors = await SymbolFinder.FindImplementationsAsync(
                        symbolAndProjectId, solution, cancellationToken : cancellationToken).ConfigureAwait(false);

                    foreach (var methodImplementor in methodImplementors)
                    {
                        var propertyAccessorOrAnOverride = await GetPropertyFromAccessorOrAnOverride(methodImplementor, solution, cancellationToken).ConfigureAwait(false);

                        if (propertyAccessorOrAnOverride.Symbol != null)
                        {
                            return(propertyAccessorOrAnOverride);
                        }
                    }
                }

                return(default(SymbolAndProjectId));
            }
        private IEnumerable <SymbolAndProjectId> CascadeBetweenPartialMethodParameters(
            SymbolAndProjectId <IParameterSymbol> parameterAndProjectId)
        {
            var parameter = parameterAndProjectId.Symbol;

            if (parameter.ContainingSymbol is IMethodSymbol)
            {
                var ordinal = parameter.Ordinal;
                var method  = (IMethodSymbol)parameter.ContainingSymbol;
                if (method.PartialDefinitionPart != null && ordinal < method.PartialDefinitionPart.Parameters.Length)
                {
                    yield return(parameterAndProjectId.WithSymbol(method.PartialDefinitionPart.Parameters[ordinal]));
                }

                if (method.PartialImplementationPart != null && ordinal < method.PartialImplementationPart.Parameters.Length)
                {
                    yield return(parameterAndProjectId.WithSymbol(method.PartialImplementationPart.Parameters[ordinal]));
                }
            }
        }
        private async Task <ImmutableArray <SymbolAndProjectId> > CascadeBetweenAnonymousFunctionParametersAsync(
            Solution solution,
            SymbolAndProjectId <IParameterSymbol> parameterAndProjectId,
            CancellationToken cancellationToken)
        {
            var results = ArrayBuilder <SymbolAndProjectId> .GetInstance();

            var parameter = parameterAndProjectId.Symbol;

            if (parameter.ContainingSymbol.IsAnonymousFunction())
            {
                var parameterNode = parameter.DeclaringSyntaxReferences.Select(r => r.GetSyntax(cancellationToken)).FirstOrDefault();
                if (parameterNode != null)
                {
                    var document = solution.GetDocument(parameterNode.SyntaxTree);
                    if (document != null)
                    {
                        var semanticFacts = document.GetLanguageService <ISemanticFactsService>();
                        if (semanticFacts.ExposesAnonymousFunctionParameterNames)
                        {
                            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                            var lambdaNode    = parameter.ContainingSymbol.DeclaringSyntaxReferences.Select(r => r.GetSyntax(cancellationToken)).FirstOrDefault();
                            var convertedType = semanticModel.GetTypeInfo(lambdaNode, cancellationToken).ConvertedType;

                            if (convertedType != null)
                            {
                                var syntaxFactsService = document.GetLanguageService <ISyntaxFactsService>();
                                var container          = GetContainer(semanticModel, parameterNode, syntaxFactsService);
                                if (container != null)
                                {
                                    results.AddRange(CascadeBetweenAnonymousFunctionParameters(
                                                         document, semanticModel, container, parameterAndProjectId, convertedType, cancellationToken));
                                }
                            }
                        }
                    }
                }

                var containingMethod = (IMethodSymbol)parameter.ContainingSymbol;
                if (containingMethod.AssociatedAnonymousDelegate != null)
                {
                    var invokeMethod = containingMethod.AssociatedAnonymousDelegate.DelegateInvokeMethod;
                    int ordinal      = parameter.Ordinal;
                    if (invokeMethod != null && ordinal < invokeMethod.Parameters.Length)
                    {
                        results.Add(parameterAndProjectId.WithSymbol(
                                        invokeMethod.Parameters[ordinal]));
                    }
                }
            }

            return(results.ToImmutableAndFree());
        }
 protected override Task <ImmutableArray <SymbolAndProjectId> > DetermineCascadedSymbolsAsync(
     SymbolAndProjectId <IMethodSymbol> symbolAndProjectId,
     Solution solution,
     IImmutableSet <Project> projects,
     CancellationToken cancellationToken)
 {
     // An explicit interface method will cascade to all the methods that it implements.
     return(Task.FromResult(
                symbolAndProjectId.Symbol.ExplicitInterfaceImplementations.Select(
                    ei => symbolAndProjectId.WithSymbol((ISymbol)ei)).ToImmutableArray()));
 }
 private static void AddParameterAtIndex(
     SymbolAndProjectId <IParameterSymbol> parameterAndProjectId,
     ArrayBuilder <SymbolAndProjectId> results,
     int ordinal,
     ImmutableArray <IParameterSymbol>?parameters)
 {
     if (parameters != null && ordinal < parameters.Value.Length)
     {
         results.Add(parameterAndProjectId.WithSymbol(parameters.Value[ordinal]));
     }
 }
        private List <SymbolAndProjectId> Add(
            List <SymbolAndProjectId> result,
            SymbolAndProjectId symbolAndProjectId,
            IEnumerable <ISymbol> enumerable)
        {
            if (enumerable != null)
            {
                result = result ?? new List <SymbolAndProjectId>();
                result.AddRange(enumerable.Select(s => symbolAndProjectId.WithSymbol(s)));
            }

            return(result);
        }
        private void CascadeBetweenPartialMethodParameters(
            SymbolAndProjectId<IParameterSymbol> parameterAndProjectId,
            ArrayBuilder<SymbolAndProjectId> results)
        {
            var parameter = parameterAndProjectId.Symbol;
            if (parameter.ContainingSymbol is IMethodSymbol)
            {
                var ordinal = parameter.Ordinal;
                var method = (IMethodSymbol)parameter.ContainingSymbol;
                if (method.PartialDefinitionPart != null && ordinal < method.PartialDefinitionPart.Parameters.Length)
                {
                    results.Add(
                        parameterAndProjectId.WithSymbol(method.PartialDefinitionPart.Parameters[ordinal]));
                }

                if (method.PartialImplementationPart != null && ordinal < method.PartialImplementationPart.Parameters.Length)
                {
                    results.Add(
                        parameterAndProjectId.WithSymbol(method.PartialImplementationPart.Parameters[ordinal]));
                }
            }
        }
        protected override async Task <IEnumerable <SymbolAndProjectId> > DetermineCascadedSymbolsAsync(
            SymbolAndProjectId <IEventSymbol> symbolAndProjectId,
            Solution solution,
            IImmutableSet <Project> projects,
            CancellationToken cancellationToken)
        {
            var baseSymbols = await base.DetermineCascadedSymbolsAsync(symbolAndProjectId, solution, projects, cancellationToken).ConfigureAwait(false);

            baseSymbols = baseSymbols ?? SpecializedCollections.EmptyEnumerable <SymbolAndProjectId>();

            var symbol        = symbolAndProjectId.Symbol;
            var backingFields = symbol.ContainingType.GetMembers()
                                .OfType <IFieldSymbol>()
                                .Where(f => symbol.Equals(f.AssociatedSymbol))
                                .Select(s => (SymbolAndProjectId)symbolAndProjectId.WithSymbol(s));

            var associatedNamedTypes = symbol.ContainingType.GetTypeMembers()
                                       .Where(n => symbol.Equals(n.AssociatedSymbol))
                                       .Select(s => (SymbolAndProjectId)symbolAndProjectId.WithSymbol(s));

            return(baseSymbols.Concat(backingFields)
                   .Concat(associatedNamedTypes));
        }
        public override Task <ImmutableArray <SymbolAndProjectId> > DetermineCascadedSymbolsAsync(
            SymbolAndProjectId symbolAndProjectId, Solution solution, IImmutableSet <Project> projects, CancellationToken cancellationToken)
        {
            var symbol = symbolAndProjectId.Symbol;

            if (symbol is TSymbol && CanFind((TSymbol)symbol))
            {
                return(DetermineCascadedSymbolsAsync(
                           symbolAndProjectId.WithSymbol((TSymbol)symbol),
                           solution, projects, cancellationToken));
            }

            return(SpecializedTasks.EmptyImmutableArray <SymbolAndProjectId>());
        }
Beispiel #17
0
        public override Task <ImmutableArray <SymbolAndProjectId> > DetermineCascadedSymbolsAsync(
            SymbolAndProjectId symbolAndProjectId, Solution solution, IImmutableSet <Project> projects,
            FindReferencesSearchOptions options, CancellationToken cancellationToken)
        {
            if (options.Cascade &&
                symbolAndProjectId.Symbol is TSymbol typedSymbol &&
                CanFind(typedSymbol))
            {
                return(DetermineCascadedSymbolsAsync(
                           symbolAndProjectId.WithSymbol(typedSymbol),
                           solution, projects, options, cancellationToken));
            }

            return(SpecializedTasks.EmptyImmutableArray <SymbolAndProjectId>());
        }
Beispiel #18
0
        private static async Task <ImmutableArray <SymbolAndProjectId> > FindSourceAndMetadataImplementationsAsync(
            Solution solution, SymbolAndProjectId symbolAndProjectId, CancellationToken cancellationToken)
        {
            if (symbolAndProjectId.Symbol.IsInterfaceType() || symbolAndProjectId.Symbol.IsImplementableMember())
            {
                var implementations = await SymbolFinder.FindImplementationsAsync(
                    symbolAndProjectId, solution, cancellationToken : cancellationToken).ConfigureAwait(false);

                // It's important we use a HashSet here -- we may have cases in an inheritance hierarchy where more than one method
                // in an overrides chain implements the same interface method, and we want to duplicate those. The easiest way to do it
                // is to just use a HashSet.
                var implementationsAndOverrides = new HashSet <SymbolAndProjectId>();

                foreach (var implementation in implementations)
                {
                    implementationsAndOverrides.Add(implementation);

                    // FindImplementationsAsync will only return the base virtual/abstract method, not that method and the overrides
                    // of the method. We should also include those.
                    if (implementation.Symbol.IsOverridable())
                    {
                        var overrides = await SymbolFinder.FindOverridesAsync(
                            implementation, solution, cancellationToken : cancellationToken).ConfigureAwait(false);

                        implementationsAndOverrides.AddRange(overrides);
                    }
                }

                if (!symbolAndProjectId.Symbol.IsInterfaceType() &&
                    !symbolAndProjectId.Symbol.IsAbstract)
                {
                    implementationsAndOverrides.Add(symbolAndProjectId);
                }

                return(implementationsAndOverrides.ToImmutableArray());
            }
            else if (symbolAndProjectId.Symbol is INamedTypeSymbol {
                TypeKind : TypeKind.Class
            } namedType)
            {
                var derivedClasses = await SymbolFinder.FindDerivedClassesAsync(
                    symbolAndProjectId.WithSymbol(namedType),
                    solution, cancellationToken : cancellationToken).ConfigureAwait(false);

                return(derivedClasses.SelectAsArray(s => (SymbolAndProjectId)s).Concat(symbolAndProjectId));
            }
Beispiel #19
0
        protected override Task <ImmutableArray <SymbolAndProjectId> > DetermineCascadedSymbolsAsync(
            SymbolAndProjectId <IFieldSymbol> symbolAndProjectId,
            Solution solution,
            IImmutableSet <Project> projects,
            CancellationToken cancellationToken)
        {
            var symbol = symbolAndProjectId.Symbol;

            if (symbol.AssociatedSymbol != null)
            {
                return(Task.FromResult(
                           ImmutableArray.Create(symbolAndProjectId.WithSymbol(symbol.AssociatedSymbol))));
            }
            else
            {
                return(SpecializedTasks.EmptyImmutableArray <SymbolAndProjectId>());
            }
        }
Beispiel #20
0
        protected override async Task <ImmutableArray <SymbolAndProjectId> > DetermineCascadedSymbolsAsync(
            SymbolAndProjectId <IMethodSymbol> symbolAndProjectId,
            Solution solution,
            IImmutableSet <Project> projects,
            CancellationToken cancellationToken)
        {
            var result = await base.DetermineCascadedSymbolsAsync(
                symbolAndProjectId, solution, projects, cancellationToken).ConfigureAwait(false);

            var symbol = symbolAndProjectId.Symbol;

            if (symbol.AssociatedSymbol != null)
            {
                result = result.Add(symbolAndProjectId.WithSymbol(symbol.AssociatedSymbol));
            }

            return(result);
        }
Beispiel #21
0
        protected override async Task <ImmutableArray <SymbolAndProjectId> > DetermineCascadedSymbolsAsync(
            SymbolAndProjectId <TSymbol> symbolAndProjectId,
            Solution solution,
            IImmutableSet <Project> projects,
            FindReferencesSearchOptions options,
            CancellationToken cancellationToken)
        {
            // Static methods can't cascade.
            var symbol = symbolAndProjectId.Symbol;

            if (!symbol.IsStatic)
            {
                if (symbol.ContainingType.TypeKind == TypeKind.Interface)
                {
                    // We have an interface method.  Find all implementations of that method and
                    // cascade to them.
                    return(await SymbolFinder.FindImplementationsAsync(symbolAndProjectId, solution, projects, cancellationToken).ConfigureAwait(false));
                }
                else
                {
                    // We have a normal method.  Find any interface methods that it implicitly or
                    // explicitly implements and cascade down to those.
                    var interfaceMembersImplemented = await SymbolFinder.FindImplementedInterfaceMembersAsync(
                        symbolAndProjectId, solution, projects, cancellationToken).ConfigureAwait(false);

                    // Finally, methods can cascade through virtual/override inheritance.  NOTE(cyrusn):
                    // We only need to go up or down one level.  Then, when we're finding references on
                    // those members, we'll end up traversing the entire hierarchy.
                    var overrides = await SymbolFinder.FindOverridesAsync(
                        symbolAndProjectId, solution, projects, cancellationToken).ConfigureAwait(false);

                    var overriddenMember = symbolAndProjectId.WithSymbol(symbol.OverriddenMember());
                    if (overriddenMember.Symbol == null)
                    {
                        return(interfaceMembersImplemented.Concat(overrides));
                    }

                    return(interfaceMembersImplemented.Concat(overrides).Concat(overriddenMember));
                }
            }

            return(ImmutableArray <SymbolAndProjectId> .Empty);
        }
        internal static async Task<IEnumerable<SymbolAndProjectId>> FindOverridesAsync(
            SymbolAndProjectId symbolAndProjectId, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            // Method can only have overrides if its a virtual, abstract or override and is not
            // sealed.
            var symbol = symbolAndProjectId.Symbol;
            if (symbol.IsOverridable())
            {
                // To find the overrides, we need to walk down the type hierarchy and check all
                // derived types.  TODO(cyrusn): This seems extremely costly.  Is there any way to
                // speed this up?
                var containingType = symbol.ContainingType.OriginalDefinition;
                var derivedTypes = await FindDerivedClassesAsync(
                    symbolAndProjectId.WithSymbol(containingType),
                    solution, projects, cancellationToken).ConfigureAwait(false);

                List<SymbolAndProjectId> results = null;
                foreach (var type in derivedTypes)
                {
                    foreach (var m in GetMembers(type, symbol.Name))
                    {
                        var sourceMember = await FindSourceDefinitionAsync(m, solution, cancellationToken).ConfigureAwait(false);
                        var bestMember = sourceMember.Symbol != null ? sourceMember : m;
                        var member = bestMember.Symbol;
                        if (member != null &&
                            member.IsOverride &&
                            member.OverriddenMember() != null &&
                            OriginalSymbolsMatch(member.OverriddenMember().OriginalDefinition, symbol.OriginalDefinition, solution, cancellationToken))
                        {
                            results = results ?? new List<SymbolAndProjectId>();
                            results.Add(bestMember);
                        }
                    }
                }

                if (results != null)
                {
                    return results;
                }
            }

            return SpecializedCollections.EmptyEnumerable<SymbolAndProjectId>();
        }
Beispiel #23
0
        internal static IEnumerable <SymbolAndProjectId> GetOverloadedSymbols(
            SymbolAndProjectId symbolAndProjectId)
        {
            var symbol = symbolAndProjectId.Symbol;

            if (symbol is IMethodSymbol)
            {
                var containingType = symbol.ContainingType;
                if (containingType.Kind == SymbolKind.NamedType)
                {
                    foreach (var member in containingType.GetMembers())
                    {
                        if (string.Equals(member.MetadataName, symbol.MetadataName, StringComparison.Ordinal) && member is IMethodSymbol && !member.Equals(symbol))
                        {
                            yield return(symbolAndProjectId.WithSymbol(member));
                        }
                    }
                }
            }
        }
        public static IEnumerable <SymbolAndProjectId> GetContainedSymbols(SymbolAndProjectId symbolAndProjectId)
        {
            if (symbolAndProjectId.Symbol is INamedTypeSymbol namedType)
            {
                foreach (var member in namedType.GetMembers())
                {
                    if (member.IsImplicitlyDeclared)
                    {
                        continue;
                    }

                    if (member is IMethodSymbol method && method.AssociatedSymbol != null)
                    {
                        continue;
                    }

                    if (!string.IsNullOrEmpty(member.Name))
                    {
                        yield return(symbolAndProjectId.WithSymbol(member));
                    }
                }
            }
        }
Beispiel #25
0
        protected override async Task <ImmutableArray <SymbolAndProjectId> > DetermineCascadedSymbolsAsync(
            SymbolAndProjectId <IMethodSymbol> symbolAndProjectId,
            Solution solution,
            IImmutableSet <Project> projects,
            FindReferencesSearchOptions options,
            CancellationToken cancellationToken)
        {
            var result = await base.DetermineCascadedSymbolsAsync(
                symbolAndProjectId, solution, projects, options, cancellationToken).ConfigureAwait(false);

            // If we've been asked to search for specific accessors, then do not cascade.
            // We don't want to produce results for the associated property.
            if (!options.AssociatePropertyReferencesWithSpecificAccessor)
            {
                var symbol = symbolAndProjectId.Symbol;
                if (symbol.AssociatedSymbol != null)
                {
                    result = result.Add(symbolAndProjectId.WithSymbol(symbol.AssociatedSymbol));
                }
            }

            return(result);
        }
Beispiel #26
0
        private static async Task <ImmutableArray <SymbolAndProjectId> > GetCalledMethodSymbolsAsync(
            SymbolAndProjectId symbolAndProjectId, Solution solution, CancellationToken cancellationToken)
        {
            using var _ = ArrayBuilder <SymbolAndProjectId> .GetInstance(out var symbols);

            foreach (var reference in symbolAndProjectId.Symbol.DeclaringSyntaxReferences)
            {
                var semanticModel = await solution.GetDocument(reference.SyntaxTree).GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                foreach (var syntaxNode in (await reference.GetSyntaxAsync(cancellationToken).ConfigureAwait(false)).DescendantNodes())
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var newSymbol = semanticModel.GetSymbolInfo(syntaxNode, cancellationToken).Symbol;
                    if (newSymbol != null && newSymbol is IMethodSymbol &&
                        (newSymbol.CanBeReferencedByName || ((IMethodSymbol)newSymbol).MethodKind == MethodKind.Constructor))
                    {
                        symbols.Add(symbolAndProjectId.WithSymbol(newSymbol));
                    }
                }
            }

            return(symbols.ToImmutable());
        }
        private static async Task<ImmutableArray<SymbolAndProjectId<INamedTypeSymbol>>> FindTypesAsync(
            SymbolAndProjectId<INamedTypeSymbol> type,
            Solution solution,
            IImmutableSet<Project> projects,
            Func<SymbolAndProjectIdSet, INamedTypeSymbol, bool> metadataTypeMatches,
            Func<SymbolAndProjectIdSet, INamedTypeSymbol, bool> sourceTypeImmediatelyMatches,
            Func<INamedTypeSymbol, bool> shouldContinueSearching,
            bool transitive,
            CancellationToken cancellationToken)
        {
            type = type.WithSymbol(type.Symbol.OriginalDefinition);
            projects = projects ?? ImmutableHashSet.Create(solution.Projects.ToArray());
            var searchInMetadata = type.Symbol.Locations.Any(s_isInMetadata);

            // Note: it is not sufficient to just walk the list of projects passed in,
            // searching only those for derived types.
            //
            // Say we have projects: A <- B <- C, but only projects A and C are passed in.
            // We might miss a derived type in C if there's an intermediate derived type
            // in B.
            //
            // However, say we have projects A <- B <- C <- D, only only projects A and C
            // are passed in.  There is no need to check D as there's no way it could
            // contribute an intermediate type that affects A or C.  We only need to check
            // A, B and C

            // First find all the projects that could potentially reference this type.
            var projectsThatCouldReferenceType = await GetProjectsThatCouldReferenceTypeAsync(
                type.Symbol, solution, searchInMetadata, cancellationToken).ConfigureAwait(false);

            // Now, based on the list of projects that could actually reference the type,
            // and the list of projects the caller wants to search, find the actual list of
            // projects we need to search through.
            //
            // This list of projects is properly topologicaly ordered.  Because of this we
            // can just process them in order from first to last because we know no project
            // in this list could affect a prior project.
            var orderedProjectsToExamine = GetOrderedProjectsToExamine(
                solution, projects, projectsThatCouldReferenceType);

            var currentMetadataTypes = CreateSymbolAndProjectIdSet();
            var currentSourceAndMetadataTypes = CreateSymbolAndProjectIdSet();

            currentSourceAndMetadataTypes.Add(type);
            if (searchInMetadata)
            {
                currentMetadataTypes.Add(type);
            }

            var result = CreateSymbolAndProjectIdSet();

            // Now walk the projects from left to right seeing what our type cascades to. Once we 
            // reach a fixed point in that project, take all the types we've found and move to the
            // next project.  Continue this until we've exhausted all projects.
            //
            // Because there is a data-dependency between the projects, we cannot process them in
            // parallel.  (Processing linearly is also probably preferable to limit the amount of
            // cache churn we could cause creating all those compilations.
            foreach (var project in orderedProjectsToExamine)
            {
                await FindTypesInProjectAsync(
                    searchInMetadata, result,
                    currentMetadataTypes, currentSourceAndMetadataTypes,
                    project,
                    metadataTypeMatches,
                    sourceTypeImmediatelyMatches,
                    shouldContinueSearching,
                    transitive, cancellationToken).ConfigureAwait(false);
            }

            return ToImmutableAndFree(result);
        }
Beispiel #28
0
        public static async Task <ImmutableArray <SymbolAndProjectId> > FindImplementationsForInterfaceMemberAsync(
            this SymbolAndProjectId <ITypeSymbol> typeSymbolAndProjectId,
            SymbolAndProjectId interfaceMemberAndProjectId,
            Solution solution,
            CancellationToken cancellationToken)
        {
            // This method can return multiple results.  Consider the case of:
            //
            // interface IGoo<X> { void Goo(X x); }
            //
            // class C : IGoo<int>, IGoo<string> { void Goo(int x); void Goo(string x); }
            //
            // If you're looking for the implementations of IGoo<X>.Goo then you want to find both
            // results in C.

            var arrBuilder = ArrayBuilder <SymbolAndProjectId> .GetInstance();

            var interfaceMember = interfaceMemberAndProjectId.Symbol;

            // TODO(cyrusn): Implement this using the actual code for
            // TypeSymbol.FindImplementationForInterfaceMember
            var typeSymbol = typeSymbolAndProjectId.Symbol;

            if (typeSymbol == null || interfaceMember == null)
            {
                return(arrBuilder.ToImmutableAndFree());
            }

            if (interfaceMember.Kind != SymbolKind.Event &&
                interfaceMember.Kind != SymbolKind.Method &&
                interfaceMember.Kind != SymbolKind.Property)
            {
                return(arrBuilder.ToImmutableAndFree());
            }

            // WorkItem(4843)
            //
            // 'typeSymbol' has to at least implement the interface containing the member.  note:
            // this just means that the interface shows up *somewhere* in the inheritance chain of
            // this type.  However, this type may not actually say that it implements it.  For
            // example:
            //
            // interface I { void Goo(); }
            //
            // class B { }
            //
            // class C : B, I { }
            //
            // class D : C { }
            //
            // D does implement I transitively through C.  However, even if D has a "Goo" method, it
            // won't be an implementation of I.Goo.  The implementation of I.Goo must be from a type
            // that actually has I in it's direct interface chain, or a type that's a base type of
            // that.  in this case, that means only classes C or B.
            var interfaceType = interfaceMember.ContainingType;

            if (!typeSymbol.ImplementsIgnoringConstruction(interfaceType))
            {
                return(arrBuilder.ToImmutableAndFree());
            }

            // We've ascertained that the type T implements some constructed type of the form I<X>.
            // However, we're not precisely sure which constructions of I<X> are being used.  For
            // example, a type C might implement I<int> and I<string>.  If we're searching for a
            // method from I<X> we might need to find several methods that implement different
            // instantiations of that method.
            var originalInterfaceType   = interfaceMember.ContainingType.OriginalDefinition;
            var originalInterfaceMember = interfaceMember.OriginalDefinition;

            var constructedInterfaces = typeSymbol.AllInterfaces.Where(i =>
                                                                       SymbolEquivalenceComparer.Instance.Equals(i.OriginalDefinition, originalInterfaceType));

            // Try to get the compilation for the symbol we're searching for,
            // which can help identify matches with the call to SymbolFinder.OriginalSymbolsMatch.
            // OriginalSymbolMatch allows types to be matched across different assemblies
            // if they are considered to be the same type, which provides a more accurate
            // implementations list for interfaces.
            var typeSymbolProject      = solution.GetProject(typeSymbolAndProjectId.ProjectId);
            var interfaceMemberProject = solution.GetProject(interfaceMemberAndProjectId.ProjectId);

            var typeSymbolCompilation = await GetCompilationOrNullAsync(typeSymbolProject, cancellationToken).ConfigureAwait(false);

            var interfaceMemberCompilation = await GetCompilationOrNullAsync(interfaceMemberProject, cancellationToken).ConfigureAwait(false);

            foreach (var constructedInterface in constructedInterfaces)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var constructedInterfaceMember = constructedInterface.GetMembers().FirstOrDefault(typeSymbol =>
                                                                                                  SymbolFinder.OriginalSymbolsMatch(
                                                                                                      typeSymbol,
                                                                                                      interfaceMember,
                                                                                                      solution,
                                                                                                      typeSymbolCompilation,
                                                                                                      interfaceMemberCompilation,
                                                                                                      cancellationToken));

                if (constructedInterfaceMember == null)
                {
                    continue;
                }

                // Now we need to walk the base type chain, but we start at the first type that actually
                // has the interface directly in its interface hierarchy.
                var seenTypeDeclaringInterface = false;
                for (var currentType = typeSymbol; currentType != null; currentType = currentType.BaseType)
                {
                    seenTypeDeclaringInterface = seenTypeDeclaringInterface ||
                                                 currentType.GetOriginalInterfacesAndTheirBaseInterfaces().Contains(interfaceType.OriginalDefinition);

                    if (seenTypeDeclaringInterface)
                    {
                        var result = currentType.FindImplementations(constructedInterfaceMember, solution.Workspace);

                        if (result != null)
                        {
                            arrBuilder.Add(typeSymbolAndProjectId.WithSymbol(result));
                            break;
                        }
                    }
                }
            }

            return(arrBuilder.ToImmutableAndFree());
        /// <summary>
        /// Returns the corresponding symbol in this type or a base type that implements
        /// interfaceMember (either implicitly or explicitly), or null if no such symbol exists
        /// (which might be either because this type doesn't implement the container of
        /// interfaceMember, or this type doesn't supply a member that successfully implements
        /// interfaceMember).
        /// </summary>
        public static IEnumerable <SymbolAndProjectId> FindImplementationsForInterfaceMember(
            this SymbolAndProjectId <ITypeSymbol> typeSymbolAndProjectId,
            ISymbol interfaceMember,
            Workspace workspace,
            CancellationToken cancellationToken)
        {
            // This method can return multiple results.  Consider the case of:
            //
            // interface IGoo<X> { void Goo(X x); }
            //
            // class C : IGoo<int>, IGoo<string> { void Goo(int x); void Goo(string x); }
            //
            // If you're looking for the implementations of IGoo<X>.Goo then you want to find both
            // results in C.

            // TODO(cyrusn): Implement this using the actual code for
            // TypeSymbol.FindImplementationForInterfaceMember
            var typeSymbol = typeSymbolAndProjectId.Symbol;

            if (typeSymbol == null || interfaceMember == null)
            {
                yield break;
            }

            if (interfaceMember.Kind != SymbolKind.Event &&
                interfaceMember.Kind != SymbolKind.Method &&
                interfaceMember.Kind != SymbolKind.Property)
            {
                yield break;
            }

            // WorkItem(4843)
            //
            // 'typeSymbol' has to at least implement the interface containing the member.  note:
            // this just means that the interface shows up *somewhere* in the inheritance chain of
            // this type.  However, this type may not actually say that it implements it.  For
            // example:
            //
            // interface I { void Goo(); }
            //
            // class B { }
            //
            // class C : B, I { }
            //
            // class D : C { }
            //
            // D does implement I transitively through C.  However, even if D has a "Goo" method, it
            // won't be an implementation of I.Goo.  The implementation of I.Goo must be from a type
            // that actually has I in it's direct interface chain, or a type that's a base type of
            // that.  in this case, that means only classes C or B.
            var interfaceType = interfaceMember.ContainingType;

            if (!typeSymbol.ImplementsIgnoringConstruction(interfaceType))
            {
                yield break;
            }

            // We've ascertained that the type T implements some constructed type of the form I<X>.
            // However, we're not precisely sure which constructions of I<X> are being used.  For
            // example, a type C might implement I<int> and I<string>.  If we're searching for a
            // method from I<X> we might need to find several methods that implement different
            // instantiations of that method.
            var originalInterfaceType   = interfaceMember.ContainingType.OriginalDefinition;
            var originalInterfaceMember = interfaceMember.OriginalDefinition;
            var constructedInterfaces   = typeSymbol.AllInterfaces.Where(i =>
                                                                         SymbolEquivalenceComparer.Instance.Equals(i.OriginalDefinition, originalInterfaceType));

            foreach (var constructedInterface in constructedInterfaces)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var constructedInterfaceMember = constructedInterface.GetMembers().FirstOrDefault(m =>
                                                                                                  SymbolEquivalenceComparer.Instance.Equals(m.OriginalDefinition, originalInterfaceMember));

                if (constructedInterfaceMember == null)
                {
                    continue;
                }

                // Now we need to walk the base type chain, but we start at the first type that actually
                // has the interface directly in its interface hierarchy.
                var seenTypeDeclaringInterface = false;
                for (var currentType = typeSymbol; currentType != null; currentType = currentType.BaseType)
                {
                    seenTypeDeclaringInterface = seenTypeDeclaringInterface ||
                                                 currentType.GetOriginalInterfacesAndTheirBaseInterfaces().Contains(interfaceType.OriginalDefinition);

                    if (seenTypeDeclaringInterface)
                    {
                        var result = FindImplementations(workspace, constructedInterfaceMember, currentType);

                        if (result != null)
                        {
                            yield return(typeSymbolAndProjectId.WithSymbol(result));

                            break;
                        }
                    }
                }
            }
        }
Beispiel #30
0
        private async Task <ImmutableArray <SymbolAndProjectId> > CascadeBetweenPropertyOrEventAndAccessorParameterAsync(
            Solution solution,
            SymbolAndProjectId <IParameterSymbol> parameterAndProjectId,
            CancellationToken cancellationToken)
        {
            var results = ArrayBuilder <SymbolAndProjectId> .GetInstance();

            var parameter        = parameterAndProjectId.Symbol;
            var ordinal          = parameter.Ordinal;
            var containingSymbol = parameter.ContainingSymbol;

            if (containingSymbol is IMethodSymbol)
            {
                var containingMethod = (IMethodSymbol)containingSymbol;
                if (containingMethod.AssociatedSymbol is IPropertySymbol)
                {
                    var property = (IPropertySymbol)containingMethod.AssociatedSymbol;
                    if (ordinal < property.Parameters.Length)
                    {
                        results.Add(parameterAndProjectId.WithSymbol(property.Parameters[ordinal]));
                    }
                }
                else
                {
                    var namedType = containingMethod.ContainingType as INamedTypeSymbol;
                    if (namedType != null && namedType.IsDelegateType() && namedType.AssociatedSymbol != null)
                    {
                        var eventNode = namedType.AssociatedSymbol.DeclaringSyntaxReferences.Select(r => r.GetSyntax(cancellationToken)).FirstOrDefault();
                        if (eventNode != null)
                        {
                            var document = solution.GetDocument(eventNode.SyntaxTree);
                            if (document != null)
                            {
                                var syntaxFacts   = document.GetLanguageService <ISyntaxFactsService>();
                                var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                                foreach (var token in eventNode.DescendantTokens())
                                {
                                    if (IdentifiersMatch(syntaxFacts, parameter.Name, token))
                                    {
                                        var eventParam = semanticModel.GetDeclaredSymbol(token.Parent, cancellationToken) as IParameterSymbol;
                                        if (eventParam != null && eventParam.Type != null && eventParam.Type.Equals(parameter.Type))
                                        {
                                            results.Add(parameterAndProjectId.WithSymbol(eventParam));
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else if (containingSymbol is IPropertySymbol)
            {
                var containingProperty = (IPropertySymbol)containingSymbol;
                if (containingProperty.GetMethod != null && ordinal < containingProperty.GetMethod.Parameters.Length)
                {
                    results.Add(parameterAndProjectId.WithSymbol(containingProperty.GetMethod.Parameters[ordinal]));
                }

                if (containingProperty.SetMethod != null && ordinal < containingProperty.SetMethod.Parameters.Length)
                {
                    results.Add(parameterAndProjectId.WithSymbol(containingProperty.SetMethod.Parameters[ordinal]));
                }
            }
            else if (containingSymbol is IEventSymbol)
            {
                var containingEvent = (IEventSymbol)containingSymbol;
                var namedType       = containingEvent.Type as INamedTypeSymbol;
                if (namedType != null && namedType.IsDelegateType())
                {
                    foreach (var member in namedType.GetMembers())
                    {
                        if (member.Kind == SymbolKind.Method)
                        {
                            foreach (var memberParam in member.GetParameters())
                            {
                                if (memberParam.Name.Equals(parameter.Name) && memberParam.Type != null && memberParam.Type.Equals(parameter.Type))
                                {
                                    results.Add(parameterAndProjectId.WithSymbol(memberParam));
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            return(results.ToImmutableAndFree());
        }
        internal static async Task<ImmutableArray<SymbolAndProjectId>> FindImplementedInterfaceMembersAsync(
            SymbolAndProjectId symbolAndProjectId, Solution solution, IImmutableSet<Project> projects = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            // Member can only implement interface members if it is an explicit member, or if it is
            // public and non static.
            var symbol = symbolAndProjectId.Symbol;
            if (symbol != null)
            {
                var explicitImplementations = symbol.ExplicitInterfaceImplementations();
                if (explicitImplementations.Length > 0)
                {
                    return explicitImplementations.SelectAsArray(symbolAndProjectId.WithSymbol);
                }
                else if (
                    symbol.DeclaredAccessibility == Accessibility.Public && !symbol.IsStatic &&
                    (symbol.ContainingType.TypeKind == TypeKind.Class || symbol.ContainingType.TypeKind == TypeKind.Struct))
                {
                    // Interface implementation is a tricky thing.  A method may implement an interface
                    // method, even if its containing type doesn't state that it implements the
                    // interface.  For example:
                    //
                    //  interface IFoo { void Foo(); }
                    //
                    //  class Base { public void Foo(); }
                    //
                    //  class Derived : Base, IFoo { }
                    //
                    // In this case, Base.Foo *does* implement IFoo.Foo in the context of the type
                    // Derived.
                    var containingType = symbolAndProjectId.WithSymbol(
                        symbol.ContainingType.OriginalDefinition);
                    var derivedClasses = await SymbolFinder.FindDerivedClassesAsync(
                        containingType, solution, projects, cancellationToken).ConfigureAwait(false);
                    var allTypes = derivedClasses.Concat(containingType);

                    var builder = ArrayBuilder<SymbolAndProjectId>.GetInstance();

                    foreach (var type in allTypes.Convert<INamedTypeSymbol, ITypeSymbol>())
                    {
                        foreach (var interfaceType in GetAllInterfaces(type))
                        {
                            if (interfaceType.Symbol.MemberNames.Contains(symbol.Name))
                            {
                                foreach (var m in GetMembers(interfaceType, symbol.Name))
                                {
                                    var sourceMethod = await FindSourceDefinitionAsync(m, solution, cancellationToken).ConfigureAwait(false);
                                    var bestMethod = sourceMethod.Symbol != null ? sourceMethod : m;

                                    var implementations = type.FindImplementationsForInterfaceMember(
                                        bestMethod.Symbol, solution.Workspace, cancellationToken);
                                    foreach (var implementation in implementations)
                                    {
                                        if (implementation.Symbol != null &&
                                            SymbolEquivalenceComparer.Instance.Equals(implementation.Symbol.OriginalDefinition, symbol.OriginalDefinition))
                                        {
                                            builder.Add(bestMethod);
                                        }
                                    }
                                }
                            }
                        }
                    }

                    var result = builder.Distinct(SymbolAndProjectIdComparer.SymbolEquivalenceInstance)
                                        .ToImmutableArray();
                    builder.Free();
                    return result;
                }
            }

            return ImmutableArray<SymbolAndProjectId>.Empty;
        }
Beispiel #32
0
 internal static IEnumerable<SymbolAndProjectId> GetOverloadedSymbols(
     SymbolAndProjectId symbolAndProjectId)
 {
     var symbol = symbolAndProjectId.Symbol;
     if (symbol is IMethodSymbol)
     {
         var containingType = symbol.ContainingType;
         if (containingType.Kind == SymbolKind.NamedType)
         {
             foreach (var member in containingType.GetMembers())
             {
                 if (string.Equals(member.MetadataName, symbol.MetadataName, StringComparison.Ordinal) && member is IMethodSymbol && !member.Equals(symbol))
                 {
                     yield return symbolAndProjectId.WithSymbol(member);
                 }
             }
         }
     }
 }
            internal static async Task<SymbolAndProjectId> GetPropertyFromAccessorOrAnOverride(
                SymbolAndProjectId symbolAndProjectId, Solution solution, CancellationToken cancellationToken)
            {
                var symbol = symbolAndProjectId.Symbol;
                if (symbol.IsPropertyAccessor())
                {
                    return symbolAndProjectId.WithSymbol(
                        ((IMethodSymbol)symbol).AssociatedSymbol);
                }

                if (symbol.IsOverride && symbol.OverriddenMember() != null)
                {
                    var originalSourceSymbol = await SymbolFinder.FindSourceDefinitionAsync(
                        symbolAndProjectId.WithSymbol(symbol.OverriddenMember()),
                        solution, cancellationToken).ConfigureAwait(false);

                    if (originalSourceSymbol.Symbol != null)
                    {
                        return await GetPropertyFromAccessorOrAnOverride(originalSourceSymbol, solution, cancellationToken).ConfigureAwait(false);
                    }
                }

                if (symbol.Kind == SymbolKind.Method &&
                    symbol.ContainingType.TypeKind == TypeKind.Interface)
                {
                    var methodImplementors = await SymbolFinder.FindImplementationsAsync(
                        symbolAndProjectId, solution, cancellationToken: cancellationToken).ConfigureAwait(false);

                    foreach (var methodImplementor in methodImplementors)
                    {
                        var propertyAccessorOrAnOverride = await GetPropertyFromAccessorOrAnOverride(methodImplementor, solution, cancellationToken).ConfigureAwait(false);
                        if (propertyAccessorOrAnOverride.Symbol != null)
                        {
                            return propertyAccessorOrAnOverride;
                        }
                    }
                }

                return default(SymbolAndProjectId);
            }
        private static SymbolAndProjectId MapToAppropriateSymbol(
            SymbolAndProjectId symbolAndProjectId)
        {
            // Never search for an alias.  Always search for it's target.  Note: if the caller was
            // actually searching for an alias, they can always get that information out in the end
            // by checking the ReferenceLocations that are returned.
            var symbol = symbolAndProjectId.Symbol;
            var searchSymbol = symbol;

            if (searchSymbol is IAliasSymbol)
            {
                searchSymbol = ((IAliasSymbol)searchSymbol).Target;
            }

            searchSymbol = searchSymbol.GetOriginalUnreducedDefinition();

            // If they're searching for a delegate constructor, then just search for the delegate
            // itself.  They're practically interchangeable for consumers.
            if (searchSymbol.IsConstructor() && searchSymbol.ContainingType.TypeKind == TypeKind.Delegate)
            {
                searchSymbol = symbol.ContainingType;
            }

            return symbolAndProjectId.WithSymbol(searchSymbol);
        }
Beispiel #35
0
        private static async Task <ImmutableArray <SymbolAndProjectId <INamedTypeSymbol> > > FindTypesAsync(
            SymbolAndProjectId <INamedTypeSymbol> type,
            Solution solution,
            IImmutableSet <Project> projects,
            Func <SymbolAndProjectIdSet, INamedTypeSymbol, bool> metadataTypeMatches,
            Func <SymbolAndProjectIdSet, INamedTypeSymbol, bool> sourceTypeImmediatelyMatches,
            Func <INamedTypeSymbol, bool> shouldContinueSearching,
            bool transitive,
            CancellationToken cancellationToken)
        {
            type     = type.WithSymbol(type.Symbol.OriginalDefinition);
            projects = projects ?? ImmutableHashSet.Create(solution.Projects.ToArray());
            var searchInMetadata = type.Symbol.Locations.Any(s_isInMetadata);

            // Note: it is not sufficient to just walk the list of projects passed in,
            // searching only those for derived types.
            //
            // Say we have projects: A <- B <- C, but only projects A and C are passed in.
            // We might miss a derived type in C if there's an intermediate derived type
            // in B.
            //
            // However, say we have projects A <- B <- C <- D, only only projects A and C
            // are passed in.  There is no need to check D as there's no way it could
            // contribute an intermediate type that affects A or C.  We only need to check
            // A, B and C

            // First find all the projects that could potentially reference this type.
            var projectsThatCouldReferenceType = await GetProjectsThatCouldReferenceTypeAsync(
                type.Symbol, solution, searchInMetadata, cancellationToken).ConfigureAwait(false);

            // Now, based on the list of projects that could actually reference the type,
            // and the list of projects the caller wants to search, find the actual list of
            // projects we need to search through.
            //
            // This list of projects is properly topologicaly ordered.  Because of this we
            // can just process them in order from first to last because we know no project
            // in this list could affect a prior project.
            var orderedProjectsToExamine = GetOrderedProjectsToExamine(
                solution, projects, projectsThatCouldReferenceType);

            var currentMetadataTypes          = CreateSymbolAndProjectIdSet();
            var currentSourceAndMetadataTypes = CreateSymbolAndProjectIdSet();

            currentSourceAndMetadataTypes.Add(type);
            if (searchInMetadata)
            {
                currentMetadataTypes.Add(type);
            }

            var result = CreateSymbolAndProjectIdSet();

            // Now walk the projects from left to right seeing what our type cascades to. Once we
            // reach a fixed point in that project, take all the types we've found and move to the
            // next project.  Continue this until we've exhausted all projects.
            //
            // Because there is a data-dependency between the projects, we cannot process them in
            // parallel.  (Processing linearly is also probably preferable to limit the amount of
            // cache churn we could cause creating all those compilations.
            foreach (var project in orderedProjectsToExamine)
            {
                await FindTypesInProjectAsync(
                    searchInMetadata, result,
                    currentMetadataTypes, currentSourceAndMetadataTypes,
                    project,
                    metadataTypeMatches,
                    sourceTypeImmediatelyMatches,
                    shouldContinueSearching,
                    transitive, cancellationToken).ConfigureAwait(false);
            }

            return(ToImmutableAndFree(result));
        }