From a014a1900a189b9cfad0cee2adc28305861fb61d Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Tue, 31 May 2016 18:00:17 -0700 Subject: [PATCH] Switch to a struct with a cached hashcode. --- .../CSharpTest/SymbolId/SymbolKeyTestBase.cs | 2 +- .../Test2/NavigationBar/TestHelpers.vb | 2 +- .../SymbolId/SymbolKeyTestBase.vb | 2 +- ...HelpProvider.SymbolKeySignatureHelpItem.cs | 14 ++++---- .../AbstractSignatureHelpProvider.cs | 5 ++- .../Progression/GraphBuilder.cs | 6 ++-- .../Progression/GraphNavigatorExtension.cs | 6 ++-- .../Progression/GraphProvider.cs | 2 +- .../Progression/RoslynGraphProperties.cs | 2 +- .../Symbols/CodeGenerationSymbol.cs | 5 --- .../FindReferences/DependentProjectsFinder.cs | 4 +-- .../SymbolId/SymbolKey.AliasSymbolKey.cs | 4 +-- .../SymbolId/SymbolKey.ArrayTypeSymbolKey.cs | 4 +-- .../SymbolId/SymbolKey.AssemblySymbolKey.cs | 11 +++--- .../SymbolId/SymbolKey.BodyLevelSymbolKey.cs | 4 +-- .../SymbolId/SymbolKey.ComparisonOptions.cs | 2 +- .../SymbolKey.DynamicTypeSymbolKey.cs | 4 +-- .../SymbolId/SymbolKey.ErrorTypeSymbolKey.cs | 4 +-- .../SymbolId/SymbolKey.EventSymbolKey.cs | 4 +-- .../SymbolId/SymbolKey.FieldSymbolKey.cs | 4 +-- .../SymbolId/SymbolKey.MethodSymbolKey.cs | 12 +++---- .../SymbolId/SymbolKey.ModuleSymbolKey.cs | 4 +-- .../SymbolId/SymbolKey.NamedTypeSymbolKey.cs | 4 +-- .../SymbolId/SymbolKey.NamespaceSymbolKey.cs | 4 +-- .../SymbolId/SymbolKey.ParameterSymbolKey.cs | 4 +-- .../SymbolKey.PointerTypeSymbolKey.cs | 4 +-- .../SymbolId/SymbolKey.PropertySymbolKey.cs | 4 +-- .../SymbolId/SymbolKey.SymbolKeyComparer.cs | 19 ++--------- .../SymbolId/SymbolKey.SymbolKeyReader.cs | 30 +++++----------- ...isitor.cs => SymbolKey.SymbolKeyWriter.cs} | 16 ++++----- .../SymbolId/SymbolKey.TupleTypeSymbolKey.cs | 4 +-- ...SymbolKey.TypeParameterOrdinalSymbolKey.cs | 4 +-- .../SymbolKey.TypeParameterSymbolKey.cs | 4 +-- .../Core/Portable/SymbolId/SymbolKey.cs | 34 +++++++++---------- .../Core/Portable/Workspaces.csproj | 2 +- 35 files changed, 103 insertions(+), 137 deletions(-) rename src/Workspaces/Core/Portable/SymbolId/{SymbolKey.Visitor.cs => SymbolKey.SymbolKeyWriter.cs} (96%) diff --git a/src/EditorFeatures/CSharpTest/SymbolId/SymbolKeyTestBase.cs b/src/EditorFeatures/CSharpTest/SymbolId/SymbolKeyTestBase.cs index 88d2a0c43a1..f1e624f1823 100644 --- a/src/EditorFeatures/CSharpTest/SymbolId/SymbolKeyTestBase.cs +++ b/src/EditorFeatures/CSharpTest/SymbolId/SymbolKeyTestBase.cs @@ -80,7 +80,7 @@ internal static ISymbol ResolveSymbol(ISymbol originalSymbol, Compilation target // Verify that serialization works. var serialized = sid.ToString(); - var deserialized = SymbolKey.FromString(serialized); + var deserialized = new SymbolKey(serialized); var comparer = SymbolKey.GetComparer(ignoreCase: false, ignoreAssemblyKeys: false); Assert.True(comparer.Equals(sid, deserialized)); diff --git a/src/EditorFeatures/Test2/NavigationBar/TestHelpers.vb b/src/EditorFeatures/Test2/NavigationBar/TestHelpers.vb index fba1aaa0980..5da9d60977c 100644 --- a/src/EditorFeatures/Test2/NavigationBar/TestHelpers.vb +++ b/src/EditorFeatures/Test2/NavigationBar/TestHelpers.vb @@ -154,7 +154,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.NavigationBar Assert.Equal(expectedItem.Grayed, actualItem.Grayed) If expectedItem.HasNavigationSymbolId Then - Assert.True(DirectCast(actualItem, NavigationBarSymbolItem).NavigationSymbolId IsNot Nothing) + ' Assert.True(DirectCast(actualItem, NavigationBarSymbolItem).NavigationSymbolId IsNot Nothing) Assert.Equal(expectedItem.HasNavigationSymbolId, DirectCast(actualItem, NavigationBarSymbolItem).NavigationSymbolIndex.HasValue) Else Assert.True(TypeOf actualItem IsNot NavigationBarSymbolItem) diff --git a/src/EditorFeatures/VisualBasicTest/SymbolId/SymbolKeyTestBase.vb b/src/EditorFeatures/VisualBasicTest/SymbolId/SymbolKeyTestBase.vb index fd27796dbaa..1fc05eaa7fb 100644 --- a/src/EditorFeatures/VisualBasicTest/SymbolId/SymbolKeyTestBase.vb +++ b/src/EditorFeatures/VisualBasicTest/SymbolId/SymbolKeyTestBase.vb @@ -73,7 +73,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.SymbolId ' Verify that serialization works. Dim serialized = sid.ToString() - Dim deserialized = SymbolKey.FromString(serialized) + Dim deserialized = New SymbolKey(serialized) Dim comparer = SymbolKey.GetComparer(ignoreCase:=False, ignoreAssemblyKeys:=False) Assert.True(comparer.Equals(sid, deserialized)) diff --git a/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem.cs b/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem.cs index d3d58594c58..bff1b37b529 100644 --- a/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem.cs +++ b/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem.cs @@ -10,7 +10,7 @@ internal abstract partial class AbstractSignatureHelpProvider { internal class SymbolKeySignatureHelpItem : SignatureHelpItem, IEquatable { - public SymbolKey SymbolKey { get; } + public SymbolKey? SymbolKey { get; } public SymbolKeySignatureHelpItem( ISymbol symbol, @@ -22,7 +22,7 @@ internal class SymbolKeySignatureHelpItem : SignatureHelpItem, IEquatable parameters, IEnumerable descriptionParts) : base(isVariadic, documentationFactory, prefixParts, separatorParts, suffixParts, parameters, descriptionParts) { - this.SymbolKey = symbol == null ? null : symbol.GetSymbolKey(); + this.SymbolKey = symbol?.GetSymbolKey(); } public override bool Equals(object obj) @@ -33,9 +33,9 @@ public override bool Equals(object obj) public bool Equals(SymbolKeySignatureHelpItem obj) { return ReferenceEquals(this, obj) || - (obj != null && - this.SymbolKey != null && - SymbolKey.GetComparer(ignoreCase: false, ignoreAssemblyKeys: false).Equals(this.SymbolKey, obj.SymbolKey)); + (obj?.SymbolKey != null && + this.SymbolKey != null && + CodeAnalysis.SymbolKey.GetComparer(ignoreCase: false, ignoreAssemblyKeys: false).Equals(this.SymbolKey.Value, obj.SymbolKey.Value)); } public override int GetHashCode() @@ -45,8 +45,8 @@ public override int GetHashCode() return 0; } - var comparer = SymbolKey.GetComparer(ignoreCase: false, ignoreAssemblyKeys: false); - return comparer.GetHashCode(this.SymbolKey); + var comparer = CodeAnalysis.SymbolKey.GetComparer(ignoreCase: false, ignoreAssemblyKeys: false); + return comparer.GetHashCode(this.SymbolKey.Value); } } } diff --git a/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs b/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs index 2cbd3209024..e2ac6e9932b 100644 --- a/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs +++ b/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs @@ -192,8 +192,7 @@ where part.Symbol.IsNormalAnonymousType() continue; } - var expectedSymbol = symbolKey.Resolve(compilation, ignoreAssemblyKey: true, cancellationToken: cancellationToken).Symbol; - + var expectedSymbol = symbolKey.Value.Resolve(compilation, ignoreAssemblyKey: true, cancellationToken: cancellationToken).Symbol; if (expectedSymbol == null) { finalItems.Add(item); @@ -231,7 +230,7 @@ where part.Symbol.IsNormalAnonymousType() if (!related.Item1.GetLanguageService().IsInInactiveRegion(syntaxTree, position, cancellationToken)) { var relatedSemanticModel = await related.Item1.GetSemanticModelForSpanAsync(new TextSpan(position, 0), cancellationToken).ConfigureAwait(false); - var symbolSet = related.Item2.Select(s => ((SymbolKeySignatureHelpItem)s).SymbolKey.Resolve(relatedSemanticModel.Compilation, cancellationToken: cancellationToken).Symbol) + var symbolSet = related.Item2.Select(s => ((SymbolKeySignatureHelpItem)s).SymbolKey?.Resolve(relatedSemanticModel.Compilation, cancellationToken: cancellationToken).Symbol) .WhereNotNull() .ToSet(SymbolEquivalenceComparer.IgnoreAssembliesInstance); resultSets.Add(Tuple.Create(related.Item1.Project.Id, symbolSet)); diff --git a/src/VisualStudio/Core/Def/Implementation/Progression/GraphBuilder.cs b/src/VisualStudio/Core/Def/Implementation/Progression/GraphBuilder.cs index 83325727a29..9617a24ed90 100644 --- a/src/VisualStudio/Core/Def/Implementation/Progression/GraphBuilder.cs +++ b/src/VisualStudio/Core/Def/Implementation/Progression/GraphBuilder.cs @@ -115,8 +115,8 @@ private async Task PopulateMapsForSymbolInputNodeAsync(GraphNode inputNode) _nodeToContextProjectMap.Add(inputNode, project); var compilation = await project.GetCompilationAsync(_cancellationToken).ConfigureAwait(false); - var symbolId = inputNode[RoslynGraphProperties.SymbolId] as SymbolKey; - var symbol = symbolId.Resolve(compilation).Symbol; + var symbolId = (SymbolKey?)inputNode[RoslynGraphProperties.SymbolId]; + var symbol = symbolId.Value.Resolve(compilation).Symbol; if (symbol != null) { _nodeToSymbolMap.Add(inputNode, symbol); @@ -205,7 +205,7 @@ public async Task AddNodeForSymbolAsync(ISymbol symbol, Project conte { GraphNode node = await GetOrCreateNodeAsync(_graph, symbol, _solution, _cancellationToken).ConfigureAwait(false); - node[RoslynGraphProperties.SymbolId] = symbol.GetSymbolKey(); + node[RoslynGraphProperties.SymbolId] = (SymbolKey?)symbol.GetSymbolKey(); node[RoslynGraphProperties.ContextProjectId] = GetContextProjectId(contextProject, symbol); node[RoslynGraphProperties.ExplicitInterfaceImplementations] = symbol.ExplicitInterfaceImplementations().Select(s => s.GetSymbolKey()).ToList(); node[RoslynGraphProperties.DeclaredAccessibility] = symbol.DeclaredAccessibility; diff --git a/src/VisualStudio/Core/Def/Implementation/Progression/GraphNavigatorExtension.cs b/src/VisualStudio/Core/Def/Implementation/Progression/GraphNavigatorExtension.cs index 286c5f1eb0b..5c4b546567d 100644 --- a/src/VisualStudio/Core/Def/Implementation/Progression/GraphNavigatorExtension.cs +++ b/src/VisualStudio/Core/Def/Implementation/Progression/GraphNavigatorExtension.cs @@ -37,7 +37,7 @@ public void NavigateTo(GraphObject graphObject) } var projectId = graphNode.GetValue(RoslynGraphProperties.ContextProjectId); - var symbolId = graphNode.GetValue(RoslynGraphProperties.SymbolId); + var symbolId = graphNode.GetValue(RoslynGraphProperties.SymbolId); if (projectId != null) { @@ -81,7 +81,7 @@ public void NavigateTo(GraphObject graphObject) } } - private void NavigateOnForegroundThread(SourceLocation sourceLocation, SymbolKey symbolId, Project project, Document document) + private void NavigateOnForegroundThread(SourceLocation sourceLocation, SymbolKey? symbolId, Project project, Document document) { AssertIsForeground(); @@ -89,7 +89,7 @@ private void NavigateOnForegroundThread(SourceLocation sourceLocation, SymbolKey if (symbolId != null) { var symbolNavigationService = _workspace.Services.GetService(); - var symbol = symbolId.Resolve(project.GetCompilationAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None)).Symbol; + var symbol = symbolId.Value.Resolve(project.GetCompilationAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None)).Symbol; // Do not allow third party navigation to types or constructors if (symbol != null && diff --git a/src/VisualStudio/Core/Def/Implementation/Progression/GraphProvider.cs b/src/VisualStudio/Core/Def/Implementation/Progression/GraphProvider.cs index e263d155bcd..6d6b50c9637 100644 --- a/src/VisualStudio/Core/Def/Implementation/Progression/GraphProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/Progression/GraphProvider.cs @@ -350,7 +350,7 @@ private bool IsAnyTypeKind(GraphNode node, params TypeKind[] typeKinds) // TODO: The check here is to see if the SymbolId property exists on the node // and if so, that's been created by us. However, eventually we'll want to extend // this to other scenarios where C#\VB nodes that aren't created by us are passed in. - if (graphNode.GetValue(RoslynGraphProperties.SymbolId) == null) + if (graphNode.GetValue(RoslynGraphProperties.SymbolId) == null) { return null; } diff --git a/src/VisualStudio/Core/Def/Implementation/Progression/RoslynGraphProperties.cs b/src/VisualStudio/Core/Def/Implementation/Progression/RoslynGraphProperties.cs index d241cc49a4c..c9d4b30f346 100644 --- a/src/VisualStudio/Core/Def/Implementation/Progression/RoslynGraphProperties.cs +++ b/src/VisualStudio/Core/Def/Implementation/Progression/RoslynGraphProperties.cs @@ -99,7 +99,7 @@ static RoslynGraphProperties() SymbolId = Schema.Properties.AddNewProperty( id: "SymbolId", - dataType: typeof(SymbolKey), + dataType: typeof(SymbolKey?), callback: () => new GraphMetadata(options: GraphMetadataOptions.Sharable | GraphMetadataOptions.Removable)); ContextProjectId = Schema.Properties.AddNewProperty( diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationSymbol.cs index bc59c52b584..d623bb3552b 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationSymbol.cs @@ -273,11 +273,6 @@ public ImmutableArray ToMinimalDisplayParts(SemanticModel sem throw new NotImplementedException(); } - public SymbolKey GetSymbolId() - { - return null; - } - public virtual string MetadataName { get diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentProjectsFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentProjectsFinder.cs index 9085b19d988..bdf083a4cb4 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentProjectsFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentProjectsFinder.cs @@ -306,7 +306,7 @@ private static async Task AddNonSubmissionDependentProjectsAsync(IAssemblySymbol var internalsVisibleToMap = CreateInternalsVisibleToMap(sourceAssembly); - SymbolKey sourceAssemblySymbolKey = null; + SymbolKey? sourceAssemblySymbolKey = null; // TODO(cyrusn): What about error tolerance situations. Do we maybe want to search // transitive dependencies as well? Even if the code wouldn't compile, they may be @@ -328,7 +328,7 @@ private static async Task AddNonSubmissionDependentProjectsAsync(IAssemblySymbol if (sourceAssembly.Language != targetAssembly.Language) { sourceAssemblySymbolKey = sourceAssemblySymbolKey ?? sourceAssembly.GetSymbolKey(); - var sourceAssemblyInTargetCompilation = sourceAssemblySymbolKey.Resolve(compilation, cancellationToken: cancellationToken).Symbol as IAssemblySymbol; + var sourceAssemblyInTargetCompilation = sourceAssemblySymbolKey.Value.Resolve(compilation, cancellationToken: cancellationToken).Symbol as IAssemblySymbol; if (sourceAssemblyInTargetCompilation != null) { diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.AliasSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.AliasSymbolKey.cs index 7a005651e22..6c9eb5b492a 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.AliasSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.AliasSymbolKey.cs @@ -5,11 +5,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class AliasSymbolKey { - public static void Create(IAliasSymbol symbol, Visitor visitor) + public static void Create(IAliasSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteString(symbol.Name); visitor.WriteSymbolKey(symbol.Target); diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ArrayTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ArrayTypeSymbolKey.cs index b146bb0ed9a..c85b757cfc7 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ArrayTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ArrayTypeSymbolKey.cs @@ -5,11 +5,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class ArrayTypeSymbolKey { - public static void Create(IArrayTypeSymbol symbol, Visitor visitor) + public static void Create(IArrayTypeSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteSymbolKey(symbol.ElementType); visitor.WriteInteger(symbol.Rank); diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.AssemblySymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.AssemblySymbolKey.cs index 2306041f84e..5c3b0d9a98d 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.AssemblySymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.AssemblySymbolKey.cs @@ -5,11 +5,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class AssemblySymbolKey { - public static void Create(IAssemblySymbol symbol, Visitor visitor) + public static void Create(IAssemblySymbol symbol, SymbolKeyWriter visitor) { // If the format of this ever changed, then it's necessary to fixup the // SymbolKeyComparer.RemoveAssemblyKeys function. @@ -19,9 +19,10 @@ public static void Create(IAssemblySymbol symbol, Visitor visitor) public static int GetHashCode(GetHashCodeReader reader) { var value = reader.ReadString(); - // isCaseSensitive doesn't apply here as AssemblyIdentity is always case - // insensitive. - return reader.Options.IgnoreAssemblyKey ? 1 : value; + + // Hash all assembly keys to the same bucket. That way we're a uniform + // hash regardless if clients care about assembly IDs or not. + return 1; } public static SymbolKeyResolution Resolve(SymbolKeyReader reader) diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.BodyLevelSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.BodyLevelSymbolKey.cs index 1cf80b9a059..3774b98d85f 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.BodyLevelSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.BodyLevelSymbolKey.cs @@ -7,11 +7,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class BodyLevelSymbolKey { - public static void Create(ISymbol symbol, Visitor visitor) + public static void Create(ISymbol symbol, SymbolKeyWriter visitor) { var containingSymbol = symbol.ContainingSymbol; diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ComparisonOptions.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ComparisonOptions.cs index 0d7bca8466d..9300b045688 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ComparisonOptions.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ComparisonOptions.cs @@ -4,7 +4,7 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private struct ComparisonOptions { diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.DynamicTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.DynamicTypeSymbolKey.cs index 6e40f8f11b1..6af728056d2 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.DynamicTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.DynamicTypeSymbolKey.cs @@ -2,13 +2,13 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class DynamicTypeSymbolKey { private static readonly object instance = new object(); - public static void Create(Visitor visitor) + public static void Create(SymbolKeyWriter visitor) { } diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ErrorTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ErrorTypeSymbolKey.cs index 2be9ea7653b..c0ae518af6e 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ErrorTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ErrorTypeSymbolKey.cs @@ -7,11 +7,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class ErrorTypeSymbolKey { - public static void Create(INamedTypeSymbol symbol, Visitor visitor) + public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteString(symbol.Name); visitor.WriteSymbolKey(symbol.ContainingSymbol as INamespaceOrTypeSymbol); diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.EventSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.EventSymbolKey.cs index 21fd0d80cd7..234ddef62d8 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.EventSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.EventSymbolKey.cs @@ -5,11 +5,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class EventSymbolKey { - public static void Create(IEventSymbol symbol, Visitor visitor) + public static void Create(IEventSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteString(symbol.MetadataName); visitor.WriteSymbolKey(symbol.ContainingType); diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.FieldSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.FieldSymbolKey.cs index 8369ba60425..4b270bb41e1 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.FieldSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.FieldSymbolKey.cs @@ -5,11 +5,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class FieldSymbolKey { - public static void Create(IFieldSymbol symbol, Visitor visitor) + public static void Create(IFieldSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteString(symbol.MetadataName); visitor.WriteSymbolKey(symbol.ContainingType); diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.MethodSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.MethodSymbolKey.cs index 5bcc8e48034..31149ae6f72 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.MethodSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.MethodSymbolKey.cs @@ -8,11 +8,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class ReducedExtensionMethodSymbolKey { - public static void Create(IMethodSymbol symbol, Visitor visitor) + public static void Create(IMethodSymbol symbol, SymbolKeyWriter visitor) { Debug.Assert(symbol.Equals(symbol.ConstructedFrom)); @@ -41,11 +41,11 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) } } - internal partial class SymbolKey + internal partial struct SymbolKey { private static class ConstructedMethodSymbolKey { - public static void Create(IMethodSymbol symbol, Visitor visitor) + public static void Create(IMethodSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteSymbolKey(symbol.ConstructedFrom); visitor.WriteSymbolKeyArray(symbol.TypeArguments); @@ -81,11 +81,11 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) } } - internal partial class SymbolKey + internal partial struct SymbolKey { private static class MethodSymbolKey { - public static void Create(IMethodSymbol symbol, Visitor visitor) + public static void Create(IMethodSymbol symbol, SymbolKeyWriter visitor) { Debug.Assert(symbol.Equals(symbol.ConstructedFrom)); diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ModuleSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ModuleSymbolKey.cs index 3ec61e5aa2b..27e650e61ef 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ModuleSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ModuleSymbolKey.cs @@ -5,11 +5,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class ModuleSymbolKey { - public static void Create(IModuleSymbol symbol, Visitor visitor) + public static void Create(IModuleSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteSymbolKey(symbol.ContainingSymbol); } diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.NamedTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.NamedTypeSymbolKey.cs index 5184d83078e..d09eadaa918 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.NamedTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.NamedTypeSymbolKey.cs @@ -7,11 +7,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class NamedTypeSymbolKey { - public static void Create(INamedTypeSymbol symbol, Visitor visitor) + public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteString(symbol.MetadataName); visitor.WriteSymbolKey(symbol.ContainingSymbol); diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.NamespaceSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.NamespaceSymbolKey.cs index e61d9b08b1e..ad334ba273f 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.NamespaceSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.NamespaceSymbolKey.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class NamespaceSymbolKey { @@ -22,7 +22,7 @@ private static class NamespaceSymbolKey // 4) The SymbolId for the containing namespace symbol if this is not a global // namespace. - public static void Create(INamespaceSymbol symbol, Visitor visitor) + public static void Create(INamespaceSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteString(symbol.MetadataName); diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ParameterSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ParameterSymbolKey.cs index 28043ba3043..dc5cdf9d3e3 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ParameterSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.ParameterSymbolKey.cs @@ -6,11 +6,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class ParameterSymbolKey { - public static void Create(IParameterSymbol symbol, Visitor visitor) + public static void Create(IParameterSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteString(symbol.MetadataName); visitor.WriteSymbolKey(symbol.ContainingSymbol); diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.PointerTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.PointerTypeSymbolKey.cs index 07e7ee8f3c2..b39eefaf4f8 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.PointerTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.PointerTypeSymbolKey.cs @@ -5,11 +5,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class PointerTypeSymbolKey { - public static void Create(IPointerTypeSymbol symbol, Visitor visitor) + public static void Create(IPointerTypeSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteSymbolKey(symbol.PointedAtType); } diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.PropertySymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.PropertySymbolKey.cs index 30879e1aae0..d4a2dc10911 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.PropertySymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.PropertySymbolKey.cs @@ -5,11 +5,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class PropertySymbolKey { - public static void Create(IPropertySymbol symbol, Visitor visitor) + public static void Create(IPropertySymbol symbol, SymbolKeyWriter visitor) { visitor.WriteString(symbol.MetadataName); visitor.WriteSymbolKey(symbol.ContainingSymbol); diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.SymbolKeyComparer.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.SymbolKeyComparer.cs index 78cdbd0ec86..3db4f3d853f 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.SymbolKeyComparer.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.SymbolKeyComparer.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private class SymbolKeyComparer : IEqualityComparer { @@ -21,16 +21,6 @@ private SymbolKeyComparer(ComparisonOptions options) public bool Equals(SymbolKey x, SymbolKey y) { - if (x == y) - { - return true; - } - - if (x == null || y == null) - { - return false; - } - var comparer = _options.IgnoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal; @@ -60,12 +50,7 @@ private string RemoveAssemblyKeys(string data) public int GetHashCode(SymbolKey obj) { - if (obj == null) - { - return 0; - } - - return SymbolKey.GetHashCode(obj, _options); + return obj.GetHashCode(); } public static IEqualityComparer GetComparer(bool ignoreCase, bool ignoreAssemblyKey) diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.SymbolKeyReader.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.SymbolKeyReader.cs index 38920af0c77..65cfe7d573f 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.SymbolKeyReader.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.SymbolKeyReader.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private abstract class Reader : IDisposable { @@ -274,51 +274,39 @@ private class GetHashCodeReader : Reader private static readonly ObjectPool s_pool = new ObjectPool(() => new GetHashCodeReader()); - public ComparisonOptions Options { get; private set; } - private GetHashCodeReader() { } - public static GetHashCodeReader GetReader(string data, ComparisonOptions options) + public static GetHashCodeReader GetReader(string data) { var reader = s_pool.Allocate(); - reader.Initialize(data, options); + reader.Initialize(data); return reader; } public override void Dispose() { base.Dispose(); - Options = default(ComparisonOptions); s_pool.Free(this); } - private void Initialize(string data, ComparisonOptions options) + private void Initialize(string data) { base.Initialize(data, CancellationToken.None); - Options = options; } protected override int CreateResultForString(int start, int end, bool hasEmbeddedQuote) { var result = 1; - if (Options.IgnoreCase) - { - for (var i = start; i < end; i++) - { - result = Hash.Combine((int)char.ToLower(Data[i]), result); - } - } - else + + // Note: we hash all strings to lowercase. It will mean more collisions, but + // it provides a uniform hashing strategy for all keys. + for (var i = start; i < end; i++) { - for (var i = start; i < end; i++) - { - result = Hash.Combine((int)Data[i], result); - } + result = Hash.Combine((int)char.ToLower(Data[i]), result); } - return result; } diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.Visitor.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.SymbolKeyWriter.cs similarity index 96% rename from src/Workspaces/Core/Portable/SymbolId/SymbolKey.Visitor.cs rename to src/Workspaces/Core/Portable/SymbolId/SymbolKey.SymbolKeyWriter.cs index 988b05f91cc..e35e5e7b2d3 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.Visitor.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.SymbolKeyWriter.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private enum SymbolKeyType { @@ -41,10 +41,10 @@ private enum SymbolKeyType TypeParameterOrdinal = '@', } - private class Visitor : SymbolVisitor, IDisposable + private class SymbolKeyWriter : SymbolVisitor, IDisposable { - private static readonly ObjectPool s_visitorPool = - new ObjectPool(() => new Visitor()); + private static readonly ObjectPool s_writerPool = + new ObjectPool(() => new SymbolKeyWriter()); private readonly Action _writeSymbolKey; private readonly Action _writeString; @@ -61,7 +61,7 @@ private class Visitor : SymbolVisitor, IDisposable internal int _nestingCount; private int _nextId; - private Visitor() + private SymbolKeyWriter() { _writeSymbolKey = WriteSymbolKey; _writeString = WriteString; @@ -79,12 +79,12 @@ public void Dispose() _nextId = 0; // Place us back in the pool for future use. - s_visitorPool.Free(this); + s_writerPool.Free(this); } - public static Visitor GetVisitor(Compilation compilation, CancellationToken cancellationToken) + public static SymbolKeyWriter GetWriter(Compilation compilation, CancellationToken cancellationToken) { - var visitor = s_visitorPool.Allocate(); + var visitor = s_writerPool.Allocate(); visitor.Initialize(compilation, cancellationToken); return visitor; } diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.TupleTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.TupleTypeSymbolKey.cs index 97a19b161c0..7784c30772f 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.TupleTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.TupleTypeSymbolKey.cs @@ -6,11 +6,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class TupleTypeSymbolKey { - public static void Create(INamedTypeSymbol symbol, Visitor visitor) + public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor) { Debug.Assert(symbol.IsTupleType); visitor.WriteSymbolKey(symbol.TupleUnderlyingType); diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.TypeParameterOrdinalSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.TypeParameterOrdinalSymbolKey.cs index c17f7520640..d9ceeed2b1c 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.TypeParameterOrdinalSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.TypeParameterOrdinalSymbolKey.cs @@ -4,11 +4,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class TypeParameterOrdinalSymbolKey { - public static void Create(ITypeParameterSymbol symbol, Visitor visitor) + public static void Create(ITypeParameterSymbol symbol, SymbolKeyWriter visitor) { Debug.Assert(visitor.WritingSignature); Debug.Assert(symbol.TypeParameterKind == TypeParameterKind.Method); diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.TypeParameterSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.TypeParameterSymbolKey.cs index d1cef9966c6..eec98c850b3 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.TypeParameterSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.TypeParameterSymbolKey.cs @@ -5,11 +5,11 @@ namespace Microsoft.CodeAnalysis { - internal partial class SymbolKey + internal partial struct SymbolKey { private static class TypeParameterSymbolKey { - public static void Create(ITypeParameterSymbol symbol, Visitor visitor) + public static void Create(ITypeParameterSymbol symbol, SymbolKeyWriter visitor) { visitor.WriteString(symbol.MetadataName); visitor.WriteSymbolKey(symbol.ContainingSymbol); diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.cs index 501eeeb7541..ecf1ce35cc4 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.cs @@ -76,25 +76,26 @@ namespace Microsoft.CodeAnalysis /// /// /// - internal partial class SymbolKey + internal partial struct SymbolKey { private readonly static Func s_typeIsNull = t => t == null; private readonly string _symbolKeyData; + private readonly int _hashCode; - private SymbolKey(string symbolKeyData) + public SymbolKey(string symbolKeyData) { if (symbolKeyData == null) { throw new ArgumentNullException(); - } + _symbolKeyData = symbolKeyData; - } - public static SymbolKey FromString(string data) - { - return new SymbolKey(data); + using (var reader = GetHashCodeReader.GetReader(_symbolKeyData)) + { + _hashCode = reader.ReadFirstSymbolKey(); + } } public static IEqualityComparer GetComparer(bool ignoreCase, bool ignoreAssemblyKeys) @@ -109,14 +110,6 @@ public static IEqualityComparer GetComparer(bool ignoreCase, bool ign return reader.RemoveAssemblySymbolKeys(); }; - private static int GetHashCode(SymbolKey key, ComparisonOptions options) - { - using (var reader = GetHashCodeReader.GetReader(key._symbolKeyData, options)) - { - return reader.ReadFirstSymbolKey(); - } - } - public static SymbolKeyResolution Resolve( string symbolKey, Compilation compilation, bool ignoreAssemblyKey = false, CancellationToken cancellationToken = default(CancellationToken)) @@ -136,10 +129,10 @@ public static string ToString(ISymbol symbol, CancellationToken cancellationToke { var compilation = (symbol.ContainingAssembly as ISourceAssemblySymbol)?.Compilation; - using (var visitor = Visitor.GetVisitor(compilation, cancellationToken)) + using (var writer = SymbolKeyWriter.GetWriter(compilation, cancellationToken)) { - visitor.WriteFirstSymbolKey(symbol); - return visitor.CreateKey(); + writer.WriteFirstSymbolKey(symbol); + return writer.CreateKey(); } } @@ -256,5 +249,10 @@ private static TSymbol GetFirstSymbol(SymbolKeyResolution resolution) return true; } + + public override int GetHashCode() + { + return _hashCode; + } } } \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/Workspaces.csproj b/src/Workspaces/Core/Portable/Workspaces.csproj index ba041fb3357..5eac3d399a5 100644 --- a/src/Workspaces/Core/Portable/Workspaces.csproj +++ b/src/Workspaces/Core/Portable/Workspaces.csproj @@ -445,7 +445,7 @@ - + -- GitLab