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); using var _ = ArrayBuilder <SymbolAndProjectId> .GetInstance(out var builder); 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); } } } } } } return(builder.Distinct(SymbolAndProjectIdComparer.SymbolEquivalenceInstance) .ToImmutableArray()); } } return(ImmutableArray <SymbolAndProjectId> .Empty); }
private static IEnumerable <SymbolAndProjectId> GetMembers( SymbolAndProjectId <INamedTypeSymbol> interfaceType, string name) { return(interfaceType.Symbol.GetMembers(name).Select(interfaceType.WithSymbol)); }
private static IEnumerable <SymbolAndProjectId <INamedTypeSymbol> > GetAllInterfaces( SymbolAndProjectId <ITypeSymbol> type) { return(type.Symbol.AllInterfaces.Select(type.WithSymbol)); }
/// <summary> /// Finds all the callers of a specified symbol. /// </summary> internal static Task <IEnumerable <SymbolCallerInfo> > FindCallersAsync( SymbolAndProjectId symbolAndProjectId, Solution solution, CancellationToken cancellationToken = default) { return(FindCallersAsync(symbolAndProjectId, solution, documents: null, cancellationToken: cancellationToken)); }
public Task OnReferenceFoundAsync(SymbolAndProjectId symbolAndProjectId, ReferenceLocation location) { _progress.OnReferenceFound(symbolAndProjectId.Symbol, location); return(Task.CompletedTask); }
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)); }
public Task OnReferenceFoundAsync(SymbolAndProjectId symbol, ReferenceLocation location) => Task.CompletedTask;
public Task OnDefinitionFoundAsync(SymbolAndProjectId symbolAndProjectId) { _progress.OnDefinitionFound(symbolAndProjectId.Symbol); return(Task.CompletedTask); }
public Task OnDefinitionFoundAsync(SymbolAndProjectId symbol) => Task.CompletedTask;
public bool Equals(SymbolAndProjectId other) { // See class comment on why we only use Symbol and ignore ProjectId. return(Equals(this.Symbol, other.Symbol)); }
public int GetHashCode(SymbolAndProjectId <TSymbol> obj) { return(_underlyingComparer.GetHashCode(obj.Symbol)); }
public bool Equals(SymbolAndProjectId <TSymbol> x, SymbolAndProjectId <TSymbol> y) { return(_underlyingComparer.Equals(x.Symbol, y.Symbol)); }
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 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); }