未验证 提交 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
LazyThreadSafetyMode.PublicationOnly);
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>(
() => AssemblyMetadata.CreateFromImage(TestResources.NetFX.netstandard13.System_Dynamic_Runtime).GetReference(display: "System.Dynamic.Runtime.dll (netstandard 1.3 ref)"),
LazyThreadSafetyMode.PublicationOnly);
......
......@@ -144,8 +144,8 @@ public static partial class SymbolFinder
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);
var implementations = await type.FindImplementationsForInterfaceMemberAsync(
bestMethod.Symbol, solution, cancellationToken).ConfigureAwait(false);
foreach (var implementation in implementations)
{
if (implementation.Symbol != null &&
......@@ -249,10 +249,11 @@ public static partial class SymbolFinder
ImmutableArray<SymbolAndProjectId>.Builder results = null;
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 bestDef = sourceDef.Symbol != null ? sourceDef : m;
var sourceDef = await FindSourceDefinitionAsync(implementation, solution, cancellationToken).ConfigureAwait(false);
var bestDef = sourceDef.Symbol != null ? sourceDef : implementation;
if (IsAccessible(bestDef))
{
results = results ?? ImmutableArray.CreateBuilder<SymbolAndProjectId>();
......
......@@ -6,9 +6,11 @@
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Roslyn.Utilities;
......@@ -91,10 +93,10 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol)
/// interfaceMember, or this type doesn't supply a member that successfully implements
/// interfaceMember).
/// </summary>
public static IEnumerable<SymbolAndProjectId> FindImplementationsForInterfaceMember(
public static async Task<ImmutableArray<SymbolAndProjectId>> FindImplementationsForInterfaceMemberAsync(
this SymbolAndProjectId<ITypeSymbol> typeSymbolAndProjectId,
ISymbol interfaceMember,
Workspace workspace,
Solution solution,
CancellationToken cancellationToken)
{
// This method can return multiple results. Consider the case of:
......@@ -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
// results in C.
var arrBuilder = ArrayBuilder<SymbolAndProjectId>.GetInstance();
// TODO(cyrusn): Implement this using the actual code for
// TypeSymbol.FindImplementationForInterfaceMember
var typeSymbol = typeSymbolAndProjectId.Symbol;
if (typeSymbol == null || interfaceMember == null)
{
yield break;
return arrBuilder.ToImmutableAndFree();
}
if (interfaceMember.Kind != SymbolKind.Event &&
interfaceMember.Kind != SymbolKind.Method &&
interfaceMember.Kind != SymbolKind.Property)
{
yield break;
return arrBuilder.ToImmutableAndFree();
}
// WorkItem(4843)
......@@ -143,7 +147,7 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol)
var interfaceType = interfaceMember.ContainingType;
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>.
......@@ -153,14 +157,31 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol)
// instantiations of that method.
var originalInterfaceType = interfaceMember.ContainingType.OriginalDefinition;
var originalInterfaceMember = interfaceMember.OriginalDefinition;
var constructedInterfaces = typeSymbol.AllInterfaces.Where(i =>
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)
{
cancellationToken.ThrowIfCancellationRequested();
var constructedInterfaceMember = constructedInterface.GetMembers().FirstOrDefault(m =>
SymbolEquivalenceComparer.Instance.Equals(m.OriginalDefinition, originalInterfaceMember));
SymbolFinder.OriginalSymbolsMatch(
m,
interfaceMember,
solution,
typeSymbolCompilation,
symbolToMatchCompilation: null,
cancellationToken));
if (constructedInterfaceMember == null)
{
......@@ -177,16 +198,18 @@ public static ITypeSymbol RemoveNullableIfPresent(this ITypeSymbol symbol)
if (seenTypeDeclaringInterface)
{
var result = FindImplementations(workspace, constructedInterfaceMember, currentType);
var result = FindImplementations(solution.Workspace, constructedInterfaceMember, currentType);
if (result != null)
{
yield return typeSymbolAndProjectId.WithSymbol(result);
arrBuilder.Add(typeSymbolAndProjectId.WithSymbol(result));
break;
}
}
}
}
return arrBuilder.ToImmutableAndFree();
}
private static ISymbol FindImplementations(Workspace workspace, ISymbol constructedInterfaceMember, ITypeSymbol currentType)
......
......@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -268,6 +269,47 @@ class B : C, A
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")]
[Fact]
public async Task OverriddenMethodsFromPortableToDesktop()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册