未验证 提交 8017891b 编写于 作者: S Sam Harwell 提交者: GitHub

Merge pull request #43060 from sharwell/faster-tests-2

Improve test performance
......@@ -13,8 +13,9 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ChangeSignature
{
public partial class ChangeSignatureTests : AbstractChangeSignatureTests
{
[WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
public async Task TestAllSignatureChanges_1This_3Regular_2Default_1Params()
[WpfTheory, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
[MemberData(nameof(AbstractChangeSignatureTests.GetAllSignatureSpecificationsForTheory), new[] { 1, 3, 2, 1 }, MemberType = typeof(AbstractChangeSignatureTests))]
public async Task TestAllSignatureChanges_1This_3Regular_2Default_1Params(int totalParameters, int[] signature)
{
var markup = @"
static class Ext
......@@ -57,12 +58,19 @@ static class Ext
M(p: new[] { 5 }, y: ""four"", x: 3, c: true, b: ""two"", a: 1, o: t);
}
}";
var signaturePartCounts = new[] { 1, 3, 2, 1 };
await TestAllSignatureChangesAsync(LanguageNames.CSharp, markup, signaturePartCounts);
await TestChangeSignatureViaCommandAsync(
LanguageNames.CSharp,
markup,
expectedSuccess: true,
updatedSignature: signature,
totalParameters: totalParameters,
verifyNoDiagnostics: true);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
public async Task TestAllSignatureChanges_OnDelegate_3Regular()
[WpfTheory, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
[MemberData(nameof(AbstractChangeSignatureTests.GetAllSignatureSpecificationsForTheory), new[] { 0, 3, 0, 0 }, MemberType = typeof(AbstractChangeSignatureTests))]
public async Task TestAllSignatureChanges_OnDelegate_3Regular(int totalParameters, int[] signature)
{
var markup = @"
using System;
......@@ -151,8 +159,15 @@ void M()
/// <param name=""c""></param>
void Goo5(int a, string b, bool c) { }
}";
var signaturePartCounts = new[] { 0, 3, 0, 0 };
await TestAllSignatureChangesAsync(LanguageNames.CSharp, markup, signaturePartCounts, new CSharpParseOptions(LanguageVersion.CSharp7));
await TestChangeSignatureViaCommandAsync(
LanguageNames.CSharp,
markup,
expectedSuccess: true,
updatedSignature: signature,
totalParameters: totalParameters,
verifyNoDiagnostics: true,
parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7));
}
}
}
......@@ -157,7 +157,7 @@ private string GetSignatureDescriptionString(int[] signature, int? totalParamete
/// </summary>
/// <param name="signaturePartCounts">A four element array containing [s, m, n, p] as
/// described above.</param>
public async Task TestAllSignatureChangesAsync(string languageName, string markup, int[] signaturePartCounts, ParseOptions parseOptions = null)
public static IEnumerable<object> GetAllSignatureSpecificationsForTheory(int[] signaturePartCounts)
{
Assert.Equal(4, signaturePartCounts.Length);
Assert.True(signaturePartCounts[0] == 0 || signaturePartCounts[0] == 1);
......@@ -167,18 +167,11 @@ public async Task TestAllSignatureChangesAsync(string languageName, string marku
foreach (var signature in GetAllSignatureSpecifications(signaturePartCounts))
{
await TestChangeSignatureViaCommandAsync(
languageName,
markup,
expectedSuccess: true,
updatedSignature: signature,
totalParameters: totalParameters,
verifyNoDiagnostics: true,
parseOptions: parseOptions);
yield return new object[] { totalParameters, signature };
}
}
private IEnumerable<int[]> GetAllSignatureSpecifications(int[] signaturePartCounts)
private static IEnumerable<int[]> GetAllSignatureSpecifications(int[] signaturePartCounts)
{
var regularParameterStartIndex = signaturePartCounts[0];
var defaultValueParameterStartIndex = signaturePartCounts[0] + signaturePartCounts[1];
......@@ -204,7 +197,7 @@ private IEnumerable<int[]> GetAllSignatureSpecifications(int[] signaturePartCoun
}
}
private IEnumerable<IEnumerable<int>> GetPermutedSubsets(int startIndex, int count)
private static IEnumerable<IEnumerable<int>> GetPermutedSubsets(int startIndex, int count)
{
foreach (var subset in GetSubsets(Enumerable.Range(startIndex, count)))
{
......@@ -215,7 +208,7 @@ private IEnumerable<IEnumerable<int>> GetPermutedSubsets(int startIndex, int cou
}
}
private IEnumerable<IEnumerable<int>> GetPermutations(IEnumerable<int> list)
private static IEnumerable<IEnumerable<int>> GetPermutations(IEnumerable<int> list)
{
if (!list.Any())
{
......@@ -236,7 +229,7 @@ private IEnumerable<IEnumerable<int>> GetPermutations(IEnumerable<int> list)
}
}
private IEnumerable<int> GetListWithoutElementAtIndex(IEnumerable<int> list, int skippedIndex)
private static IEnumerable<int> GetListWithoutElementAtIndex(IEnumerable<int> list, int skippedIndex)
{
var index = 0;
foreach (var x in list)
......@@ -250,7 +243,7 @@ private IEnumerable<int> GetListWithoutElementAtIndex(IEnumerable<int> list, int
}
}
private IEnumerable<IEnumerable<int>> GetSubsets(IEnumerable<int> list)
private static IEnumerable<IEnumerable<int>> GetSubsets(IEnumerable<int> list)
{
if (!list.Any())
{
......
......@@ -9,8 +9,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ChangeSignature
Partial Public Class ChangeSignatureTests
Inherits AbstractChangeSignatureTests
<WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)>
Public Async Function TestAllSignatureChanges_1This_3Regular_2Default() As Task
<WpfTheory, Trait(Traits.Feature, Traits.Features.ChangeSignature)>
<MemberData(NameOf(AbstractChangeSignatureTests.GetAllSignatureSpecificationsForTheory), New Integer() {1, 3, 2, 0}, MemberType:=GetType(AbstractChangeSignatureTests))>
Public Async Function TestAllSignatureChanges_1This_3Regular_2Default(totalParameters As Integer, signature As Integer()) As Task
Dim markup = <Text><![CDATA[
Option Strict On
......@@ -47,12 +48,19 @@ Module Program
End Sub
End Module
]]></Text>.NormalizedValue()
Dim signaturePartCounts = {1, 3, 2, 0}
Await TestAllSignatureChangesAsync(LanguageNames.VisualBasic, markup, signaturePartCounts)
Await TestChangeSignatureViaCommandAsync(
LanguageNames.VisualBasic,
markup,
expectedSuccess:=True,
updatedSignature:=signature,
totalParameters:=totalParameters,
verifyNoDiagnostics:=True)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)>
Public Async Function TestAllSignatureChanges_1This_3Regular_1ParamArray() As Task
<WpfTheory, Trait(Traits.Feature, Traits.Features.ChangeSignature)>
<MemberData(NameOf(AbstractChangeSignatureTests.GetAllSignatureSpecificationsForTheory), New Integer() {1, 3, 0, 1}, MemberType:=GetType(AbstractChangeSignatureTests))>
Public Async Function TestAllSignatureChanges_1This_3Regular_1ParamArray(totalParameters As Integer, signature As Integer()) As Task
Dim markup = <Text><![CDATA[
Option Strict On
......@@ -72,12 +80,19 @@ Module Program
End Sub
End Module
]]></Text>.NormalizedValue()
Dim signaturePartCounts = {1, 3, 0, 1}
Await TestAllSignatureChangesAsync(LanguageNames.VisualBasic, markup, signaturePartCounts)
Await TestChangeSignatureViaCommandAsync(
LanguageNames.VisualBasic,
markup,
expectedSuccess:=True,
updatedSignature:=signature,
totalParameters:=totalParameters,
verifyNoDiagnostics:=True)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.ChangeSignature)>
Public Async Function TestAllSignatureChanges_Delegate_3() As Task
<WpfTheory, Trait(Traits.Feature, Traits.Features.ChangeSignature)>
<MemberData(NameOf(AbstractChangeSignatureTests.GetAllSignatureSpecificationsForTheory), New Integer() {0, 3, 0, 0}, MemberType:=GetType(AbstractChangeSignatureTests))>
Public Async Function TestAllSignatureChanges_Delegate_3(totalParameters As Integer, signature As Integer()) As Task
Dim markup = <Text><![CDATA[
Option Strict On
......@@ -135,8 +150,14 @@ Class C
End Sub
End Class
]]></Text>.NormalizedValue()
Dim signaturePartCounts = {0, 3, 0, 0}
Await TestAllSignatureChangesAsync(LanguageNames.VisualBasic, markup, signaturePartCounts)
Await TestChangeSignatureViaCommandAsync(
LanguageNames.VisualBasic,
markup,
expectedSuccess:=True,
updatedSignature:=signature,
totalParameters:=totalParameters,
verifyNoDiagnostics:=True)
End Function
End Class
End Namespace
......@@ -15,6 +15,9 @@ namespace Microsoft.CodeAnalysis.Completion.Providers
{
internal static partial class SymbolCompletionItem
{
private static readonly Func<IReadOnlyList<ISymbol>, CompletionItem, CompletionItem> s_addSymbolEncoding = AddSymbolEncoding;
private static readonly Func<IReadOnlyList<ISymbol>, CompletionItem, CompletionItem> s_addSymbolInfo = AddSymbolInfo;
private static CompletionItem CreateWorker(
string displayText,
string displayTextSuffix,
......@@ -280,7 +283,7 @@ public static string GetInsertionText(CompletionItem item)
{
return CreateWorker(
displayText, displayTextSuffix, symbols, rules, contextPosition,
AddSymbolEncoding, sortText, insertionText,
s_addSymbolEncoding, sortText, insertionText,
filterText, supportedPlatforms, properties, tags);
}
......@@ -299,7 +302,7 @@ public static string GetInsertionText(CompletionItem item)
{
return CreateWorker(
displayText, displayTextSuffix, symbols, rules, contextPosition,
AddSymbolInfo, sortText, insertionText,
s_addSymbolInfo, sortText, insertionText,
filterText, supportedPlatforms, properties, tags);
}
......
......@@ -86,13 +86,13 @@ private void ReleaseAndGarbageCollect()
_strongReference = null;
// We'll loop 1000 times, or until the weak reference disappears. When we're trying to assert that the
// We'll loop 10 times, or until the weak reference disappears. When we're trying to assert that the
// object is released, once the weak reference goes away, we know we're good. But if we're trying to assert
// that the object is held, our only real option is to know to do it "enough" times; but if it goes away then
// we are definitely done.
for (var i = 0; i < 1000 && _weakReference.IsAlive; i++)
for (var i = 0; i < 10 && _weakReference.IsAlive; i++)
{
GC.Collect();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true, compacting: true);
GC.WaitForPendingFinalizers();
}
}
......
......@@ -653,18 +653,19 @@ private static bool ElementNameIs(XElement element, string name)
// PERF: HasUnsupportedMetadata may require recreating the syntax tree to get the base class, so first
// check to see if we're referencing a symbol defined in source.
bool isSymbolDefinedInSource(Location l) => l.IsInSource;
return symbols.WhereAsArray(s =>
static bool isSymbolDefinedInSource(Location l) => l.IsInSource;
return symbols.WhereAsArray((s, arg) =>
(s.Locations.Any(isSymbolDefinedInSource) || !s.HasUnsupportedMetadata) &&
!s.IsDestructor() &&
s.IsEditorBrowsable(
hideAdvancedMembers,
compilation,
editorBrowsableAttributeConstructor,
typeLibTypeAttributeConstructors,
typeLibFuncAttributeConstructors,
typeLibVarAttributeConstructors,
hideModuleNameAttribute));
arg.hideAdvancedMembers,
arg.compilation,
arg.editorBrowsableAttributeConstructor,
arg.typeLibTypeAttributeConstructors,
arg.typeLibFuncAttributeConstructors,
arg.typeLibVarAttributeConstructors,
arg.hideModuleNameAttribute),
(hideAdvancedMembers, compilation, editorBrowsableAttributeConstructor, typeLibTypeAttributeConstructors, typeLibFuncAttributeConstructors, typeLibVarAttributeConstructors, hideModuleNameAttribute));
}
private static ImmutableArray<T> RemoveOverriddenSymbolsWithinSet<T>(this ImmutableArray<T> symbols) where T : ISymbol
......
......@@ -129,10 +129,10 @@ private TriviaData GetWhitespaceOnlyTriviaInfo(SyntaxToken token1, SyntaxToken t
private int CalculateSpaces(SyntaxToken token1, SyntaxToken token2)
{
var initialColumn = (token1.RawKind == 0) ? 0 : this.TreeInfo.GetOriginalColumn(this.Options.GetOption(FormattingOptions2.TabSize), token1) + token1.Span.Length;
var initialColumn = (token1.RawKind == 0) ? 0 : this.TreeInfo.GetOriginalColumn(TabSize, token1) + token1.Span.Length;
var textSnippet = this.TreeInfo.GetTextBetween(token1, token2);
return textSnippet.ConvertTabToSpace(this.Options.GetOption(FormattingOptions2.TabSize), initialColumn, textSnippet.Length);
return textSnippet.ConvertTabToSpace(TabSize, initialColumn, textSnippet.Length);
}
private (bool canUseTriviaAsItIs, int lineBreaks, int indentation) GetLineBreaksAndIndentation(Analyzer.AnalysisResult result)
......@@ -140,7 +140,7 @@ private int CalculateSpaces(SyntaxToken token1, SyntaxToken token2)
Debug.Assert(result.Tab >= 0);
Debug.Assert(result.LineBreaks >= 0);
var indentation = result.Tab * this.Options.GetOption(FormattingOptions2.TabSize) + result.Space;
var indentation = result.Tab * TabSize + result.Space;
if (result.HasTrailingSpace || result.HasUnknownWhitespace)
{
if (result.HasUnknownWhitespace && result.LineBreaks == 0 && indentation == 0)
......@@ -152,7 +152,7 @@ private int CalculateSpaces(SyntaxToken token1, SyntaxToken token2)
return (canUseTriviaAsItIs: false, result.LineBreaks, indentation);
}
if (!this.Options.GetOption(FormattingOptions2.UseTabs))
if (!UseTabs)
{
if (result.Tab > 0)
{
......@@ -162,7 +162,7 @@ private int CalculateSpaces(SyntaxToken token1, SyntaxToken token2)
return (canUseTriviaAsItIs: true, result.LineBreaks, indentation);
}
Debug.Assert(this.Options.GetOption(FormattingOptions2.UseTabs));
Debug.Assert(UseTabs);
// tab can only appear before space to be a valid tab for indentation
if (result.HasTabAfterSpace)
......@@ -170,13 +170,13 @@ private int CalculateSpaces(SyntaxToken token1, SyntaxToken token2)
return (canUseTriviaAsItIs: false, result.LineBreaks, indentation);
}
if (result.Space >= this.Options.GetOption(FormattingOptions2.TabSize))
if (result.Space >= TabSize)
{
return (canUseTriviaAsItIs: false, result.LineBreaks, indentation);
}
Debug.Assert((indentation / this.Options.GetOption(FormattingOptions2.TabSize)) == result.Tab);
Debug.Assert((indentation % this.Options.GetOption(FormattingOptions2.TabSize)) == result.Space);
Debug.Assert((indentation / TabSize) == result.Tab);
Debug.Assert((indentation % TabSize) == result.Space);
return (canUseTriviaAsItIs: true, result.LineBreaks, indentation);
}
......
......@@ -17,6 +17,10 @@ internal abstract partial class AbstractTriviaDataFactory
protected readonly TreeData TreeInfo;
protected readonly AnalyzerConfigOptions Options;
protected readonly bool UseTabs;
protected readonly int TabSize;
protected readonly int IndentationSize;
private readonly Whitespace[] _spaces = new Whitespace[SpaceCacheSize];
private readonly Whitespace[,] _whitespaces = new Whitespace[LineBreakCacheSize, IndentationLevelCacheSize];
......@@ -28,6 +32,10 @@ protected AbstractTriviaDataFactory(TreeData treeInfo, AnalyzerConfigOptions opt
this.TreeInfo = treeInfo;
this.Options = options;
UseTabs = options.GetOption(FormattingOptions2.UseTabs);
TabSize = options.GetOption(FormattingOptions2.TabSize);
IndentationSize = options.GetOption(FormattingOptions2.IndentationSize);
for (var i = 0; i < SpaceCacheSize; i++)
{
_spaces[i] = new Whitespace(this.Options, space: i, elastic: false, language: treeInfo.Root.Language);
......@@ -67,11 +75,11 @@ protected TriviaData GetWhitespaceTriviaData(int lineBreaks, int indentation, bo
useTriviaAsItIs &&
lineBreaks > 0 &&
lineBreaks <= LineBreakCacheSize &&
indentation % this.Options.GetOption(FormattingOptions2.IndentationSize) == 0;
indentation % IndentationSize == 0;
if (canUseCache)
{
var indentationLevel = indentation / this.Options.GetOption(FormattingOptions2.IndentationSize);
var indentationLevel = indentation / IndentationSize;
if (indentationLevel < IndentationLevelCacheSize)
{
var lineIndex = lineBreaks - 1;
......@@ -94,7 +102,7 @@ private void EnsureWhitespaceTriviaInfo(int lineIndex, int indentationLevel)
// set up caches
if (_whitespaces[lineIndex, indentationLevel] == null)
{
var indentation = indentationLevel * this.Options.GetOption(FormattingOptions2.IndentationSize);
var indentation = indentationLevel * IndentationSize;
var triviaInfo = new Whitespace(this.Options, lineBreaks: lineIndex + 1, indentation: indentation, elastic: false, language: this.TreeInfo.Root.Language);
Interlocked.CompareExchange(ref _whitespaces[lineIndex, indentationLevel], triviaInfo, null);
}
......
......@@ -16,7 +16,7 @@
namespace Microsoft.CodeAnalysis.NamingStyles
{
internal partial struct NamingStyle
internal partial struct NamingStyle : IEquatable<NamingStyle>
{
public Guid ID { get; }
public string Name { get; }
......@@ -63,6 +63,32 @@ internal partial struct NamingStyle
newName, newPrefix, newSuffix, newWordSeparator, newCapitalizationScheme);
}
public override bool Equals(object obj)
{
return obj is NamingStyle other
&& Equals(other);
}
public bool Equals(NamingStyle other)
{
return ID == other.ID
&& Name == other.Name
&& Prefix == other.Prefix
&& Suffix == other.Suffix
&& WordSeparator == other.WordSeparator
&& CapitalizationScheme == other.CapitalizationScheme;
}
public override int GetHashCode()
{
return Hash.Combine(ID.GetHashCode(),
Hash.Combine(Name?.GetHashCode() ?? 0,
Hash.Combine(Prefix?.GetHashCode() ?? 0,
Hash.Combine(Suffix?.GetHashCode() ?? 0,
Hash.Combine(WordSeparator?.GetHashCode() ?? 0,
(int)CapitalizationScheme)))));
}
public string CreateName(ImmutableArray<string> words)
{
var wordsWithCasing = ApplyCapitalization(words);
......
......@@ -8,6 +8,7 @@
using System.Linq;
using System.Xml.Linq;
using Microsoft.CodeAnalysis.NamingStyles;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles
{
......@@ -17,7 +18,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles
/// 2. Name Style
/// 3. Naming Rule (points to Symbol Specification IDs)
/// </summary>
internal class NamingStylePreferences : IEquatable<NamingStylePreferences>
internal sealed class NamingStylePreferences : IEquatable<NamingStylePreferences>
{
private const int s_serializationVersion = 5;
......@@ -81,9 +82,12 @@ public override bool Equals(object obj)
public bool Equals(NamingStylePreferences other)
{
return other == null
? false
: CreateXElement().ToString() == other.CreateXElement().ToString();
if (other is null)
return false;
return SymbolSpecifications.SequenceEqual(other.SymbolSpecifications)
&& NamingStyles.SequenceEqual(other.NamingStyles)
&& NamingRules.SequenceEqual(other.NamingRules);
}
public static bool operator ==(NamingStylePreferences left, NamingStylePreferences right)
......@@ -104,7 +108,11 @@ public bool Equals(NamingStylePreferences other)
=> !(left == right);
public override int GetHashCode()
=> CreateXElement().ToString().GetHashCode();
{
return Hash.Combine(Hash.CombineValues(SymbolSpecifications),
Hash.Combine(Hash.CombineValues(NamingStyles),
Hash.CombineValues(NamingRules)));
}
private static readonly string _defaultNamingPreferencesString = $@"
<NamingPreferencesInfo SerializationVersion=""{s_serializationVersion}"">
......
......@@ -4,10 +4,11 @@
using System;
using System.Xml.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles
{
internal class SerializableNamingRule
internal sealed class SerializableNamingRule : IEquatable<SerializableNamingRule>
{
public Guid SymbolSpecificationID;
public Guid NamingStyleID;
......@@ -40,5 +41,25 @@ internal static SerializableNamingRule FromXElement(XElement namingRuleElement)
SymbolSpecificationID = Guid.Parse(namingRuleElement.Attribute(nameof(SymbolSpecificationID)).Value)
};
}
public override bool Equals(object obj)
{
return Equals(obj as SerializableNamingRule);
}
public bool Equals(SerializableNamingRule other)
{
return other != null
&& SymbolSpecificationID.Equals(other.SymbolSpecificationID)
&& NamingStyleID.Equals(other.NamingStyleID)
&& EnforcementLevel == other.EnforcementLevel;
}
public override int GetHashCode()
{
return Hash.Combine(SymbolSpecificationID.GetHashCode(),
Hash.Combine(NamingStyleID.GetHashCode(),
(int)EnforcementLevel));
}
}
}
......@@ -19,7 +19,7 @@
namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles
{
internal class SymbolSpecification
internal sealed class SymbolSpecification : IEquatable<SymbolSpecification>
{
private static readonly SymbolSpecification DefaultSymbolSpecificationTemplate = CreateDefaultSymbolSpecification();
......@@ -182,6 +182,32 @@ private bool AllMatches<TSymbolMatcher>(ImmutableArray<TSymbolMatcher> matchers,
return true;
}
public override bool Equals(object obj)
{
return Equals(obj as SymbolSpecification);
}
public bool Equals(SymbolSpecification other)
{
if (other is null)
return false;
return ID == other.ID
&& Name == other.Name
&& ApplicableSymbolKindList.SequenceEqual(other.ApplicableSymbolKindList)
&& ApplicableAccessibilityList.SequenceEqual(other.ApplicableAccessibilityList)
&& RequiredModifierList.SequenceEqual(other.RequiredModifierList);
}
public override int GetHashCode()
{
return Hash.Combine(ID.GetHashCode(),
Hash.Combine(Name.GetHashCode(),
Hash.Combine(Hash.CombineValues(ApplicableSymbolKindList),
Hash.Combine(Hash.CombineValues(ApplicableAccessibilityList),
Hash.CombineValues(RequiredModifierList)))));
}
internal XElement CreateXElement()
{
return new XElement(nameof(SymbolSpecification),
......@@ -338,11 +364,10 @@ public bool Equals(SymbolKindOrTypeKind other)
=> this.SymbolKind == other.SymbolKind && this.TypeKind == other.TypeKind && this.MethodKind == other.MethodKind;
public override int GetHashCode()
=> Hash.CombineValues(new[] {
(int)this.SymbolKind.GetValueOrDefault(),
(int)this.TypeKind.GetValueOrDefault(),
(int)this.MethodKind.GetValueOrDefault()
});
{
return Hash.Combine((int)SymbolKind.GetValueOrDefault(),
Hash.Combine((int)TypeKind.GetValueOrDefault(), (int)MethodKind.GetValueOrDefault()));
}
}
public struct ModifierKind : ISymbolMatcher, IEquatable<ModifierKind>
......@@ -437,7 +462,7 @@ public override bool Equals(object obj)
=> obj is ModifierKind kind && Equals(kind);
public override int GetHashCode()
=> ModifierKindWrapper.GetHashCode();
=> (int)ModifierKindWrapper;
public bool Equals(ModifierKind other)
=> ModifierKindWrapper == other.ModifierKindWrapper;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册