Repository: dotnet/roslyn
File: src/Features/CSharp/Portable/Diagnostics/Analyzers/FileBasedPrograms/FileLevelDirectiveDiagnosticAnalyzer.cs (C#)

Code before:
﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.CodeAnalysis.CodeQuality;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.DotNet.FileBasedPrograms;

namespace Microsoft.CodeAnalysis.FileBasedPrograms;

[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class FileLevelDirectiveDiagnosticAnalyzer()
    : AbstractCodeQualityDiagnosticAnalyzer(
        descriptors: [Rule],
        generatedCodeAnalysisFlags: GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics)
{
    public const string DiagnosticId = "FileBasedPrograms";

    private static readonly DiagnosticDescriptor Rule = CreateDescriptor(
                id: DiagnosticId,
                enforceOnBuild: EnforceOnBuild.Never,
                title: DiagnosticId,
                messageFormat: "{0}",
                hasAnyCodeStyleOption: false,
                isUnnecessary: false,
                isEnabledByDefault: true,
                isConfigurable: false,
                defaultSeverity: DiagnosticSeverity.Error,
                helpLinkUri: "https://learn.microsoft.com/dotnet/csharp/language-reference/preprocessor-directives#file-based-apps");

    public override DiagnosticAnalyzerCategory GetAnalyzerCategory()
        => DiagnosticAnalyzerCategory.SyntaxTreeWithoutSemanticsAnalysis;

    protected override void InitializeWorker(AnalysisContext context)
    {
        context.RegisterSyntaxTreeAction(context =>
        {
            var cancellationToken = context.CancellationToken;
            var tree = context.Tree;
            if (!tree.Options.Features.ContainsKey("FileBasedProgram"))
                return;

            var root = tree.GetRoot(cancellationToken);
            if (!root.ContainsDirectives)

Review comment (suggestion):
Should private static fields follow this convention?
```suggestion
    private static readonly DiagnosticDescriptor s_rule = CreateDescriptor(
```

Code after:
﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.CodeAnalysis.CodeQuality;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.DotNet.FileBasedPrograms;

namespace Microsoft.CodeAnalysis.FileBasedPrograms;

[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class FileLevelDirectiveDiagnosticAnalyzer()
    : AbstractCodeQualityDiagnosticAnalyzer(
        descriptors: [s_descriptor],
        generatedCodeAnalysisFlags: GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics)
{
    public const string DiagnosticId = "FileBasedPrograms";

    private static readonly DiagnosticDescriptor s_descriptor = CreateDescriptor(
                id: DiagnosticId,
                enforceOnBuild: EnforceOnBuild.Never,
                title: DiagnosticId,
                messageFormat: "{0}",
                hasAnyCodeStyleOption: false,
                isUnnecessary: false,
                isEnabledByDefault: true,
                isConfigurable: false,
                defaultSeverity: DiagnosticSeverity.Error,
                helpLinkUri: "https://learn.microsoft.com/dotnet/csharp/language-reference/preprocessor-directives#file-based-apps");

    public override DiagnosticAnalyzerCategory GetAnalyzerCategory()
        => DiagnosticAnalyzerCategory.SyntaxTreeWithoutSemanticsAnalysis;

    protected override void InitializeWorker(AnalysisContext context)
    {
        context.RegisterSyntaxTreeAction(context =>
        {
            var cancellationToken = context.CancellationToken;
            var tree = context.Tree;
            if (!tree.Options.Features.ContainsKey("FileBasedProgram"))
                return;

            var root = tree.GetRoot(cancellationToken);
            if (!root.ContainsDirectives)