File: RenderTreeBuilder\RenderTreeBuilderAnalyzer.cs
Web Access
Project: src\src\Framework\AspNetCoreAnalyzers\src\Analyzers\Microsoft.AspNetCore.App.Analyzers.csproj (Microsoft.AspNetCore.App.Analyzers)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Immutable;
using Microsoft.AspNetCore.App.Analyzers.Infrastructure;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
 
namespace Microsoft.AspNetCore.Analyzers.RenderTreeBuilder;
 
using WellKnownType = WellKnownTypeData.WellKnownType;
 
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public partial class RenderTreeBuilderAnalyzer : DiagnosticAnalyzer
{
    private const int SequenceParameterOrdinal = 0;
    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.DoNotUseNonLiteralSequenceNumbers);
 
    public override void Initialize(AnalysisContext context)
    {
        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
        context.EnableConcurrentExecution();
        context.RegisterCompilationStartAction(context =>
        {
            var compilation = context.Compilation;
            var wellKnownTypes = WellKnownTypes.GetOrCreate(compilation);
 
            context.RegisterOperationAction(context =>
            {
                var invocation = (IInvocationOperation)context.Operation;
 
                if (!IsRenderTreeBuilderMethodWithSequenceParameter(wellKnownTypes, invocation.TargetMethod))
                {
                    return;
                }
 
                foreach (var argument in invocation.Arguments)
                {
                    if (argument.Parameter?.Ordinal == SequenceParameterOrdinal)
                    {
                        if (!argument.Value.Syntax.IsKind(SyntaxKind.NumericLiteralExpression))
                        {
                            context.ReportDiagnostic(Diagnostic.Create(
                                DiagnosticDescriptors.DoNotUseNonLiteralSequenceNumbers,
                                argument.Syntax.GetLocation(),
                                argument.Syntax.ToString()));
                        }
 
                        break;
                    }
                }
 
            }, OperationKind.Invocation);
        });
    }
 
    private static bool IsRenderTreeBuilderMethodWithSequenceParameter(WellKnownTypes wellKnownTypes, IMethodSymbol targetMethod)
        => SymbolEqualityComparer.Default.Equals(wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Components_Rendering_RenderTreeBuilder), targetMethod.ContainingType)
        && targetMethod.Parameters.Length > SequenceParameterOrdinal
        && targetMethod.Parameters[SequenceParameterOrdinal].Name == "sequence";
}