未验证 提交 a4672177 编写于 作者: A Andrew Hall 提交者: GitHub

Merge pull request #33227 from ryzngard/issue/28827_gotoimplementation_broken

Update the FindImplementationsForInterfaceMember
...@@ -246,6 +246,18 @@ private static MetadataReference GetOrCreateMetadataReference(ref MetadataRefere ...@@ -246,6 +246,18 @@ private static MetadataReference GetOrCreateMetadataReference(ref MetadataRefere
LazyThreadSafetyMode.PublicationOnly); LazyThreadSafetyMode.PublicationOnly);
public static MetadataReference CSharpNetStandard10Ref => s_stdCSharpRef.Value; public static MetadataReference CSharpNetStandard10Ref => s_stdCSharpRef.Value;
private static readonly Lazy<MetadataReference> s_std20Ref = new Lazy<MetadataReference>(
() => AssemblyMetadata.CreateFromImage(TestResources.NetFX.netstandard20.netstandard).GetReference(display: "netstandard20.netstandard.dll"),
LazyThreadSafetyMode.PublicationOnly);
public static MetadataReference NetStandard20Ref => s_std20Ref.Value;
private static readonly Lazy<MetadataReference> s_46NetStandardFacade = new Lazy<MetadataReference>(
() => AssemblyMetadata.CreateFromImage(TestResources.NetFX.net461.netstandard).GetReference(display: "net461.netstandard.dll"),
LazyThreadSafetyMode.PublicationOnly);
public static MetadataReference Net46StandardFacade => s_46NetStandardFacade.Value;
private static readonly Lazy<MetadataReference> s_systemDynamicRuntimeRef = new Lazy<MetadataReference>( private static readonly Lazy<MetadataReference> s_systemDynamicRuntimeRef = new Lazy<MetadataReference>(
() => AssemblyMetadata.CreateFromImage(TestResources.NetFX.netstandard13.System_Dynamic_Runtime).GetReference(display: "System.Dynamic.Runtime.dll (netstandard 1.3 ref)"), () => AssemblyMetadata.CreateFromImage(TestResources.NetFX.netstandard13.System_Dynamic_Runtime).GetReference(display: "System.Dynamic.Runtime.dll (netstandard 1.3 ref)"),
LazyThreadSafetyMode.PublicationOnly); LazyThreadSafetyMode.PublicationOnly);
......
...@@ -144,8 +144,8 @@ public static partial class SymbolFinder ...@@ -144,8 +144,8 @@ public static partial class SymbolFinder
var sourceMethod = await FindSourceDefinitionAsync(m, solution, cancellationToken).ConfigureAwait(false); var sourceMethod = await FindSourceDefinitionAsync(m, solution, cancellationToken).ConfigureAwait(false);
var bestMethod = sourceMethod.Symbol != null ? sourceMethod : m; var bestMethod = sourceMethod.Symbol != null ? sourceMethod : m;
var implementations = type.FindImplementationsForInterfaceMember( var implementations = await type.FindImplementationsForInterfaceMemberAsync(
bestMethod.Symbol, solution.Workspace, cancellationToken); bestMethod.Symbol, solution, cancellationToken).ConfigureAwait(false);
foreach (var implementation in implementations) foreach (var implementation in implementations)
{ {
if (implementation.Symbol != null && if (implementation.Symbol != null &&
...@@ -249,10 +249,11 @@ public static partial class SymbolFinder ...@@ -249,10 +249,11 @@ public static partial class SymbolFinder
ImmutableArray<SymbolAndProjectId>.Builder results = null; ImmutableArray<SymbolAndProjectId>.Builder results = null;
foreach (var t in allTypes.Convert<INamedTypeSymbol, ITypeSymbol>()) foreach (var t in allTypes.Convert<INamedTypeSymbol, ITypeSymbol>())
{ {
foreach (var m in t.FindImplementationsForInterfaceMember(symbol, solution.Workspace, cancellationToken)) var implementations = await t.FindImplementationsForInterfaceMemberAsync(symbolAndProjectId.Symbol, solution, cancellationToken).ConfigureAwait(false);
foreach (var implementation in implementations)
{ {
var sourceDef = await FindSourceDefinitionAsync(m, solution, cancellationToken).ConfigureAwait(false); var sourceDef = await FindSourceDefinitionAsync(implementation, solution, cancellationToken).ConfigureAwait(false);
var bestDef = sourceDef.Symbol != null ? sourceDef : m; var bestDef = sourceDef.Symbol != null ? sourceDef : implementation;
if (IsAccessible(bestDef)) if (IsAccessible(bestDef))
{ {
results = results ?? ImmutableArray.CreateBuilder<SymbolAndProjectId>(); results = results ?? ImmutableArray.CreateBuilder<SymbolAndProjectId>();
......
...@@ -6,9 +6,11 @@ ...@@ -6,9 +6,11 @@
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.Utilities;
using Roslyn.Utilities; using Roslyn.Utilities;
...@@ -91,10 +93,10 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol) ...@@ -91,10 +93,10 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol)
/// interfaceMember, or this type doesn't supply a member that successfully implements /// interfaceMember, or this type doesn't supply a member that successfully implements
/// interfaceMember). /// interfaceMember).
/// </summary> /// </summary>
public static IEnumerable<SymbolAndProjectId> FindImplementationsForInterfaceMember( public static async Task<ImmutableArray<SymbolAndProjectId>> FindImplementationsForInterfaceMemberAsync(
this SymbolAndProjectId<ITypeSymbol> typeSymbolAndProjectId, this SymbolAndProjectId<ITypeSymbol> typeSymbolAndProjectId,
ISymbol interfaceMember, ISymbol interfaceMember,
Workspace workspace, Solution solution,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
// This method can return multiple results. Consider the case of: // This method can return multiple results. Consider the case of:
...@@ -106,19 +108,21 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol) ...@@ -106,19 +108,21 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol)
// If you're looking for the implementations of IGoo<X>.Goo then you want to find both // If you're looking for the implementations of IGoo<X>.Goo then you want to find both
// results in C. // results in C.
var arrBuilder = ArrayBuilder<SymbolAndProjectId>.GetInstance();
// TODO(cyrusn): Implement this using the actual code for // TODO(cyrusn): Implement this using the actual code for
// TypeSymbol.FindImplementationForInterfaceMember // TypeSymbol.FindImplementationForInterfaceMember
var typeSymbol = typeSymbolAndProjectId.Symbol; var typeSymbol = typeSymbolAndProjectId.Symbol;
if (typeSymbol == null || interfaceMember == null) if (typeSymbol == null || interfaceMember == null)
{ {
yield break; return arrBuilder.ToImmutableAndFree();
} }
if (interfaceMember.Kind != SymbolKind.Event && if (interfaceMember.Kind != SymbolKind.Event &&
interfaceMember.Kind != SymbolKind.Method && interfaceMember.Kind != SymbolKind.Method &&
interfaceMember.Kind != SymbolKind.Property) interfaceMember.Kind != SymbolKind.Property)
{ {
yield break; return arrBuilder.ToImmutableAndFree();
} }
// WorkItem(4843) // WorkItem(4843)
...@@ -143,7 +147,7 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol) ...@@ -143,7 +147,7 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol)
var interfaceType = interfaceMember.ContainingType; var interfaceType = interfaceMember.ContainingType;
if (!typeSymbol.ImplementsIgnoringConstruction(interfaceType)) if (!typeSymbol.ImplementsIgnoringConstruction(interfaceType))
{ {
yield break; return arrBuilder.ToImmutableAndFree();
} }
// We've ascertained that the type T implements some constructed type of the form I<X>. // We've ascertained that the type T implements some constructed type of the form I<X>.
...@@ -153,14 +157,31 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol) ...@@ -153,14 +157,31 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol)
// instantiations of that method. // instantiations of that method.
var originalInterfaceType = interfaceMember.ContainingType.OriginalDefinition; var originalInterfaceType = interfaceMember.ContainingType.OriginalDefinition;
var originalInterfaceMember = interfaceMember.OriginalDefinition; var originalInterfaceMember = interfaceMember.OriginalDefinition;
var constructedInterfaces = typeSymbol.AllInterfaces.Where(i => var constructedInterfaces = typeSymbol.AllInterfaces.Where(i =>
SymbolEquivalenceComparer.Instance.Equals(i.OriginalDefinition, originalInterfaceType)); SymbolEquivalenceComparer.Instance.Equals(i.OriginalDefinition, originalInterfaceType));
// Try to get the compilation for the symbol we're searching for,
// which can help identify matches with the call to SymbolFinder.OriginalSymbolsMatch.
// OriginalSymbolMatch allows types to be matched across different assemblies
// if they are considered to be the same type, which provides a more accurate
// implementations list for interfaces.
var typeSymbolProject = solution.GetProject(typeSymbolAndProjectId.ProjectId);
var typeSymbolCompilation = typeSymbolProject == null ?
null :
await typeSymbolProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
foreach (var constructedInterface in constructedInterfaces) foreach (var constructedInterface in constructedInterfaces)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var constructedInterfaceMember = constructedInterface.GetMembers().FirstOrDefault(m => var constructedInterfaceMember = constructedInterface.GetMembers().FirstOrDefault(m =>
SymbolEquivalenceComparer.Instance.Equals(m.OriginalDefinition, originalInterfaceMember)); SymbolFinder.OriginalSymbolsMatch(
m,
interfaceMember,
solution,
typeSymbolCompilation,
symbolToMatchCompilation: null,
cancellationToken));
if (constructedInterfaceMember == null) if (constructedInterfaceMember == null)
{ {
...@@ -177,16 +198,18 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol) ...@@ -177,16 +198,18 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol)
if (seenTypeDeclaringInterface) if (seenTypeDeclaringInterface)
{ {
var result = FindImplementations(workspace, constructedInterfaceMember, currentType); var result = FindImplementations(solution.Workspace, constructedInterfaceMember, currentType);
if (result != null) if (result != null)
{ {
yield return typeSymbolAndProjectId.WithSymbol(result); arrBuilder.Add(typeSymbolAndProjectId.WithSymbol(result));
break; break;
} }
} }
} }
} }
return arrBuilder.ToImmutableAndFree();
} }
private static ISymbol FindImplementations(Workspace workspace, ISymbol constructedInterfaceMember, ITypeSymbol currentType) private static ISymbol FindImplementations(Workspace workspace, ISymbol constructedInterfaceMember, ITypeSymbol currentType)
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities; using Roslyn.Test.Utilities;
using Xunit; using Xunit;
...@@ -268,6 +269,47 @@ class B : C, A ...@@ -268,6 +269,47 @@ class B : C, A
Assert.Empty(expectedMatchedLines); Assert.Empty(expectedMatchedLines);
} }
[Fact, WorkItem(28827, "https://github.com/dotnet/roslyn/issues/28827")]
public async Task FindReferences_DifferingAssemblies()
{
var solution = new AdhocWorkspace().CurrentSolution;
solution = AddProjectWithMetadataReferences(solution, "NetStandardProject", LanguageNames.CSharp, @"
namespace N
{
public interface I
{
System.Uri Get();
}
}", NetStandard20Ref);
solution = AddProjectWithMetadataReferences(solution, "DesktopProject", LanguageNames.CSharp, @"
using N;
namespace N2
{
public class Impl : I
{
public System.Uri Get()
{
return null;
}
}
}", SystemRef_v46, solution.Projects.Single(pid => pid.Name == "NetStandardProject").Id);
var desktopProject = solution.Projects.First(p => p.Name == "DesktopProject");
solution = solution.AddMetadataReferences(desktopProject.Id, new[] { MscorlibRef_v46, Net46StandardFacade });
desktopProject = solution.GetProject(desktopProject.Id);
var netStandardProject = solution.Projects.First(p => p.Name == "NetStandardProject");
var interfaceMethod = (IMethodSymbol)(await netStandardProject.GetCompilationAsync()).GetTypeByMetadataName("N.I").GetMembers("Get").First();
var references = (await SymbolFinder.FindReferencesAsync(interfaceMethod, solution)).ToList();
Assert.Equal(2, references.Count);
Assert.True(references.Any(r => r.DefinitionAndProjectId.ProjectId == desktopProject.Id));
}
[WorkItem(4936, "https://github.com/dotnet/roslyn/issues/4936")] [WorkItem(4936, "https://github.com/dotnet/roslyn/issues/4936")]
[Fact] [Fact]
public async Task OverriddenMethodsFromPortableToDesktop() public async Task OverriddenMethodsFromPortableToDesktop()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册