A small set of Roslyn analyzers and code fixes that enforce one readability
convention everywhere it can apply: a comma-delimited list — method/constructor
parameters, call/new arguments, attribute arguments, primary-constructor
parameters, generic type-parameter and type-argument lists, function-pointer
parameter lists, and more — must either sit entirely on one line or have
each item on its own line. A "jagged" layout (some items sharing a line,
others wrapped) is reported, and the accompanying code fix rewrites the list so
every item is on its own line.
// 👎 jagged — flagged
void Configure(string host, int port,
bool useTls);
// 👍 each parameter on its own line
void Configure(
string host,
int port,
bool useTls);
// 👍 all on one line
void Configure(string host, int port, bool useTls);The analyzers target netstandard2.0, have no runtime dependencies, ship as
a development-only NuGet package, and are built against the Roslyn that ships
with Visual Studio 2022 17.14 (Microsoft.CodeAnalysis.* 4.14.0). The package
id is Blazor.Common.Analyzers; the repository is RoslynCommonAnalyzers.
Diagnostics share the
RCGSprefix. Every rule is categoryReadability, default severityWarning, and ships with a code fix.
dotnet add package Blazor.Common.AnalyzersIt is a DevelopmentDependency analyzer package — it adds no assemblies to your
output and is not transitive to consumers of your library.
Each rule has a documentation page under docs/rules; the
helpLinkUri on every diagnostic points there.
| Rule | Applies to |
|---|---|
| RCGS0001 | Constructor declaration parameters |
| RCGS0002 | Method declaration parameters |
| RCGS0003 | Delegate declaration parameters |
| RCGS0004 | Indexer declaration parameters |
| RCGS0005 | Invocation (method call) arguments |
| RCGS0006 | Object creation (new T(...)) arguments |
| RCGS0007 | Element access (x[...]) arguments |
| RCGS0008 | Attribute arguments |
| RCGS0009 | Anonymous method (delegate(...)) parameters |
| RCGS0010 | Parenthesized lambda parameters |
| RCGS0011 | record / record struct primary-constructor parameters |
| RCGS0012 | class primary-constructor parameters (C# 12) |
| RCGS0013 | struct primary-constructor parameters (C# 12) |
| RCGS0014 | Target-typed new(...) arguments |
| RCGS0015 | : base(...) / : this(...) constructor-initializer arguments |
| RCGS0016 | record Foo(...) : Bar(args) base-type arguments |
| RCGS0017 | Local function parameters |
| RCGS0018 | operator declaration parameters |
| RCGS0019 | Conversion-operator declaration parameters (never reports — conversion ops always have one parameter; kept for symmetry) |
| RCGS0020 | Generic type-parameter lists — class Foo<T1, T2>, void M<T1, T2>() |
| RCGS0021 | Generic type-argument lists — Foo<int, string> |
| RCGS0022 | Function-pointer parameter lists — delegate*<int, string, void> |
These are formatting/readability conventions, so tune them per project in
.editorconfig:
# bump everything to a build error
dotnet_diagnostic.RCGS0001.severity = error
# … or turn one rule off
dotnet_diagnostic.RCGS0007.severity = nonePrefer .editorconfig over scattering #pragma warning disable / [SuppressMessage].
Every rule is a SyntaxNodeAnalysisContext-based DiagnosticAnalyzer registered
for a specific SyntaxKind (or two — e.g. RecordDeclaration +
RecordStructDeclaration). It pulls the relevant SeparatedSyntaxList, and
reports when the items are split across lines such that they are neither all on
one line nor all on separate lines. The code fix rebuilds the list with a newline
after the opening token and each separator (and re-indents one level deeper than
the owning declaration), via the shared helpers in ArgumentsOrParameterOnSameLineHelper
and UniqueLineCodeFixerHelper.
The solution follows the standard analyzer layout:
| Project | Purpose |
|---|---|
Blazor.Common.Analyzers |
the DiagnosticAnalyzers (netstandard2.0) |
Blazor.Common.Analyzers.CodeFixes |
the CodeFixProviders (netstandard2.0) |
Blazor.Common.Analyzers.Package |
packs the two above into the Blazor.Common.Analyzers NuGet package |
Blazor.Common.Analyzers.Tests |
TUnit tests using Microsoft.CodeAnalysis.Testing |
dotnet restore Blazor.Common.Analyzers.sln
dotnet build Blazor.Common.Analyzers.sln --configuration Release
dotnet test --solution Blazor.Common.Analyzers.sln --configuration ReleaseTreatWarningsAsErrors is on and the repo's .editorconfig is strict — the
build is clean only when every analyzer (StyleCop, Roslynator, SonarAnalyzer,
the .NET analyzers) is satisfied. Fix issues rather than suppressing them.
Issues and PRs welcome. Adding a rule means: a Rcgs####…Analyzer.cs, a
matching …CodeFixProvider.cs, a Rcgs####…AnalyzersUnitTest.cs (markup-based
CSharpCodeFixVerifier tests), a docs/rules/RCGS####.md page, and a row in
AnalyzerReleases.Unshipped.md.
MIT — see LICENSE.