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); }
/// <summary> /// Find symbols for declarations that implement members of the specified interface symbol /// </summary> public static async Task <IEnumerable <ISymbol> > FindImplementedInterfaceMembersAsync( ISymbol symbol, 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. if (symbol != null) { var explicitImplementations = symbol.ExplicitInterfaceImplementations(); if (explicitImplementations.Length > 0) { return(explicitImplementations); } 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 = symbol.ContainingType.OriginalDefinition; var derivedClasses = await SymbolFinder.FindDerivedClassesAsync(containingType, solution, projects, cancellationToken).ConfigureAwait(false); var allTypes = derivedClasses.Concat(containingType); List <ISymbol> results = null; foreach (var type in allTypes) { foreach (var interfaceType in type.AllInterfaces) { if (interfaceType.MemberNames.Contains(symbol.Name)) { foreach (var m in interfaceType.GetMembers(symbol.Name)) { var interfaceMethod = await FindSourceDefinitionAsync(m, solution, cancellationToken).ConfigureAwait(false) ?? m; foreach (var implementation in type.FindImplementationsForInterfaceMember(interfaceMethod, solution.Workspace, cancellationToken)) { if (implementation != null && SymbolEquivalenceComparer.Instance.Equals(implementation.OriginalDefinition, symbol.OriginalDefinition)) { results = results ?? new List <ISymbol>(); results.Add(interfaceMethod); } } } } } } if (results != null) { return(results.Distinct(SymbolEquivalenceComparer.Instance)); } } } return(SpecializedCollections.EmptyEnumerable <ISymbol>()); }