| File: FindSymbols\FindReferences\MetadataUnifyingEquivalenceComparer.cs | Web Access |
| Project: src\roslyn\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.Shared.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols; internal sealed class MetadataUnifyingEquivalenceComparer : IEqualityComparer<ISymbol> { public static readonly IEqualityComparer<ISymbol> Instance = new MetadataUnifyingEquivalenceComparer(); private MetadataUnifyingEquivalenceComparer() { } public bool Equals(ISymbol? x, ISymbol? y) { // If either symbol is from source, then we must do stricter equality. Consider this: // // S1 <-> M <-> S2 (where S# = source symbol, M = some metadata symbol) // // In this case, imagine that both the comparisons denoted by <-> were done with the // SymbolEquivalenceComparer, and returned true. If S1 and S2 were from different projects, // they would compare false but transitivity would say they must be true. Another way to think // of this is any use of a source symbol "poisons" the comparison and requires it to be stricter. if (x == null || y == null || IsInSource(x) || IsInSource(y)) { return object.Equals(x, y); } // Both of the symbols are from metadata, so defer to the equivalence comparer return SymbolEquivalenceComparer.Instance.Equals(x, y); } public int GetHashCode(ISymbol obj) { if (IsInSource(obj)) { return obj.GetHashCode(); } else { return SymbolEquivalenceComparer.Instance.GetHashCode(obj); } } private static bool IsInSource(ISymbol symbol) => symbol.Locations.Any(static l => l.IsInSource); }