.NET compiler platform (Roslyn) analyzers are included in the .NET SDK and
enabled by default in .NET 5 and later. Code analysis violations are prefixed
with CA
or IDE
to differentiate them from compiler errors.
Rule Categories
Rules fall in one of the following categories:
- Design: Adherence to the design guidelines for
.NET
libraries . - Documentation: Correct use of XML documentation comments for externally visible APIs.
- Globalization: World-ready libraries and applications.
- Interoperability: Portability across platforms; interaction with COM clients.
- Maintainability: Library and application maintenance.
- Naming: Naming conventions of the .NET design guidelines.
- Performance: High-performance libraries and applications.
- SingleFile: Single-file applications.
- Reliability: Library and application reliability, e.g., thread usage.
- Security: Prevent security flaws in your program.
- Style: Consistent code style.
- Usage: Proper usage of .NET.
Configuration in the MSBuild File
AnalysisMode
controls which rules are enabled as build warnings. Possible
values are None
, Default
, Minimum
, Recommended
, or All
(with each
being more aggressive than the previous). Can use <AnalysisMode<Category>>
to
target a specific category of rules, e.g., <AnalysisModeReliability>
.
Setting CodeAnalysisTreatWarningsAsErrors
to true
is equivalent to building
with the -warnaserror
flag. By default, it’s set to false
; you’ll still see
code analysis warnings, but they won’t break the build.
Newer versions of .NET may come with more code analysis rules. AnalysisLevel
<AnalysisLevel>8.0</AnalysisLevel>
locks to the rules that shipped with v8.0
of the .NET SDK. One can also install the Microsoft.CodeAnalysis.NetAnalyzers
package to decouple the rule updates from the .NET SDK updates.
Setting EnforceCodeStyleInBuild
to true
enables you to enforce consistent
code styles at build time. For performance reasons,
some rules are exempt from EnforceCodeStyleInBuild
and only run in the IDE
(e.g., as code refactoring quick actions), e.g., SimplifyNames
,
RemoveQualification
, PreferBuiltInOrFrameworkType
, RemoveUnreachableCode
,
RemoveUnnecessarySuppression
, etc. .
Configuration in Config Files
Both code quality and code style rules accept a severity level, e.g.,
# Most specific rule wins. CA1822 will have an effective severity of "error"
dotnet_diagnostic.CA1822.severity = error
# All other rules in the "Performance" category that are enabled by default will
# have a "warning" severity.
dotnet_analyzer_diagnostic.category-performance.severity = warning
# All other rules outside of "Performance" category that are enabled by default
# will have a "suggestion" severity.
dotnet_analyzer_diagnostic.severity = suggestion
… where the severity can be one of none
, silent
, suggestion
, warning
,
error
, or default
.
However, if you enable any <AnalysisMode>
or <AnalysisLevel>
, then any bulk
dotnet_analyzer_diagnostic
options are ignored. It’s better to enable a
category of rules by setting <AnalysisMode<Category>>
to All
.
.editorconfig
files may contain both editor settings (e.g., indent_style = space
) and options for code analysis rules. The files apply to source files the
current folder, including subfolders, e.g.,
[*.cs]
# Applies to all .cs files in the current folder and subfolders.
dotnet_diagnostic.CA1822.severity = error
By default, auto-generated files (as identified by header or extension) are exempt from code analyzer warnings. Additional files and folders can be configured as follows:
[*.MyGenerated.cs]
generated_code = true
Unlike .editorconfig
files, .globalconfig
files apply to all source files in
a project, regardless of their file paths. .globalconfig
do not configure
editor settings either. The conventional extension is .globalconfig
but there
is no limitation (non-conventional paths can be added under the
<GlobalAnalyzerConfigFiles>
node in the .csproj
file).
# Top level entry required to mark this as a global AnalyzerConfig file.
# Even in an implicitly referenced `.globalconfig`, include this by convention.
is_global = true
# By default, .globalconfig files have a level of 100 and others default to 0.
# In case of conflicts, the file with the higher value wins; if there's a tie,
# a compiler warning is reported and conflicting entries are ignored.
global_level = 100
# NOTE: No section headers for configuration entries
#### .NET Coding Conventions ####
# this. and Me. preferences
dotnet_style_qualification_for_method = true:warning
#### Diagnostic configuration ####
# CA1000: Do not declare static members on generic types
dotnet_diagnostic.CA1000.severity = warning
.globalconfig
files can be conditionally included to disable/enable certain
code analysis rules in different environments, e.g.,
<ItemGroup Condition="'$(IsShipping)' == 'false'">
<GlobalAnalyzerConfigFiles
Include="$(MSBuildThisFileDirectory)CodeAnalysis.test.globalconfig" />
</ItemGroup>
Beyond configuring severity, code quality analyzers can be configured to only apply to specific parts of the codebase, e.g.,
# Only analyze public API surfaces
dotnet_code_quality.api_surface = public
# For rules in the Naming category, only analyze internal and private protected APIs.
dotnet_code_quality.Naming.api_surface = friend
… where configurable options include api_surface
, allowed_surfaces
,
excluded_symbol_names
, etc.
Code-style rules also have associated options, e.g.,
dotnet_sort_system_directives_first = false
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
dotnet_style_prefer_collection_expression = when_types_loosely_match
csharp_style_var_when_type_is_apparent = false
Configuration in Source Files
One can use preprocessor directives to suppress warnings for specific lines of code, e.g.,
try { ... }
catch (Exception e)
{
#pragma warning disable CA2200 // Rethrow to preserve stack details
throw e;
#pragma warning restore CA2200 // Rethrow to preserve stack details
}
For compiler-generated code that doesn’t map to explicitly provided user source,
one may use the SuppressMessage
attribute in the GlobalSuppressions.cs
for
the project, e.g.,
[assembly: SuppressMessage(
"Usage",
"CA2200:Rethrow to preserve stack details",
Justification = "Not production code.",
Scope = "member",
// Target property accepts the documentation ID for the API being suppressed.
Target = "~M:MyApp.Program.IgnorableCharacters")]
I don’t fully follow this example. Why would generated code be running into code analyzer errors? Shouldn’t we have:
[*.MyGenerated.cs]
generated_code = true
Or maybe the use-case is for when I’m the one writing the generator, and I don’t want the generated code to be bug-prone?
To get rules like JSON001
, JSON002
and RE0001
to kick in, annotate strings
that should be identified as JSON or RegEx, e.g.,
// lang=json,strict
var v = """{ "pie": true, "cherry": [1, 2, 3 }""";
// lang=regex,strict
string pattern = @"\b[M]\w+\";
Not to be confused with
CS
-prefixed messages that are generated by the C# compiler.