Infra, Ops & WorkflowSûr100100/100

Analyzer Codefix (.NET)

Create or modify Roslyn IDE analyzers, code fixes, and code refactorings. Use when: adding a new IDE diagnostic (IDE0xxx), implementing a CodeFixProvider, implementing a CodeRefactoringProvider, writing analyzer/fixer tests, or working with AbstractBuiltInCodeStyleDiagnosticAnalyzer. Also use for: diagnostic analyzer, code action, FixAllProvider, TestInRegularAndScriptAsync, TestMissingInRegularAndScriptAsync.

ou envoie-le directement à ton agent.

Installer dans ton projet

$ curl -fsSL https://arboristhree.xyz/cli/install-skill.mjs -o /tmp/arboris-install-skill.mjs && node /tmp/arboris-install-skill.mjs analyzer-codefix__dotnet-dotnet__src-roslyn-github-skills-a45acfd1f5bf
.NET
dotnet/dotnet
Contenu à copier
---
name: analyzer-codefix
description: "Create or modify Roslyn IDE analyzers, code fixes, and code refactorings. Use when: adding a new IDE diagnostic (IDE0xxx), implementing a CodeFixProvider, implementing a CodeRefactoringProvider, writing analyzer/fixer tests, or working with AbstractBuiltInCodeStyleDiagnosticAnalyzer. Also use for: diagnostic analyzer, code action, FixAllProvider, TestInRegularAndScriptAsync, TestMissingInRegularAndScriptAsync."
metadata:
  origin: .NET
---

# Roslyn Analyzer, Code Fix & Code Refactoring Patterns

## When to Use

- Adding a new IDE analyzer (IDE0xxx diagnostic)
- Implementing or modifying a `CodeFixProvider`
- Implementing or modifying a `CodeRefactoringProvider`
- Writing tests for analyzers, code fixes, or refactorings
- Working with `AbstractBuiltInCodeStyleDiagnosticAnalyzer`

## IDE Diagnostic IDs

All IDE diagnostics use `IDE0xxx` format, defined as constants in `src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs`. Always reference these constants rather than hardcoding string IDs.

## Analyzer Patterns

### Code Style Analyzer (preferred for IDE diagnostics)

Inherit from `AbstractBuiltInCodeStyleDiagnosticAnalyzer` — not raw `DiagnosticAnalyzer`:

```csharp
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class CSharpUseXxxDiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer
{
    public CSharpUseXxxDiagnosticAnalyzer()
        : base(IDEDiagnosticIds.UseXxxDiagnosticId,
               EnforceOnBuildValues.UseXxx,
               option: CSharpCodeStyleOptions.PreferXxx,
               title: new LocalizableResourceString(
                   nameof(AnalyzersResources.Use_xxx),
                   AnalyzersResources.ResourceManager,
                   typeof(AnalyzersResources))) { }

    protected override void InitializeWorker(AnalysisContext context)
        => context.RegisterCompilationStartAction(context =>
            context.RegisterOperationAction(AnalyzeOperation, OperationKind.Invocation));
}
```

### Non-Style Analyzer

Use raw `DiagnosticAnalyzer` with a `DiagnosticDescriptor`:

```csharp
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class MyAnalyzer : DiagnosticAnalyzer
{
    private static readonly DiagnosticDescriptor s_rule = new(
        "IDE0xxx", "Title", "Message format", "Category",
        DiagnosticSeverity.Warning, isEnabledByDefault: true);

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
        => ImmutableArray.Create(s_rule);

    public override void Initialize(AnalysisContext context)
    {
        context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration);
    }
}
```

## CodeFixProvider Pattern

```csharp
[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.UseXxx), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class CSharpUseXxxCodeFixProvider() : CodeFixProvider
{
    public override ImmutableArray<string> FixableDiagnosticIds
        => [IDEDiagnosticIds.UseXxxDiagnosticId];

    // Always provide FixAllProvider — typically BatchFixer
    public override FixAllProvider? GetFixAllProvider()
        => WellKnownFixAllProviders.BatchFixer;

    public override async Task RegisterCodeFixesAsync(CodeFixContext context)
    {
        var diagnostic = context.Diagnostics.First();
        context.RegisterCodeFix(
            CodeAction.Create(
                title,
                c => FixAsync(context.Document, diagnostic, c),
                equivalenceKey: nameof(AnalyzersResources.Use_xxx)),
            diagnostic);
    }
}
```

## CodeRefactoringProvider Pattern

```csharp
[ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.MyRefactoring), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class MyRefactoringProvider() : CodeRefactoringProvider
{
    public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
    {
        // Register refactoring actions via context.RegisterRefactoring(...)
    }
}
```

## EditorConfig / Options Integration

IDE analyzers read user preferences from `.editorconfig` via the options system:
- Options are defined in `CSharpCodeStyleOptions`, `CodeStyleOptions2`, etc.
- Access in analyzers: `context.GetCSharpAnalyzerOptions().PreferXxx`
- Analyzers should respect user-configured severity and enablement

## Resource & Localization

- Error messages and UI strings live in `.resx` files (e.g., `AnalyzersResources.resx`, `FeaturesResources.resx`)
- Reference via generated designer class: `AnalyzersResources.Use_xxx`
- For localizable strings in descriptors: `new LocalizableResourceString(nameof(AnalyzersResources.Use_xxx), AnalyzersResources.ResourceManager, typeof(AnalyzersResources))`
- After modifying `.resx` files, run `dotnet msbuild <path to csproj> /t:UpdateXlf` to update `.xlf` localization files

## Testing

### Test Base Class

For analyzer + fixer pairs, inherit from `AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor`:

```csharp
public sealed class UseXxxTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor
{
    internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
        => (new CSharpUseXxxDiagnosticAnalyzer(), new CSharpUseXxxCodeFixProvider());

    [Fact]
    public async Task TestBasicCase()
    {
        await TestInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    [|var x = 1;|]
                }
            }
            """,
            """
            class C
            {
                void M()
                {
                    int x = 1;
                }
            }
            """);
    }

    [Fact]
    public async Task TestNoFixWhenAlreadyCorrect()
    {
        await TestMissingInRegularAndScriptAsync(
            """
            class C
            {
                void M()
                {
                    int x = 1;
                }
            }
            """);
    }
}
```

### Test Markup Syntax
- `[|...|]` — diagnostic span (the code the diagnostic highlights)
- `{|DiagnosticId:...|}` — named span with specific diagnostic ID
- `$$` — cursor position marker (single instance only)

### Verifier-Based Tests (for standalone analyzers)

```csharp
await new VerifyCS.Test
{
    TestCode = source,
    FixedCode = fixedSource,
    ExpectedDiagnostics = { VerifyCS.Diagnostic("IDE0xxx").WithSpan(5, 9, 5, 20) },
}.RunAsync();
```

### Test Conventions
- Use `TestInRegularAndScriptAsync` to cover both regular and script contexts
- Use `TestMissingInRegularAndScriptAsync` to verify no fix is offered
- Prefer raw string literals (`"""..."""`) over verbatim strings (`@"..."`) for test source code
- Keep tests focused — avoid unnecessary intermediary assertions

## Checklist for New Analyzer + Code Fix

1. Add diagnostic ID constant to `IDEDiagnosticIds.cs`
2. Add resource strings to the appropriate `.resx` file
3. Run `dotnet msbuild <path to csproj> /t:UpdateXlf` for localization
4. Implement analyzer (inherit `AbstractBuiltInCodeStyleDiagnosticAnalyzer` for code style)
5. Implement code fix with `FixAllProvider`
6. Write tests inheriting `AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor`
7. Test both "fix applies" and "fix does not apply" cases
Colle ce Markdown dans ton agent ou utilise les boutons ci-dessus pour l’écrire dans ton projet.

Ce que fait Analyzer Codefix (.NET)

Adding a new IDE analyzer (IDE0xxx diagnostic)
Implementing or modifying a `CodeFixProvider`
Implementing or modifying a `CodeRefactoringProvider`
Writing tests for analyzers, code fixes, or refactorings

Comment utiliser Analyzer Codefix (.NET)

1
Copie le prompt
Un clic copie le prompt packagé (ou l'envoie à ton agent).
2
L'agent installe le skill
Il ajoute le SKILL.md et ses ressources à ton projet.
3
Activation automatique
Le skill s'active dès que le contexte correspond.

Déclencheurs pour Analyzer Codefix (.NET)

Dis simplement à ton agent quelque chose comme :

Applique le skill analyzer-codefix__dotnet-dotnet__src-roslyn-github-skills-a45acfd1f5bf à cette tâche
Utilise analyzer-codefix__dotnet-dotnet__src-roslyn-github-skills-a45acfd1f5bf pour améliorer cette implémentation
Passe en revue ce sujet avec analyzer-codefix__dotnet-dotnet__src-roslyn-github-skills-a45acfd1f5bf

Skills liés à Analyzer Codefix (.NET)

Add CLI Command (.NET)
Add or change a dotnet CLI command, subcommand, or option across the relevant CLI projects. USE FOR: adding or changing a dotnet CLI command/subcommand, adding a new Option<T> or Argument<T>, registering a subcommand in the command tree, changing an option's help description or a command's runtime message, wiring a command parser, or updating --help output.
Add Dotnet Aot Command (.NET)
Add, enable, or review a dotnet CLI command or feature in the Native AOT CLI (src/Cli/dotnet-aot) and prove its compatibility. USE FOR: migrating a command or option to AOT, reviewing an AOT migration PR, defining conservative eligibility and managed fallback, changing AotSourceFiles.props or AotDependencies.props, validating AOT/managed parity, NativeAOT-publishing tests, checking binary-size impact, or using the dn harness and separated SDK layout. DO NOT USE FOR: resolving IL trim/AOT analyzer warnings alone (use dotnet-aot-compat), running dotnet.Tests incrementally (use incremental-test), or pure managed CLI work.
Add Net Analyzer (.NET)
Add, port, or change a .NET code analysis rule (CA####) under src/Microsoft.CodeAnalysis.NetAnalyzers. USE FOR: implementing a new CA analyzer and its code fixer, porting a rule or PR from the retired dotnet/roslyn-analyzers repo, allocating a diagnostic ID from DiagnosticCategoryAndIdRanges.txt, choosing RuleLevel/severity/category, wiring resx + xlf strings, recording the rule in AnalyzerReleases.Unshipped.md, regenerating the analyzer documentation/sarif files, and writing MSTest analyzer/code-fix tests with the VerifyCS/VerifyVB harness. DO NOT USE FOR: NETSDK#### MSBuild diagnostics (src/Tasks), CS####/BC#### compiler diagnostics or IDE#### analyzers (dotnet/roslyn), or CONTAINER#### diagnostics (src/Containers).