Fix #2298 simplify TagHelperDescriptor hash

The hash code implementation here is exhaustive when it doesn't need to
be. Slimming this down to a much more reasonable set of things for perf
reasons.
This commit is contained in:
Ryan Nowak 2018-04-30 11:52:41 -07:00
parent 2885b4b138
commit f67458f156
6 changed files with 37 additions and 85 deletions

View File

@ -54,20 +54,18 @@ namespace Microsoft.AspNetCore.Razor.Language
return false;
}
return descriptorX != null &&
return
string.Equals(descriptorX.Name, descriptorY.Name, _stringComparison) &&
string.Equals(descriptorX.DisplayName, descriptorY.DisplayName, StringComparison.Ordinal) &&
Enumerable.SequenceEqual(descriptorX.Diagnostics, descriptorY.Diagnostics);
string.Equals(descriptorX.DisplayName, descriptorY.DisplayName, StringComparison.Ordinal);
}
/// <inheritdoc />
public virtual int GetHashCode(AllowedChildTagDescriptor descriptor)
{
var hashCodeCombiner = HashCodeCombiner.Start();
hashCodeCombiner.Add(descriptor.Name, _stringComparer);
hashCodeCombiner.Add(descriptor.DisplayName, StringComparer.Ordinal);
var hash = HashCodeCombiner.Start();
hash.Add(descriptor.Name, _stringComparer);
return hashCodeCombiner.CombinedHash;
return hash.CombinedHash;
}
}
}

View File

@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Razor.Language
return false;
}
return descriptorX != null &&
return
string.Equals(descriptorX.Kind, descriptorY.Kind, StringComparison.Ordinal) &&
descriptorX.IsIndexerStringProperty == descriptorY.IsIndexerStringProperty &&
descriptorX.IsEnum == descriptorY.IsEnum &&
@ -61,7 +61,6 @@ namespace Microsoft.AspNetCore.Razor.Language
string.Equals(descriptorX.IndexerTypeName, descriptorY.IndexerTypeName, StringComparison.Ordinal) &&
string.Equals(descriptorX.Documentation, descriptorY.Documentation, StringComparison.Ordinal) &&
string.Equals(descriptorX.DisplayName, descriptorY.DisplayName, StringComparison.Ordinal) &&
Enumerable.SequenceEqual(descriptorX.Diagnostics, descriptorY.Diagnostics) &&
Enumerable.SequenceEqual(
descriptorX.Metadata.OrderBy(propertyX => propertyX.Key, StringComparer.Ordinal),
descriptorY.Metadata.OrderBy(propertyY => propertyY.Key, StringComparer.Ordinal));
@ -74,19 +73,11 @@ namespace Microsoft.AspNetCore.Razor.Language
throw new ArgumentNullException(nameof(descriptor));
}
var hashCodeCombiner = HashCodeCombiner.Start();
hashCodeCombiner.Add(descriptor.Kind);
hashCodeCombiner.Add(descriptor.IsIndexerStringProperty);
hashCodeCombiner.Add(descriptor.IsEnum);
hashCodeCombiner.Add(descriptor.HasIndexer);
hashCodeCombiner.Add(descriptor.Name, _stringComparer);
hashCodeCombiner.Add(descriptor.IndexerNamePrefix, _stringComparer);
hashCodeCombiner.Add(descriptor.TypeName, StringComparer.Ordinal);
hashCodeCombiner.Add(descriptor.IndexerTypeName, StringComparer.Ordinal);
hashCodeCombiner.Add(descriptor.Documentation, StringComparer.Ordinal);
hashCodeCombiner.Add(descriptor.DisplayName, StringComparer.Ordinal);
var hash = HashCodeCombiner.Start();
hash.Add(descriptor.Kind);
hash.Add(descriptor.Name, _stringComparer);
return hashCodeCombiner.CombinedHash;
return hash.CombinedHash;
}
}
}

View File

@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Razor.Language
@ -58,26 +57,21 @@ namespace Microsoft.AspNetCore.Razor.Language
return false;
}
return descriptorX != null &&
return
descriptorX.NameComparison == descriptorY.NameComparison &&
descriptorX.ValueComparison == descriptorY.ValueComparison &&
string.Equals(descriptorX.Name, descriptorY.Name, _stringComparison) &&
string.Equals(descriptorX.Value, descriptorY.Value, StringComparison.Ordinal) &&
string.Equals(descriptorX.DisplayName, descriptorY.DisplayName, StringComparison.Ordinal) &&
Enumerable.SequenceEqual(descriptorX.Diagnostics, descriptorY.Diagnostics);
string.Equals(descriptorX.DisplayName, descriptorY.DisplayName, StringComparison.Ordinal);
}
/// <inheritdoc />
public virtual int GetHashCode(RequiredAttributeDescriptor descriptor)
{
var hashCodeCombiner = HashCodeCombiner.Start();
hashCodeCombiner.Add(descriptor.NameComparison);
hashCodeCombiner.Add(descriptor.ValueComparison);
hashCodeCombiner.Add(descriptor.Name, _stringComparer);
hashCodeCombiner.Add(descriptor.Value, StringComparer.Ordinal);
hashCodeCombiner.Add(descriptor.DisplayName, StringComparer.Ordinal);
var hash = HashCodeCombiner.Start();
hash.Add(descriptor.Name, _stringComparer);
return hashCodeCombiner.CombinedHash;
return hash.CombinedHash;
}
}
}

View File

@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Razor.Language
public virtual bool Equals(TagHelperDescriptor descriptorX, TagHelperDescriptor descriptorY)
{
if (descriptorX == descriptorY)
if (object.ReferenceEquals(descriptorX, descriptorY))
{
return true;
}
@ -62,6 +62,7 @@ namespace Microsoft.AspNetCore.Razor.Language
return descriptorX != null &&
string.Equals(descriptorX.Kind, descriptorY.Kind, StringComparison.Ordinal) &&
string.Equals(descriptorX.AssemblyName, descriptorY.AssemblyName, StringComparison.Ordinal) &&
string.Equals(descriptorX.Name, descriptorY.Name, StringComparison.Ordinal) &&
Enumerable.SequenceEqual(
descriptorX.BoundAttributes.OrderBy(attribute => attribute.Name, _stringComparer),
descriptorY.BoundAttributes.OrderBy(attribute => attribute.Name, _stringComparer),
@ -94,33 +95,12 @@ namespace Microsoft.AspNetCore.Razor.Language
throw new ArgumentNullException(nameof(descriptor));
}
var hashCodeCombiner = HashCodeCombiner.Start();
hashCodeCombiner.Add(descriptor.Kind);
hashCodeCombiner.Add(descriptor.AssemblyName, StringComparer.Ordinal);
var hash = HashCodeCombiner.Start();
hash.Add(descriptor.Kind, StringComparer.Ordinal);
hash.Add(descriptor.AssemblyName, StringComparer.Ordinal);
hash.Add(descriptor.Name, StringComparer.Ordinal);
var childTags = descriptor.AllowedChildTags.OrderBy(childTag => childTag.Name, _stringComparer);
foreach (var childTag in childTags)
{
hashCodeCombiner.Add(_AllowedChildTagDescriptorComparer.GetHashCode(childTag));
}
var boundAttributes = descriptor.BoundAttributes.OrderBy(attribute => attribute.Name, _stringComparer);
foreach (var attribute in boundAttributes)
{
hashCodeCombiner.Add(_boundAttributeComparer.GetHashCode(attribute));
}
var rules = descriptor.TagMatchingRules.OrderBy(rule => rule.TagName, _stringComparer);
foreach (var rule in rules)
{
hashCodeCombiner.Add(_tagMatchingRuleComparer.GetHashCode(rule));
}
hashCodeCombiner.Add(descriptor.Documentation, StringComparer.Ordinal);
hashCodeCombiner.Add(descriptor.DisplayName, StringComparer.Ordinal);
hashCodeCombiner.Add(descriptor.TagOutputHint, _stringComparer);
return hashCodeCombiner.CombinedHash;
return hash.CombinedHash;
}
}
}

View File

@ -54,12 +54,11 @@ namespace Microsoft.AspNetCore.Razor.Language
return false;
}
return ruleX != null &&
return
string.Equals(ruleX.TagName, ruleY.TagName, _stringComparison) &&
string.Equals(ruleX.ParentTag, ruleY.ParentTag, _stringComparison) &&
ruleX.TagStructure == ruleY.TagStructure &&
Enumerable.SequenceEqual(ruleX.Attributes, ruleY.Attributes, _requiredAttributeComparer) &&
Enumerable.SequenceEqual(ruleX.Diagnostics, ruleY.Diagnostics);
Enumerable.SequenceEqual(ruleX.Attributes, ruleY.Attributes, _requiredAttributeComparer);
}
public virtual int GetHashCode(TagMatchingRuleDescriptor rule)
@ -69,18 +68,10 @@ namespace Microsoft.AspNetCore.Razor.Language
throw new ArgumentNullException(nameof(rule));
}
var hashCodeCombiner = HashCodeCombiner.Start();
hashCodeCombiner.Add(rule.TagName, _stringComparer);
hashCodeCombiner.Add(rule.ParentTag, _stringComparer);
hashCodeCombiner.Add(rule.TagStructure);
var hash = HashCodeCombiner.Start();
hash.Add(rule.TagName, _stringComparer);
var attributes = rule.Attributes.OrderBy(attribute => attribute.Name, _stringComparer);
foreach (var attribute in attributes)
{
hashCodeCombiner.Add(_requiredAttributeComparer.GetHashCode(attribute));
}
return hashCodeCombiner.CombinedHash;
return hash.CombinedHash;
}
}
}

View File

@ -29,18 +29,16 @@ namespace Microsoft.VisualStudio.Editor.Razor
_tagHelperFactsService = tagHelperFactsService;
}
/*
* This API attempts to understand a users context as they're typing in a Razor file to provide TagHelper based attribute IntelliSense.
*
* Scenarios for TagHelper attribute IntelliSense follows:
* 1. TagHelperDescriptor's have matching required attribute names
* -> Provide IntelliSense for the required attributes of those descriptors to lead users towards a TagHelperified element.
* 2. TagHelperDescriptor entirely applies to current element. Tag name, attributes, everything is fulfilled.
* -> Provide IntelliSense for the bound attributes for the applied descriptors.
*
* Within each of the above scenarios if an attribute completion has a corresponding bound attribute we associate it with the corresponding
* BoundAttributeDescriptor. By doing this a user can see what C# type a TagHelper expects for the attribute.
*/
// This API attempts to understand a users context as they're typing in a Razor file to provide TagHelper based attribute IntelliSense.
//
// Scenarios for TagHelper attribute IntelliSense follows:
// 1. TagHelperDescriptor's have matching required attribute names
// -> Provide IntelliSense for the required attributes of those descriptors to lead users towards a TagHelperified element.
// 2. TagHelperDescriptor entirely applies to current element. Tag name, attributes, everything is fulfilled.
// -> Provide IntelliSense for the bound attributes for the applied descriptors.
//
// Within each of the above scenarios if an attribute completion has a corresponding bound attribute we associate it with the corresponding
// BoundAttributeDescriptor. By doing this a user can see what C# type a TagHelper expects for the attribute.
public override AttributeCompletionResult GetAttributeCompletions(AttributeCompletionContext completionContext)
{
if (completionContext == null)