Beispiel #1
0
        internal static async Task <ImmutableArray <SymbolAndProjectId> > FindOverridesAsync(
            SymbolAndProjectId symbolAndProjectId, Solution solution, IImmutableSet <Project> projects = null, CancellationToken cancellationToken = default)
        {
            var results = ArrayBuilder <SymbolAndProjectId> .GetInstance();

            var symbol = symbolAndProjectId.Symbol?.OriginalDefinition;

            if (symbol.IsOverridable())
            {
                // To find the overrides, we need to walk down the type hierarchy and check all
                // derived types.
                var containingType = symbol.ContainingType;
                var derivedTypes   = await FindDerivedClassesAsync(
                    symbolAndProjectId.WithSymbol(containingType),
                    solution, projects, cancellationToken).ConfigureAwait(false);

                foreach (var type in derivedTypes)
                {
                    foreach (var m in type.Symbol.GetMembers(symbol.Name))
                    {
                        var sourceMember = await FindSourceDefinitionAsync(m, solution, cancellationToken).ConfigureAwait(false);

                        var bestMember = sourceMember ?? m;

                        if (IsOverride(solution, bestMember, symbol, cancellationToken))
                        {
                            results.Add(new SymbolAndProjectId(bestMember, type.ProjectId));
                        }
                    }
                }
            }

            return(results.ToImmutableAndFree());
        }
Beispiel #2
0
        internal static Task <SymbolAndProjectId> FindSourceDefinitionAsync(
            SymbolAndProjectId symbolAndProjectId, Solution solution, CancellationToken cancellationToken = default(CancellationToken))
        {
            var symbol = symbolAndProjectId.Symbol;

            if (symbol != null)
            {
                symbol             = symbol.GetOriginalUnreducedDefinition();
                symbolAndProjectId = symbolAndProjectId.WithSymbol(symbol);
                switch (symbol.Kind)
                {
                case SymbolKind.Event:
                case SymbolKind.Field:
                case SymbolKind.Method:
                case SymbolKind.Local:
                case SymbolKind.NamedType:
                case SymbolKind.Parameter:
                case SymbolKind.Property:
                case SymbolKind.TypeParameter:
                case SymbolKind.Namespace:
                    return(FindSourceDefinitionWorkerAsync(symbolAndProjectId, solution, cancellationToken));
                }
            }

            return(SpecializedTasks.Default <SymbolAndProjectId>());
        }
        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 #4
0
        /// <summary>
        /// Finds all the callers of a specified symbol.
        /// </summary>
        internal static async Task <IEnumerable <SymbolCallerInfo> > FindCallersAsync(
            SymbolAndProjectId symbolAndProjectId, Solution solution, IImmutableSet <Document> documents, CancellationToken cancellationToken = default)
        {
            symbolAndProjectId = symbolAndProjectId.WithSymbol(symbolAndProjectId.Symbol.OriginalDefinition);
            var foundSymbol = await FindSourceDefinitionAsync(symbolAndProjectId, solution, cancellationToken).ConfigureAwait(false);

            symbolAndProjectId = foundSymbol.Symbol != null ? foundSymbol : symbolAndProjectId;

            var references = await FindCallReferencesAsync(solution, symbolAndProjectId, documents, cancellationToken).ConfigureAwait(false);

            var directReference = references.Where(
                r => SymbolEquivalenceComparer.Instance.Equals(symbolAndProjectId.Symbol, r.Definition)).FirstOrDefault();

            var indirectReferences = references.WhereAsArray(r => r != directReference);

            var results = new List <SymbolCallerInfo>();

            if (directReference != null)
            {
                await AddReferencingSymbols(directReference, isDirect : true).ConfigureAwait(false);
            }

            foreach (var indirectReference in indirectReferences)
            {
                await AddReferencingSymbols(indirectReference, isDirect : false).ConfigureAwait(false);
            }

            return(results);

            async Task AddReferencingSymbols(ReferencedSymbol reference, bool isDirect)
            {
                var result = await reference.Locations.FindReferencingSymbolsAsync(cancellationToken).ConfigureAwait(false);

                foreach (var(callingSymbol, locations) in result)
                {
                    results.Add(new SymbolCallerInfo(callingSymbol, reference.DefinitionAndProjectId, locations, isDirect));
                }
            }
        }
Beispiel #5
0
        internal static async Task <ImmutableArray <SymbolAndProjectId> > FindImplementedInterfaceMembersAsync(
            SymbolAndProjectId symbolAndProjectId, Solution solution, IImmutableSet <Project> projects = null, CancellationToken cancellationToken = default)
        {
            // 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 IGoo { void Goo(); }
                    //
                    //  class Base { public void Goo(); }
                    //
                    //  class Derived : Base, IGoo { }
                    //
                    // In this case, Base.Goo *does* implement IGoo.Goo 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))
                        {
                            // We don't want to look inside this type if we can avoid it. So first
                            // make sure that the interface even contains a symbol with the same
                            // name as the symbol we're looking for.
                            var nameToLookFor = symbol.IsPropertyAccessor()
                                ? ((IMethodSymbol)symbol).AssociatedSymbol.Name
                                : symbol.Name;
                            if (interfaceType.Symbol.MemberNames.Contains(nameToLookFor))
                            {
                                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 = await type.FindImplementationsForInterfaceMemberAsync(
                                        bestMethod, solution, cancellationToken).ConfigureAwait(false);

                                    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 #6
0
        private static async Task <IEnumerable <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(result);
        }
        internal static async Task <IEnumerable <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.Select(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);

                    List <SymbolAndProjectId> results = null;

                    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))
                                        {
                                            results = results ?? new List <SymbolAndProjectId>();
                                            results.Add(bestMethod);
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (results != null)
                    {
                        return(results.Distinct(SymbolAndProjectIdComparer.SymbolEquivalenceInstance));
                    }
                }
            }

            return(SpecializedCollections.EmptyEnumerable <SymbolAndProjectId>());
        }