Skip to content

Compare symbols by metadata name when searching for eqivalent symbols in FAR engine #78656

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions src/EditorFeatures/CSharpTest/CodeLens/CSharpCodeLensTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -402,4 +402,54 @@ internal partial class Program
""";
await RunMethodReferenceTest(input);
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/64592")]
public async Task TestFileScopedTypes()
{
const string input = """
<Workspace>
<Project Language="C#" CommonReferences="true" AssemblyName="Proj1">
<Document FilePath="File1.cs"><![CDATA[
namespace TestNamespace
{
{|1:file class C|}
{
public C ()
{
}

void M()
{
var t1 = new T();
var t2 = new T();
}
}

{|2:file class T|}
{
}
}]]>
</Document>
<Document FilePath="File2.cs"><![CDATA[
namespace TestNamespace
{
{|0:file class C|}
{
void M()
{
var t1 = new T();
var t2 = new T();
}
}

{|2:file class T|}
{
}
}]]>
</Document>
</Project>
</Workspace>
""";
await RunReferenceTest(input);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@ internal static bool OriginalSymbolsMatch(
if (searchSymbol == null || symbolToMatch == null)
return false;

// Avoid the expensive checks if we can fast path when the compiler just says these are equal. Also, for the
// purposes of symbol finding nullability of symbols doesn't affect things, so just use the default
// comparison.
if (searchSymbol.Equals(symbolToMatch))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to the core fix, but when I traced down the problem I noticed that OriginalSymbolsMatchCore method, which is invoked right below this check, has exactly the same condition in it, so there is clearly duplication of efforts going on here)

return true;

if (OriginalSymbolsMatchCore(solution, searchSymbol, symbolToMatch))
return true;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Shared.Utilities;

Expand Down Expand Up @@ -153,15 +152,15 @@ private bool AssembliesAreEquivalent(IAssemblySymbol x, IAssemblySymbol y)
private bool FieldsAreEquivalent(IFieldSymbol x, IFieldSymbol y, Dictionary<INamedTypeSymbol, INamedTypeSymbol>? equivalentTypesWithDifferingAssemblies)
{
return
x.Name == y.Name &&
x.MetadataName == y.MetadataName &&
AreEquivalent(x.CustomModifiers, y.CustomModifiers, equivalentTypesWithDifferingAssemblies) &&
AreEquivalent(x.ContainingSymbol, y.ContainingSymbol, equivalentTypesWithDifferingAssemblies);
}

private static bool LabelsAreEquivalent(ILabelSymbol x, ILabelSymbol y)
{
return
x.Name == y.Name &&
x.MetadataName == y.MetadataName &&
HaveSameLocation(x, y);
}

Expand Down Expand Up @@ -208,7 +207,7 @@ private bool MethodsAreEquivalent(IMethodSymbol x, IMethodSymbol y, Dictionary<I
IsConstructedFromSelf(x) != IsConstructedFromSelf(y) ||
x.Arity != y.Arity ||
x.Parameters.Length != y.Parameters.Length ||
x.Name != y.Name)
x.MetadataName != y.MetadataName)
{
return false;
}
Expand Down Expand Up @@ -277,7 +276,7 @@ private static bool HaveSameLocation(ISymbol x, ISymbol y)
}

private bool ModulesAreEquivalent(IModuleSymbol x, IModuleSymbol y)
=> AssembliesAreEquivalent(x.ContainingAssembly, y.ContainingAssembly) && x.Name == y.Name;
=> AssembliesAreEquivalent(x.ContainingAssembly, y.ContainingAssembly) && x.MetadataName == y.MetadataName;

private bool NamedTypesAreEquivalent(INamedTypeSymbol x, INamedTypeSymbol y, Dictionary<INamedTypeSymbol, INamedTypeSymbol>? equivalentTypesWithDifferingAssemblies)
{
Expand Down Expand Up @@ -357,8 +356,7 @@ private bool HandleNamedTypesWorker(INamedTypeSymbol x, INamedTypeSymbol y, Dict
return true;

if (IsConstructedFromSelf(x) != IsConstructedFromSelf(y) ||
x.Arity != y.Arity ||
x.Name != y.Name ||
x.MetadataName != y.MetadataName ||
x.IsAnonymousType != y.IsAnonymousType ||
x.IsUnboundGenericType != y.IsUnboundGenericType ||
!NullableAnnotationsEquivalent(x, y))
Expand All @@ -375,12 +373,12 @@ x.ContainingSymbol is INamespaceSymbol xNamespace &&
// For error types, we just ensure that the containing namespaces are equivalent up to the root.
while (true)
{
if (xNamespace.Name != yNamespace.Name)
if (xNamespace.MetadataName != yNamespace.MetadataName)
return false;

// Error namespaces don't set the IsGlobalNamespace bit unfortunately. So we just do the
// nominal check to see if we've actually hit the root.
if (xNamespace.Name == "")
if (xNamespace.MetadataName == "")
break;

xNamespace = xNamespace.ContainingNamespace;
Expand All @@ -398,7 +396,7 @@ x.ContainingSymbol is INamespaceSymbol xNamespace &&
if (equivalentTypesWithDifferingAssemblies != null &&
x.ContainingType == null &&
x.ContainingAssembly != null &&
!AssemblyIdentityComparer.SimpleNameComparer.Equals(x.ContainingAssembly.Name, y.ContainingAssembly.Name) &&
!AssemblyIdentityComparer.SimpleNameComparer.Equals(x.ContainingAssembly.MetadataName, y.ContainingAssembly.MetadataName) &&
!equivalentTypesWithDifferingAssemblies.ContainsKey(x))
{
equivalentTypesWithDifferingAssemblies.Add(x, y);
Expand Down Expand Up @@ -434,7 +432,7 @@ private bool HandleTupleTypes(INamedTypeSymbol x, INamedTypeSymbol y, Dictionary
{
var xElement = xElements[i];
var yElement = yElements[i];
if (xElement.Name != yElement.Name)
if (xElement.MetadataName != yElement.MetadataName)
return false;
}
}
Expand Down Expand Up @@ -534,7 +532,7 @@ private bool HandleAnonymousTypes(INamedTypeSymbol x, INamedTypeSymbol y, Dictio
var p1 = xMembersEnumerator.Current;
var p2 = yMembersEnumerator.Current;

if (p1.Name != p2.Name ||
if (p1.MetadataName != p2.MetadataName ||
p1.IsReadOnly != p2.IsReadOnly ||
!AreEquivalent(p1.Type, p2.Type, equivalentTypesWithDifferingAssemblies))
{
Expand All @@ -549,7 +547,7 @@ private bool HandleAnonymousTypes(INamedTypeSymbol x, INamedTypeSymbol y, Dictio
private bool NamespacesAreEquivalent(INamespaceSymbol x, INamespaceSymbol y, Dictionary<INamedTypeSymbol, INamedTypeSymbol>? equivalentTypesWithDifferingAssemblies)
{
if (x.IsGlobalNamespace != y.IsGlobalNamespace ||
x.Name != y.Name)
x.MetadataName != y.MetadataName)
{
return false;
}
Expand All @@ -567,7 +565,7 @@ private bool ParametersAreEquivalent(IParameterSymbol x, IParameterSymbol y, Dic
{
return
x.IsRefOrOut() == y.IsRefOrOut() &&
x.Name == y.Name &&
x.MetadataName == y.MetadataName &&
AreEquivalent(x.CustomModifiers, y.CustomModifiers, equivalentTypesWithDifferingAssemblies) &&
AreEquivalent(x.Type, y.Type, equivalentTypesWithDifferingAssemblies) &&
AreEquivalent(x.ContainingSymbol, y.ContainingSymbol, equivalentTypesWithDifferingAssemblies);
Expand Down Expand Up @@ -610,7 +608,7 @@ private bool PropertiesAreEquivalent(IPropertySymbol x, IPropertySymbol y, Dicti
private bool EventsAreEquivalent(IEventSymbol x, IEventSymbol y, Dictionary<INamedTypeSymbol, INamedTypeSymbol>? equivalentTypesWithDifferingAssemblies)
{
return
x.Name == y.Name &&
x.MetadataName == y.MetadataName &&
IsPartialEventDefinitionPart(x) == IsPartialEventDefinitionPart(y) &&
IsPartialEventImplementationPart(x) == IsPartialEventImplementationPart(y) &&
AreEquivalent(x.ContainingSymbol, y.ContainingSymbol, equivalentTypesWithDifferingAssemblies);
Expand Down Expand Up @@ -660,6 +658,6 @@ private static bool RangeVariablesAreEquivalent(IRangeVariableSymbol x, IRangeVa
=> HaveSameLocation(x, y);

private static bool PreprocessingSymbolsAreEquivalent(IPreprocessingSymbol x, IPreprocessingSymbol y)
=> x.Name == y.Name;
=> x.MetadataName == y.MetadataName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities;
/// equivalent.
/// <list type="number">
/// <item>The kinds of the two symbols must match.</item>
/// <item>The names of the two symbols must match.</item>
/// <item>The metadata names of the two symbols must match.</item>
/// <item>The arity of the two symbols must match.</item>
/// <item>If the symbols are methods or parameterized properties, then the signatures of the two
/// symbols must match.</item>
Expand Down
Loading