Safeguard
Developer Tools•

How do you write a Roslyn analyzer for a custom .NET code check?

A Roslyn analyzer derives from DiagnosticAnalyzer, registers a syntax action, reports a diagnostic, and gets unit tests. Steps and severity setup in .NET.

Safeguard Security Team
4 min read

A Roslyn analyzer is a class that derives from DiagnosticAnalyzer, carries a DiagnosticAnalyzer attribute naming its language, registers actions in Initialize, and reports diagnostics when code matches. Package it as NuGet so it applies per project, then set its severity in an EditorConfig file.

What Microsoft's tutorial shows

Microsoft's analyzer tutorial builds a "Make Const" analyzer with a code fix, starting from the Analyzer with Code Fix template in Visual Studio. It states that every diagnostic analyzer must provide the attribute describing the language it works on and must derive, directly or indirectly, from DiagnosticAnalyzer. Actions are registered in your override of Initialize, and the tutorial changes the registration to a syntax node action for local declaration statements.

You need the .NET Compiler Platform SDK installed through the Visual Studio Installer, where it is an optional component.

Steps

  1. Create the project from the analyzer template.
  2. Define the diagnostic: an id, a title, a message format and a default severity.
  3. In Initialize, register an action for the syntax kind you care about.
  4. In the action, inspect the node and call ReportDiagnostic when it matches.
  5. Optionally add a code fix so developers can accept a recommendation in one step.
  6. Write unit tests with sample code that should and should not be flagged. The tutorial finishes by improving the analysis through unit tests.
  7. Package it and add it to the projects that need it.

Installing and scoping

Microsoft's documentation describes NuGet as the preferred way to install an external analyzer. A NuGet analyzer applies only to the project where it is installed, while an analyzer installed as a Visual Studio extension applies to any solution you open. For a team rule, choose NuGet so the rule travels with the repository and runs in CI as well as in the editor.

Severity levels

Each analyzer rule has a default severity that you can customize. The documented levels are Error, Warning, Suggestion, Silent, None and Default. In an EditorConfig file the syntax is dotnet_diagnostic followed by the rule id and severity, for example setting a rule id to error under a section for C# files. Because the setting lives in a file in the repository, severity changes are code reviewed.

SeverityTypical use for a new custom check
SuggestionFirst rollout, visible in the editor only
WarningShows in builds, does not fail them
ErrorFails the build once existing violations are fixed
NoneTurned off while you investigate noise

Practical advice

  • Keep one diagnostic per concern. A single analyzer that reports five different things is hard to tune.
  • Give each diagnostic a help link to a short internal page that explains the problem and the fix.
  • Test on real project code before raising severity, since sample tests rarely cover every coding style.

Quick check

Do I need a code fix?

No. A code fix is optional. It helps adoption when the safe replacement is mechanical, but an analyzer is valid without one.

Where should the severity setting live?

In an EditorConfig file in the repository, so changes are reviewed and apply to every developer and to CI.

Safeguard's scanning covers dependencies and SBOMs, and its reachability analysis helps show which findings your code can actually call. You can run a free scan on a repository.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.