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()); }
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>()); }
/// <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)); } } }
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); }
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>()); }