Esempio n. 1
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);
        }
Esempio n. 2
0
        /// <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>());
        }