C# Analyzers and Code Fixes: Building Developer Tools
Maria

Maria @chakewitz

About: I’m a code whisperer :) A software developer with a decade of experience building websites, web apps, and the occasional Frankenstein monster made entirely of JavaScript and caffeine

Joined:
May 27, 2025

C# Analyzers and Code Fixes: Building Developer Tools

Publish Date: Jun 26
0 0

C# Analyzers and Code Fixes: Building Developer Tools

In the world of software development, clean and consistent code is more than just a luxury—it's a necessity. Whether you're working on a small personal project or contributing to a large enterprise application, adhering to coding standards and automating improvements can save countless hours of debugging and refactoring. But what if you could enforce these standards at compile time and even suggest or apply fixes automatically? Welcome to the world of C# Analyzers and Code Fixes.

In this blog post, we'll dive deep into creating custom Roslyn analyzers and code fixes. By the end, you'll have a solid understanding of how to extend your toolchain with custom developer tools that elevate your team's productivity and code quality. Let's get started!


What Are C# Analyzers and Code Fixes?

Imagine you’re writing a novel, and your editor not only points out grammatical errors but also suggests better phrasing. Roslyn analyzers are like that editor for your C# code. They analyze your codebase in real-time, identify issues, and offer suggestions to improve it. Code fixes take this one step further, allowing developers to automatically apply these suggestions with a single click or keystroke.

Why Use C# Analyzers and Code Fixes?

  • Enforce Coding Standards: Ensure that your team adheres to best practices and your project's coding guidelines.
  • Automate Repetitive Tasks: Save time by automating common refactorings and improvements.
  • Improve Code Quality: Catch potential issues early, reducing bugs and technical debt.
  • Empower Developers: Provide actionable suggestions that help developers learn and grow.

Getting Started with Roslyn

Roslyn is the open-source .NET compiler platform that powers C# and VB.NET. It provides APIs to analyze, modify, and generate code. This makes it the foundation for creating custom analyzers and code fixes.

To build a custom analyzer, you'll need to create a Visual Studio extension (VSIX) project. Follow these steps:

Step 1: Set Up Your Development Environment

  1. Install Visual Studio: Ensure you have the latest version of Visual Studio with the .NET desktop development workload installed.
  2. Install the Analyzer Template: Install the Analyzer with Code Fix project template from the Visual Studio Marketplace.

Step 2: Create a New Analyzer Project

  1. Open Visual Studio and create a new project.
  2. Search for the Analyzer with Code Fix (.NET Standard) template.
  3. Name your project and solution (e.g., MyCustomAnalyzer).

This template provides a basic scaffold for an analyzer and a code fix. Let’s explore how to customize it.


Writing Your First Analyzer

An analyzer inspects your code for specific patterns or issues. Let’s create an analyzer that flags the use of var and suggests replacing it with an explicit type.

Step 1: Define the Diagnostic Descriptor

The DiagnosticDescriptor defines the metadata for your analyzer, such as the ID, title, message, and severity.

private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(
    id: "MY001",
    title: "Avoid using 'var'",
    messageFormat: "Consider replacing 'var' with the explicit type",
    category: "Style",
    defaultSeverity: DiagnosticSeverity.Warning,
    isEnabledByDefault: true);
Enter fullscreen mode Exit fullscreen mode

Step 2: Implement the Analyzer Logic

Override the Initialize method to register your analyzer. In this case, we’ll analyze variable declarations.

public override void Initialize(AnalysisContext context)
{
    context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
    context.EnableConcurrentExecution();
    context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.VariableDeclaration);
}

private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
    var variableDeclaration = (VariableDeclarationSyntax)context.Node;

    // Check if the variable type is 'var'
    if (variableDeclaration.Type.IsVar)
    {
        var diagnostic = Diagnostic.Create(Rule, variableDeclaration.GetLocation());
        context.ReportDiagnostic(diagnostic);
    }
}
Enter fullscreen mode Exit fullscreen mode

Explanation

  1. SyntaxNodeAction: Registers a callback for specific syntax nodes. Here, we’re targeting VariableDeclarationSyntax.
  2. IsVar: Checks if the variable type is var.
  3. ReportDiagnostic: Reports a diagnostic at the relevant code location.

Adding a Code Fix

Now that we’ve flagged the use of var, let’s implement a code fix to replace it with the explicit type.

Step 1: Implement the Code Fix

Override the RegisterCodeFixesAsync method in your CodeFixProvider class.

public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
    var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

    // Find the diagnostic and the corresponding node
    var diagnostic = context.Diagnostics.First();
    var diagnosticSpan = diagnostic.Location.SourceSpan;

    var declaration = root.FindNode(diagnosticSpan) as VariableDeclarationSyntax;

    // Register the code fix
    context.RegisterCodeFix(
        CodeAction.Create(
            title: "Use explicit type",
            createChangedDocument: c => ReplaceVarWithExplicitTypeAsync(context.Document, declaration, c),
            equivalenceKey: "Use explicit type"),
        diagnostic);
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Replace var with the Explicit Type

Here’s the logic for performing the replacement:

private async Task<Document> ReplaceVarWithExplicitTypeAsync(
    Document document,
    VariableDeclarationSyntax declaration,
    CancellationToken cancellationToken)
{
    var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
    var typeInfo = semanticModel.GetTypeInfo(declaration.Type);

    // Get the explicit type name
    var explicitTypeName = typeInfo.ConvertedType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);

    // Replace 'var' with the explicit type
    var explicitType = SyntaxFactory.ParseTypeName(explicitTypeName)
        .WithLeadingTrivia(declaration.Type.GetLeadingTrivia())
        .WithTrailingTrivia(declaration.Type.GetTrailingTrivia());

    var newDeclaration = declaration.WithType(explicitType);

    var root = await document.GetSyntaxRootAsync(cancellationToken);
    var newRoot = root.ReplaceNode(declaration, newDeclaration);

    return document.WithSyntaxRoot(newRoot);
}
Enter fullscreen mode Exit fullscreen mode

Common Pitfalls and How to Avoid Them

1. Performance Issues

  • Pitfall: Analyzers can slow down the IDE if not optimized.
  • Solution: Use context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None) to skip analyzing generated code. Use EnableConcurrentExecution to allow parallel analysis.

2. Overly Broad Rules

  • Pitfall: Analyzers that flag too many irrelevant scenarios frustrate developers.
  • Solution: Ensure your rules are specific and only target genuine issues.

3. Complex Fixes

  • Pitfall: Code fixes that are hard to understand or apply automatically can confuse users.
  • Solution: Keep fixes simple and intuitive. Provide clear explanations in the diagnostic message.

Key Takeaways and Next Steps

  • C# Analyzers and Code Fixes are powerful tools for enforcing coding standards and automating repetitive tasks.
  • Using Roslyn, you can analyze and modify code at compile time.
  • Start small with simple analyzers and fixes, and gradually expand their functionality.
  • Focus on optimizing performance and usability to ensure your tools are helpful, not intrusive.

Next Steps:

  1. Explore the Roslyn GitHub repository for more examples and documentation.
  2. Experiment with creating analyzers for your team's specific needs.
  3. Share your analyzers as NuGet packages or Visual Studio extensions.

By creating custom analyzers and code fixes, you're not just writing code—you’re empowering your team, improving code quality, and making development a more enjoyable experience. So, grab your keyboard and start building your first analyzer today!

Comments 0 total

    Add comment