Skip to content

Commit

Permalink
New constant expected analyzer (#5766)
Browse files Browse the repository at this point in the history
* Add ConstantExpectedAnalyzer

Co-authored-by: Robin Lindner <robin.lindner1@t-online.de>
Co-authored-by: Robin Lindner <robin@deeprobin.de>
  • Loading branch information
3 people authored Nov 16, 2022
1 parent 0ba720f commit ebaa318
Show file tree
Hide file tree
Showing 26 changed files with 3,310 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.NetCore.Analyzers.Performance;

namespace Microsoft.NetCore.CSharp.Analyzers.Performance
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class CSharpConstantExpectedAnalyzer : ConstantExpectedAnalyzer
{
private static readonly CSharpDiagnosticHelper s_diagnosticHelper = new();
private static readonly IdentifierNameSyntax s_constantExpectedIdentifier = (IdentifierNameSyntax)SyntaxFactory.ParseName(ConstantExpected);
private static readonly IdentifierNameSyntax s_constantExpectedAttributeIdentifier = (IdentifierNameSyntax)SyntaxFactory.ParseName(ConstantExpectedAttribute);

protected override DiagnosticHelper Helper => s_diagnosticHelper;

protected override void RegisterAttributeSyntax(CompilationStartAnalysisContext context, ConstantExpectedContext constantExpectedContext)
{
context.RegisterSyntaxNodeAction(context => OnAttributeNode(context, constantExpectedContext), SyntaxKind.Attribute);
}

private void OnAttributeNode(SyntaxNodeAnalysisContext context, ConstantExpectedContext constantExpectedContext)
{
var attributeSyntax = (AttributeSyntax)context.Node;
var attributeName = attributeSyntax.Name;
if (!attributeName.IsEquivalentTo(s_constantExpectedIdentifier) && !attributeName.IsEquivalentTo(s_constantExpectedAttributeIdentifier))
{
return;
}

if (attributeSyntax.Parent.Parent is ParameterSyntax parameter)
{
var parameterSymbol = context.SemanticModel.GetDeclaredSymbol(parameter);
OnParameterWithConstantExpectedAttribute(parameterSymbol, constantExpectedContext, context.ReportDiagnostic);
}
}

private sealed class CSharpDiagnosticHelper : DiagnosticHelper
{
private readonly IdentifierNameSyntax _constantExpectedMinIdentifier = (IdentifierNameSyntax)SyntaxFactory.ParseName(ConstantExpectedMin);
private readonly IdentifierNameSyntax _constantExpectedMaxIdentifier = (IdentifierNameSyntax)SyntaxFactory.ParseName(ConstantExpectedMax);

public override Location? GetMaxLocation(SyntaxNode attributeNode) => GetArgumentLocation(attributeNode, _constantExpectedMaxIdentifier);

public override Location? GetMinLocation(SyntaxNode attributeNode) => GetArgumentLocation(attributeNode, _constantExpectedMinIdentifier);

private static Location? GetArgumentLocation(SyntaxNode attributeNode, IdentifierNameSyntax targetNameSyntax)
{
var attributeSyntax = (AttributeSyntax)attributeNode;
if (attributeSyntax.ArgumentList is null)
{
return null;
}
var targetArg = attributeSyntax.ArgumentList.Arguments.FirstOrDefault(arg => arg.NameEquals.Name.IsEquivalentTo(targetNameSyntax, true));
return targetArg?.GetLocation();
}
}
}
}
;
7 changes: 7 additions & 0 deletions src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
; Please do not edit this file manually, it should only be updated through code fix application.

### New Rules

Rule ID | Category | Severity | Notes
--------|----------|----------|-------
CA1856 | Performance | Error | ConstantExpectedAnalyzer, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1856)
CA1857 | Performance | Warning | ConstantExpectedAnalyzer, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1857)
Original file line number Diff line number Diff line change
Expand Up @@ -1864,6 +1864,42 @@
<data name="UsesPreviewTypeParameterMessage" xml:space="preserve">
<value>'{0}' uses the preview type '{1}' and needs to opt into preview features. See {2} for more information.</value>
</data>
<data name="ConstantExpectedApplicationTitle" xml:space="preserve">
<value>Incorrect usage of ConstantExpected attribute</value>
</data>
<data name="ConstantExpectedApplicationDescription" xml:space="preserve">
<value>ConstantExpected attribute is not applied correctly on the parameter.</value>
</data>
<data name="ConstantExpectedUsageTitle" xml:space="preserve">
<value>A constant is expected for the parameter</value>
</data>
<data name="ConstantExpectedUsageDescription" xml:space="preserve">
<value>The parameter expects a constant for optimal performance.</value>
</data>
<data name="ConstantExpectedNotSupportedMessage" xml:space="preserve">
<value>The '{0}' type is not supported for ConstantExpected attribute</value>
</data>
<data name="ConstantExpectedIncompatibleConstantTypeMessage" xml:space="preserve">
<value>The '{0}' value is not compatible with parameter type of '{1}'</value>
</data>
<data name="ConstantExpectedInvalidBoundsMessage" xml:space="preserve">
<value>The '{0}' value does not fit within the parameter value bounds of '{1}' to '{2}'</value>
</data>
<data name="ConstantExpectedInvertedRangeMessage" xml:space="preserve">
<value>The Min and Max values are inverted</value>
</data>
<data name="ConstantExpectedOutOfBoundsMessage" xml:space="preserve">
<value>The constant does not fit within the value bounds of '{0}' to '{1}'</value>
</data>
<data name="ConstantExpectedInvalidMessage" xml:space="preserve">
<value>The constant is not of the same '{0}' type as the parameter</value>
</data>
<data name="ConstantExpectedNotConstantMessage" xml:space="preserve">
<value>The argument should be a constant for optimal performance</value>
</data>
<data name="ConstantExpectedAttributExpectedMessage" xml:space="preserve">
<value>The ConstantExpected attribute is required for the parameter due to the parent method annotation</value>
</data>
<data name="SpecifyCultureForToLowerAndToUpperTitle" xml:space="preserve">
<value>Specify a culture or use an invariant version</value>
</data>
Expand Down
Loading

0 comments on commit ebaa318

Please sign in to comment.