diff --git a/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs b/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs index 67cb1756f1592d81de7d7ade0581c993d6014955..ae3d5f16f7ac147b5ef1588cf356214fc013e4d9 100644 --- a/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs +++ b/src/EditorFeatures/Test/SymbolFinder/DependentTypeFinderTests.cs @@ -563,7 +563,34 @@ struct OtherStruct { } } [Theory, CombinatorialData] - public async Task ImplementingTypesDoesNotProduceEnums(TestHost host) + public async Task ImplementingTypesDoesProduceDelegates(TestHost host) + { + using var workspace = GetWorkspace(host); + var solution = workspace.CurrentSolution; + + // create a normal assembly with a type derived from the portable abstract base + solution = AddProjectWithMetadataReferences(solution, "NormalProject", LanguageNames.CSharp, @" +delegate void D(); +", MscorlibRef); + + // get symbols for types + var compilation = await GetNormalProject(solution).GetCompilationAsync(); + var rootType = compilation.GetTypeByMetadataName("System.ICloneable"); + + Assert.NotNull(rootType); + + var transitiveImpls = await SymbolFinder.FindImplementationsAsync( + rootType, solution, transitive: true); + + var delegates = transitiveImpls.Where(i => i.TypeKind == TypeKind.Delegate); + + Assert.NotEmpty(delegates); // We should find delegates when looking for implementations + Assert.True(delegates.Any(i => i.Locations.Any(loc => loc.IsInMetadata)), "We should find a metadata delegate"); + Assert.Single(delegates.Where(i => i.Locations.Any(loc => loc.IsInSource))); // We should find a single source delegate + } + + [Theory, CombinatorialData] + public async Task ImplementingTypesDoesProduceEnums(TestHost host) { using var workspace = GetWorkspace(host); var solution = workspace.CurrentSolution; @@ -584,6 +611,12 @@ enum E var transitiveImpls = await SymbolFinder.FindImplementationsAsync( rootType, solution, transitive: true); + + var enums = transitiveImpls.Where(i => i.TypeKind == TypeKind.Enum); + + Assert.NotEmpty(enums); // We should find enums when looking for implementations + Assert.True(enums.Any(i => i.Locations.Any(loc => loc.IsInMetadata)), "We should find a metadata enum"); + Assert.Single(enums.Where(i => i.Locations.Any(loc => loc.IsInSource))); // We should find a single source type } } } diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ImplementingTypes.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ImplementingTypes.cs index 88f7cca09a5d0d5477b669adb35782461ef979cb..5e0ca42c2bdf95fb31609f6aebd900a7aab13805 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ImplementingTypes.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ImplementingTypes.cs @@ -84,9 +84,14 @@ static bool TypeMatches(INamedTypeSymbol type, SymbolSet set) transitive: transitive, cancellationToken: cancellationToken).ConfigureAwait(false); - // Only classes/struct implement interface types. Derived interfaces can be found with - // FindDerivedInterfacesAsync. - return allTypes.WhereAsArray(t => t.TypeKind == TypeKind.Class || t.TypeKind == TypeKind.Struct); + // Only classes/struct/delegates/enums implement interface types. Derived interfaces can be found with + // FindDerivedInterfacesAsync. Delegates/Enums only happen in a few corner cases. For example, enums + // implement IComparable, and delegates implement ICloneable. + return allTypes.WhereAsArray( + t => t.TypeKind == TypeKind.Class || + t.TypeKind == TypeKind.Struct || + t.TypeKind == TypeKind.Delegate || + t.TypeKind == TypeKind.Enum); } return ImmutableArray.Empty;