Skip to content

Commit 1e5cd95

Browse files
committed
Reduce the number of allocations required to register one syntax kind
1 parent 4f1d09f commit 1e5cd95

1 file changed

Lines changed: 65 additions & 0 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers/AnalyzerExtensions.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace StyleCop.Analyzers
55
{
66
using System;
77
using System.Collections.Concurrent;
8+
using System.Collections.Immutable;
89
using System.Threading;
910
using Microsoft.CodeAnalysis;
1011
using Microsoft.CodeAnalysis.Diagnostics;
@@ -86,6 +87,25 @@ public static ConcurrentDictionary<SyntaxTree, bool> GetOrCreateGeneratedDocumen
8687
return headerCache.Item2;
8788
}
8889

90+
/// <summary>
91+
/// Register an action to be executed at completion of semantic analysis of a <see cref="SyntaxNode"/> with an
92+
/// appropriate kind. A syntax node action can report diagnostics about a <see cref="SyntaxNode"/>, and can also
93+
/// collect state information to be used by other syntax node actions or code block end actions.
94+
/// </summary>
95+
/// <remarks>This method honors exclusions.</remarks>
96+
/// <param name="context">Action will be executed only if the kind of a <see cref="SyntaxNode"/> matches
97+
/// <paramref name="syntaxKind"/>.</param>
98+
/// <param name="action">Action to be executed at completion of semantic analysis of a
99+
/// <see cref="SyntaxNode"/>.</param>
100+
/// <param name="syntaxKind">The kind of syntax that should be analyzed.</param>
101+
/// <typeparam name="TLanguageKindEnum">Enum type giving the syntax node kinds of the source language for which
102+
/// the action applies.</typeparam>
103+
public static void RegisterSyntaxNodeActionHonorExclusions<TLanguageKindEnum>(this CompilationStartAnalysisContext context, Action<SyntaxNodeAnalysisContext> action, TLanguageKindEnum syntaxKind)
104+
where TLanguageKindEnum : struct
105+
{
106+
context.RegisterSyntaxNodeActionHonorExclusions(action, LanguageKindArrays<TLanguageKindEnum>.GetOrCreateArray(syntaxKind));
107+
}
108+
89109
/// <summary>
90110
/// Register an action to be executed at completion of semantic analysis of a <see cref="SyntaxNode"/> with an
91111
/// appropriate kind. A syntax node action can report diagnostics about a <see cref="SyntaxNode"/>, and can also
@@ -101,6 +121,32 @@ public static ConcurrentDictionary<SyntaxTree, bool> GetOrCreateGeneratedDocumen
101121
/// the action applies.</typeparam>
102122
public static void RegisterSyntaxNodeActionHonorExclusions<TLanguageKindEnum>(this CompilationStartAnalysisContext context, Action<SyntaxNodeAnalysisContext> action, params TLanguageKindEnum[] syntaxKinds)
103123
where TLanguageKindEnum : struct
124+
{
125+
if (syntaxKinds == null)
126+
{
127+
RegisterSyntaxNodeActionHonorExclusions(context, action, default(ImmutableArray<TLanguageKindEnum>));
128+
}
129+
else
130+
{
131+
RegisterSyntaxNodeActionHonorExclusions(context, action, syntaxKinds.ToImmutableArray());
132+
}
133+
}
134+
135+
/// <summary>
136+
/// Register an action to be executed at completion of semantic analysis of a <see cref="SyntaxNode"/> with an
137+
/// appropriate kind. A syntax node action can report diagnostics about a <see cref="SyntaxNode"/>, and can also
138+
/// collect state information to be used by other syntax node actions or code block end actions.
139+
/// </summary>
140+
/// <remarks>This method honors exclusions.</remarks>
141+
/// <param name="context">Action will be executed only if the kind of a <see cref="SyntaxNode"/> matches one of
142+
/// the <paramref name="syntaxKinds"/> values.</param>
143+
/// <param name="action">Action to be executed at completion of semantic analysis of a
144+
/// <see cref="SyntaxNode"/>.</param>
145+
/// <param name="syntaxKinds">The kinds of syntax that should be analyzed.</param>
146+
/// <typeparam name="TLanguageKindEnum">Enum type giving the syntax node kinds of the source language for which
147+
/// the action applies.</typeparam>
148+
public static void RegisterSyntaxNodeActionHonorExclusions<TLanguageKindEnum>(this CompilationStartAnalysisContext context, Action<SyntaxNodeAnalysisContext> action, ImmutableArray<TLanguageKindEnum> syntaxKinds)
149+
where TLanguageKindEnum : struct
104150
{
105151
Compilation compilation = context.Compilation;
106152
ConcurrentDictionary<SyntaxTree, bool> cache = GetOrCreateGeneratedDocumentCache(compilation);
@@ -121,5 +167,24 @@ public static void RegisterSyntaxNodeActionHonorExclusions<TLanguageKindEnum>(th
121167
},
122168
syntaxKinds);
123169
}
170+
171+
private static class LanguageKindArrays<TLanguageKindEnum>
172+
where TLanguageKindEnum : struct
173+
{
174+
private static readonly ConcurrentDictionary<TLanguageKindEnum, ImmutableArray<TLanguageKindEnum>> Arrays =
175+
new ConcurrentDictionary<TLanguageKindEnum, ImmutableArray<TLanguageKindEnum>>();
176+
177+
private static readonly Func<TLanguageKindEnum, ImmutableArray<TLanguageKindEnum>> CreateValueFactory = CreateValue;
178+
179+
public static ImmutableArray<TLanguageKindEnum> GetOrCreateArray(TLanguageKindEnum syntaxKind)
180+
{
181+
return Arrays.GetOrAdd(syntaxKind, CreateValueFactory);
182+
}
183+
184+
private static ImmutableArray<TLanguageKindEnum> CreateValue(TLanguageKindEnum syntaxKind)
185+
{
186+
return ImmutableArray.Create(syntaxKind);
187+
}
188+
}
124189
}
125190
}

0 commit comments

Comments
 (0)