From dotnet-skills
Adding analyzer packages to a project. Nullable, trimming, AOT compat analyzers, severity config.
How this skill is triggered — by the user, by Claude, or both
Slash command
/dotnet-skills:dotnet-add-analyzersThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Add and configure .NET code analyzers to an existing project. Covers built-in Roslyn CA rules, nullable reference types enforcement, trimming/AOT compatibility analyzers, and third-party analyzer packages.
Add and configure .NET code analyzers to an existing project. Covers built-in Roslyn CA rules, nullable reference types enforcement, trimming/AOT compatibility analyzers, and third-party analyzer packages.
Prerequisites: Run [skill:dotnet-version-detection] first — analyzer features vary by SDK version. Run [skill:dotnet-project-analysis] to understand the current project layout.
Cross-references: [skill:dotnet-project-structure] for where build props/targets live, [skill:dotnet-scaffold-project] which includes analyzer setup in new projects, [skill:dotnet-editorconfig] for EditorConfig hierarchy/precedence, IDE* code style preferences, naming rules, and global AnalyzerConfig files.
.NET SDK ships built-in analyzers controlled by AnalysisLevel. Configure in Directory.Build.props:
<PropertyGroup>
<AnalysisLevel>latest-all</AnalysisLevel>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
| Value | Behavior |
|---|---|
latest | Default rules only — covers correctness, not style |
latest-minimum | Fewer rules than default |
latest-recommended | Default + additional recommended rules |
latest-all | All rules enabled — most comprehensive |
9-all, 10-all | Pin to a specific SDK version's full rule set |
latest-all is recommended for new projects. For existing projects with many warnings, start with latest-recommended and tighten over time.
| Category | Prefix | Examples |
|---|---|---|
| Design | CA1xxx | CA1002 (don't expose generic lists), CA1062 (validate arguments) |
| Globalization | CA1300–CA1399 | CA1304 (specify CultureInfo) |
| Performance | CA1800–CA1899 | CA1822 (mark members static), CA1848 (use LoggerMessage) |
| Reliability | CA2000–CA2099 | CA2000 (dispose objects), CA2007 (ConfigureAwait) |
| Security | CA2100–CA2199, CA3xxx, CA5xxx | CA2100 (SQL injection), CA3075 (XML processing) |
| Usage | CA2200–CA2299 | CA2211 (non-constant static fields), CA2245 (don't assign to self) |
| Naming | CA1700–CA1799 | CA1707 (no underscores in identifiers) |
| Style | IDE0xxx | IDE0003 (this qualification), IDE0063 (using declaration) |
Fine-tune analyzer severity per-rule in .editorconfig:
[*.cs]
# Suppress specific rules
dotnet_diagnostic.CA1062.severity = none # Nullable handles this
dotnet_diagnostic.CA2007.severity = none # Not needed in ASP.NET Core apps
# Escalate to error
dotnet_diagnostic.CA1822.severity = error # Mark members as static
dotnet_diagnostic.CA1848.severity = warning # Use LoggerMessage delegates
# Style enforcement
dotnet_diagnostic.IDE0005.severity = warning # Remove unnecessary usings
dotnet_diagnostic.IDE0063.severity = warning # Use simple using statement
dotnet_diagnostic.IDE0090.severity = warning # Simplify new expression
ASP.NET Core apps — suppress ConfigureAwait warnings:
dotnet_diagnostic.CA2007.severity = none
Libraries — keep CA2007 as warning (callers may not have a SynchronizationContext):
dotnet_diagnostic.CA2007.severity = warning
Test projects — relax certain rules:
dotnet_diagnostic.CA1707.severity = none # Allow underscores in test names
dotnet_diagnostic.CA1062.severity = none # Parameters validated by test framework
dotnet_diagnostic.CA2007.severity = none # ConfigureAwait not relevant
Enable globally in Directory.Build.props:
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
Nullable analysis produces warnings (CS86xx) not CA rules. Related settings:
<PropertyGroup>
<!-- Treat nullable warnings as errors -->
<WarningsAsErrors>$(WarningsAsErrors);nullable</WarningsAsErrors>
</PropertyGroup>
For gradual adoption in existing codebases, enable per-file:
#nullable enable
See [skill:dotnet-csharp-nullable-reference-types] for annotation strategies and patterns.
For apps published with trimming or Native AOT, enable the analyzers alongside the publish properties:
<PropertyGroup>
<!-- Enable trimmed publishing + analysis -->
<PublishTrimmed>true</PublishTrimmed>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
<!-- Enable AOT publishing + analysis -->
<PublishAot>true</PublishAot>
<EnableAotAnalyzer>true</EnableAotAnalyzer>
<!-- Single-file analysis (subset of trim analysis) -->
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
</PropertyGroup>
Enable the analyzers early (even before publishing trimmed) to catch issues during development. EnableTrimAnalyzer and EnableAotAnalyzer can be set independently of PublishTrimmed/PublishAot.
Libraries use IsTrimmable and IsAotCompatible to declare compatibility to consumers. Enable these even if consumers don't trim yet:
<PropertyGroup>
<IsTrimmable>true</IsTrimmable>
<IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>
Setting IsTrimmable/IsAotCompatible automatically enables the corresponding analyzers. This ensures the library works correctly when consumers eventually enable trimming/AOT.
These analyzers flag:
Reflection.Emit, System.Linq.Expressions compilation)[DynamicallyAccessedMembers]Add via Directory.Build.targets so they apply to all projects:
<!-- Directory.Build.targets -->
<Project>
<ItemGroup>
<PackageReference Include="Meziantou.Analyzer" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" PrivateAssets="all" />
</ItemGroup>
</Project>
With CPM, add version entries in Directory.Packages.props:
<PackageVersion Include="Meziantou.Analyzer" Version="2.0.187" />
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.11.0-beta1.25058.1" />
| Package | Focus |
|---|---|
Meziantou.Analyzer | Security, performance, best practices (broad coverage) |
Microsoft.CodeAnalysis.BannedApiAnalyzers | Ban specific APIs via BannedSymbols.txt |
Microsoft.CodeAnalysis.PublicApiAnalyzers | Track public API surface (library authors) |
SonarAnalyzer.CSharp | Security, reliability, maintainability |
When using BannedApiAnalyzers, create BannedSymbols.txt at the repo root and include it:
<!-- Directory.Build.targets -->
<ItemGroup>
<AdditionalFiles Include="$(MSBuildThisFileDirectory)BannedSymbols.txt"
Condition="Exists('$(MSBuildThisFileDirectory)BannedSymbols.txt')" />
</ItemGroup>
Example BannedSymbols.txt:
T:System.DateTime;Use DateTimeOffset instead
M:System.DateTime.Now;Use DateTimeOffset.UtcNow instead
T:System.GC;Do not call GC methods directly
AnalysisLevel and EnforceCodeStyleInBuild in Directory.Build.propslatest-recommended if latest-all produces too many warningsDirectory.Build.targets with CPM versionsTreatWarningsAsErrors only after addressing existing warnings, or use <NoWarn> temporarily for categories being addressedFor large codebases, avoid fixing all warnings at once:
<!-- Directory.Build.props — temporary during migration -->
<PropertyGroup>
<AnalysisLevel>latest-recommended</AnalysisLevel>
<!-- Fix these categories first, then remove NoWarn entries -->
<NoWarn>$(NoWarn);CA1822;CA1848</NoWarn>
</PropertyGroup>
Remove NoWarn entries as each category is addressed. Track progress with:
dotnet build 2>&1 | grep -oE 'CA[0-9]+' | sort | uniq -c | sort -rn
npx claudepluginhub wshaddix/dotnet-skillsAdds Roslynator and Meziantou analyzers, creates a comprehensive .editorconfig with 80+ diagnostic rules for enforcing strict .NET/C# coding standards.
Authoring .editorconfig rules. IDE/CA severity, AnalysisLevel, globalconfig, code style enforcement.
Batch-fixes .NET analyzer warnings (IDE*, CA*, CS* for style, quality, naming, performance, security, nullable) with category/severity filtering, preview, and interactive review.