Skip to content

Commit 6db4e7b

Browse files
committed
* Benchmark classes annotated with a [GenericTypeArguments] attribute must be non-abstract and generic
* Benchmark classes are allowed to be generic if they are either abstract or annotated with at least one [GenericTypeArguments] attribute * Assume that a class can be annotated with more than one [GenericTypeArguments] attribute
1 parent 1f20823 commit 6db4e7b

File tree

9 files changed

+298
-208
lines changed

9 files changed

+298
-208
lines changed

src/BenchmarkDotNet.Analyzers/AnalyzerHelper.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@
22
{
33
using Microsoft.CodeAnalysis;
44
using Microsoft.CodeAnalysis.CSharp.Syntax;
5+
56
using System.Collections.Immutable;
67

78
internal static class AnalyzerHelper
89
{
910
public static LocalizableResourceString GetResourceString(string name) => new LocalizableResourceString(name, BenchmarkDotNetAnalyzerResources.ResourceManager, typeof(BenchmarkDotNetAnalyzerResources));
1011

11-
public static INamedTypeSymbol GetBenchmarkAttributeTypeSymbol(Compilation compilation) => compilation.GetTypeByMetadataName("BenchmarkDotNet.Attributes.BenchmarkAttribute");
12+
public static INamedTypeSymbol? GetBenchmarkAttributeTypeSymbol(Compilation compilation) => compilation.GetTypeByMetadataName("BenchmarkDotNet.Attributes.BenchmarkAttribute");
1213

1314
public static bool AttributeListsContainAttribute(string attributeName, Compilation compilation, SyntaxList<AttributeListSyntax> attributeLists, SemanticModel semanticModel) => AttributeListsContainAttribute(compilation.GetTypeByMetadataName(attributeName), attributeLists, semanticModel);
1415

15-
public static bool AttributeListsContainAttribute(INamedTypeSymbol attributeTypeSymbol, SyntaxList<AttributeListSyntax> attributeLists, SemanticModel semanticModel)
16+
public static bool AttributeListsContainAttribute(INamedTypeSymbol? attributeTypeSymbol, SyntaxList<AttributeListSyntax> attributeLists, SemanticModel semanticModel)
1617
{
1718
if (attributeTypeSymbol == null)
1819
{
@@ -41,7 +42,7 @@ public static bool AttributeListsContainAttribute(INamedTypeSymbol attributeType
4142

4243
public static ImmutableArray<AttributeSyntax> GetAttributes(string attributeName, Compilation compilation, SyntaxList<AttributeListSyntax> attributeLists, SemanticModel semanticModel) => GetAttributes(compilation.GetTypeByMetadataName(attributeName), attributeLists, semanticModel);
4344

44-
public static ImmutableArray<AttributeSyntax> GetAttributes(INamedTypeSymbol attributeTypeSymbol, SyntaxList<AttributeListSyntax> attributeLists, SemanticModel semanticModel)
45+
public static ImmutableArray<AttributeSyntax> GetAttributes(INamedTypeSymbol? attributeTypeSymbol, SyntaxList<AttributeListSyntax> attributeLists, SemanticModel semanticModel)
4546
{
4647
var attributesBuilder = ImmutableArray.CreateBuilder<AttributeSyntax>();
4748

src/BenchmarkDotNet.Analyzers/AnalyzerReleases.Unshipped.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ BDN1003 | Usage | Error | BDN1003_General_BenchmarkClass_ClassMustBePubli
1212
BDN1004 | Usage | Error | BDN1004_General_BenchmarkClass_ClassMustBeNonStatic
1313
BDN1005 | Usage | Error | BDN1005_General_BenchmarkClass_ClassMustBeNonAbstract
1414
BDN1006 | Usage | Error | BDN1006_General_BenchmarkClass_ClassMustBeNonGeneric
15-
BDN1007 | Usage | Error | BDN1007_General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustHaveTypeParameters
15+
BDN1007 | Usage | Error | BDN1007_General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustBeGeneric
1616
BDN1008 | Usage | Error | BDN1008_General_BenchmarkClass_GenericTypeArgumentsAttributeMustHaveMatchingTypeParameterCount
1717
BDN1009 | Usage | Error | BDN1009_General_BenchmarkClass_ClassMustBeUnsealed
1818
BDN1010 | Usage | Error | BDN1010_General_BenchmarkClass_OnlyOneMethodCanBeBaseline

src/BenchmarkDotNet.Analyzers/BenchmarkDotNetAnalyzerResources.Designer.cs

Lines changed: 58 additions & 63 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/BenchmarkDotNet.Analyzers/BenchmarkDotNetAnalyzerResources.resx

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -129,29 +129,26 @@
129129
<data name="General_BenchmarkClass_ClassMustBeNonStatic_Description" xml:space="preserve">
130130
<value>A benchmark class must be an instance class</value>
131131
</data>
132-
<data name="General_BenchmarkClass_ClassMustBeNonGeneric_Description" xml:space="preserve">
133-
<value>A benchmark class not annotated with the [GenericTypeArguments] attribute must be non-generic</value>
134-
</data>
135-
<data name="General_BenchmarkClass_ClassMustBeNonAbstract_Description" xml:space="preserve">
136-
<value>A benchmark class must be non-abstract</value>
132+
<data name="General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustBeNonAbstract_Description" xml:space="preserve">
133+
<value>A benchmark class annotated with the [GenericTypeArguments] attribute must be non-abstract</value>
137134
</data>
138135
<data name="General_BenchmarkClass_ClassMustBeNonStatic_MessageFormat" xml:space="preserve">
139136
<value>Benchmark class '{0}' cannot be static</value>
140137
</data>
141-
<data name="General_BenchmarkClass_ClassMustBeNonAbstract_MessageFormat" xml:space="preserve">
138+
<data name="General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustBeNonAbstract_MessageFormat" xml:space="preserve">
142139
<value>Benchmark class '{0}' cannot be abstract</value>
143140
</data>
144-
<data name="General_BenchmarkClass_ClassMustBeNonGeneric_MessageFormat" xml:space="preserve">
145-
<value>Benchmark class '{0}' cannot be generic</value>
141+
<data name="General_BenchmarkClass_GenericClassMustBeAbstractOrAnnotatedWithAGenericTypeArgumentsAttribute_MessageFormat" xml:space="preserve">
142+
<value>Benchmark class '{0}' cannot be generic unless declared as abstract or annotated with a [GenericTypeArguments] attribute</value>
146143
</data>
147144
<data name="General_BenchmarkClass_ClassMustBeNonStatic_Title" xml:space="preserve">
148145
<value>Benchmark classes must be non-static</value>
149146
</data>
150-
<data name="General_BenchmarkClass_ClassMustBeNonAbstract_Title" xml:space="preserve">
151-
<value>Benchmark classes must be non-abstract</value>
147+
<data name="General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustBeNonAbstract_Title" xml:space="preserve">
148+
<value>Benchmark classes annotated with the [GenericTypeArguments] attribute must be non-abstract</value>
152149
</data>
153-
<data name="General_BenchmarkClass_ClassMustBeNonGeneric_Title" xml:space="preserve">
154-
<value>Benchmark classes not annotated with the [GenericTypeArguments] attribute must be non-generic</value>
150+
<data name="General_BenchmarkClass_GenericClassMustBeAbstractOrAnnotatedWithAGenericTypeArgumentsAttribute_Title" xml:space="preserve">
151+
<value>Benchmark classes can only be generic if they're either abstract or annotated with a [GenericTypeArguments] attribute</value>
155152
</data>
156153
<data name="General_BenchmarkClass_ClassMustBePublic_Description" xml:space="preserve">
157154
<value>A benchmark class must be public</value>
@@ -180,7 +177,7 @@
180177
<data name="General_BenchmarkClass_GenericTypeArgumentsAttributeMustHaveMatchingTypeParameterCount_Description" xml:space="preserve">
181178
<value>The number of type arguments passed to the [GenericTypeArguments] attribute must match the number of type parameters on the targeted benchmark class</value>
182179
</data>
183-
<data name="General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustHaveTypeParameters_Description" xml:space="preserve">
180+
<data name="General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustBeGeneric_Description" xml:space="preserve">
184181
<value>A benchmark class annotated with the [GenericTypeArguments] attribute must be generic, having between one to three type parameters</value>
185182
</data>
186183
<data name="General_BenchmarkClass_MethodMustBePublic_MessageFormat" xml:space="preserve">
@@ -192,7 +189,7 @@
192189
<data name="General_BenchmarkClass_GenericTypeArgumentsAttributeMustHaveMatchingTypeParameterCount_MessageFormat" xml:space="preserve">
193190
<value>Expected {0} type argument{1} as declared on the benchmark class '{2}', but found {3}. Update the attribute usage or the type parameter list of the class declaration to match.</value>
194191
</data>
195-
<data name="General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustHaveTypeParameters_MessageFormat" xml:space="preserve">
192+
<data name="General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustBeGeneric_MessageFormat" xml:space="preserve">
196193
<value>Benchmark class '{0}' must be generic</value>
197194
</data>
198195
<data name="General_BenchmarkClass_OnlyOneMethodCanBeBaseline_MessageFormat" xml:space="preserve">
@@ -207,7 +204,7 @@
207204
<data name="General_BenchmarkClass_GenericTypeArgumentsAttributeMustHaveMatchingTypeParameterCount_Title" xml:space="preserve">
208205
<value>Number of type arguments passed to the [GenericTypeArguments] attribute must match the number of type parameters on the targeted benchmark class</value>
209206
</data>
210-
<data name="General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustHaveTypeParameters_Title" xml:space="preserve">
207+
<data name="General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustBeGeneric_Title" xml:space="preserve">
211208
<value>Benchmark classes annotated with the [GenericTypeArguments] attribute must be generic</value>
212209
</data>
213210
<data name="General_BenchmarkClass_OnlyOneMethodCanBeBaseline_Title" xml:space="preserve">

src/BenchmarkDotNet.Analyzers/BenchmarkRunner/RunAnalyzer.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,17 @@ public override void Initialize(AnalysisContext analysisContext)
4040

4141
private static void Analyze(SyntaxNodeAnalysisContext context)
4242
{
43-
if (!(context.Node is InvocationExpressionSyntax invocationExpression))
43+
if (context.Node is not InvocationExpressionSyntax invocationExpression)
4444
{
4545
return;
4646
}
4747

48-
if (!(invocationExpression.Expression is MemberAccessExpressionSyntax memberAccessExpression))
48+
if (invocationExpression.Expression is not MemberAccessExpressionSyntax memberAccessExpression)
4949
{
5050
return;
5151
}
5252

53-
if (!(memberAccessExpression.Expression is IdentifierNameSyntax typeIdentifier))
53+
if (memberAccessExpression.Expression is not IdentifierNameSyntax typeIdentifier)
5454
{
5555
return;
5656
}
@@ -61,7 +61,7 @@ private static void Analyze(SyntaxNodeAnalysisContext context)
6161
return;
6262
}
6363

64-
if (!(memberAccessExpression.Name is GenericNameSyntax genericMethod))
64+
if (memberAccessExpression.Name is not GenericNameSyntax genericMethod)
6565
{
6666
return;
6767
}

src/BenchmarkDotNet.Analyzers/DiagnosticIds.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ public static class DiagnosticIds
77
public const string General_BenchmarkClass_MethodMustBeNonGeneric = "BDN1002";
88
public const string General_BenchmarkClass_ClassMustBePublic = "BDN1003";
99
public const string General_BenchmarkClass_ClassMustBeNonStatic = "BDN1004";
10-
public const string General_BenchmarkClass_ClassMustBeNonAbstract = "BDN1005";
11-
public const string General_BenchmarkClass_ClassMustBeNonGeneric = "BDN1006";
12-
public const string General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustHaveTypeParameters = "BDN1007";
10+
public const string General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustBeNonAbstract = "BDN1005";
11+
public const string General_BenchmarkClass_GenericClassMustBeAbstractOrAnnotatedWithAGenericTypeArgumentsAttribute = "BDN1006";
12+
public const string General_BenchmarkClass_ClassWithGenericTypeArgumentsAttributeMustBeGeneric = "BDN1007";
1313
public const string General_BenchmarkClass_GenericTypeArgumentsAttributeMustHaveMatchingTypeParameterCount = "BDN1008";
1414
public const string General_BenchmarkClass_ClassMustBeUnsealed = "BDN1009";
1515
public const string General_BenchmarkClass_OnlyOneMethodCanBeBaseline = "BDN1010";

0 commit comments

Comments
 (0)