Skip to content

Support C# 15 unions in the remaining type declaration rules - #4193

Merged
AArnott merged 3 commits into
masterfrom
csharp15-union-remaining
Oct 9, 2026
Merged

AArnott merged 3 commits into
masterfrom
csharp15-union-remaining

Conversation

@AArnott

@AArnott AArnott commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Builds on #4192 (merged), which makes the C# 15 test project default to preview. This PR finishes union (SyntaxKindEx.UnionDeclaration) support in the rules that still skipped unions.

Closes #4182. Once this merges, every sub-issue of #4180 is closed, so #4180 can be closed too.

Approach

UnionDeclarationSyntax is a TypeDeclarationSyntax, so I added SyntaxKindEx.UnionDeclaration to the shared SyntaxKinds.BaseTypeDeclaration and SyntaxKinds.TypeDeclaration lists, the same way records were added. Each of these is still a syntax-kind registration, so code without unions does no extra work.

This differs from #4191, which added a separate union registration to each rule. With the shared lists, those per-rule lines in SA1201, SA1202, SA1203, SA1400, SA1600 and SA1601 would run each rule twice per union, so I removed them. Their existing union tests still pass, each with exactly one diagnostic. If you'd rather keep per-rule registrations, I can switch to that. It would mean about 25 extra registration lines.

Rules that now analyze unions

Area Rules Via
Layout SA1500, SA1502, SA1505, SA1508, SA1516 shared lists
Layout SA1506, SA1514 their own kind lists
Ordering SA1205 shared list
Ordering SA1207, SA1214 their own kind lists
Readability (the union's case type list) SA1106, SA1110, SA1111, SA1112, SA1113, SA1114, SA1115, SA1116, SA1117 shared lists
Readability SA1137 shared list, plus the nested-type attribute check
Ordering SA1200 A union in the global namespace now suppresses SA1200 the same way other types do
Documentation SA1604–SA1608, SA1612–SA1614, SA1616, SA1625, SA1629 ElementDocumentationBase / summary base classes
Documentation SA1618, SA1619, SA1620–SA1622 shared list
Documentation SA1648 its own kind list

Requested rules not in the table: SA1201–SA1204, SA1206, SA1300, SA1400, SA1402, SA1600, SA1601 and SA1649 were already done in #4188/#4191/#4096.

Adjustments

  • SA1611 skips unions. A union's parameter list declares its case types (union Pet(Cat, Dog)), which have no names to document. Without this, the shared list would have reported each case type with an empty name. TestUnionCaseTypesAsync covers it.
  • Code fixes: SA1205 (adds the access modifier through UnionDeclarationSyntaxWrapper) and SA1502 (expands a single-line union body).

SA1642 union constructors (5032740, 4ca6e40)

SA1642 and its code fix treated union constructors as class constructors. So on master:

  • SA1642 required Initializes a new instance of the <see cref="Pet"/> class. on union constructors.
  • The code fix inserted the class text.
  • SA1642SA1643CodeFixProvider.GetTypeParameterList had no union case. In Debug builds it hit Debug.Assert ("Unhandled type UnionDeclaration"). In Release builds the cref for a generic union lost its type parameters (Result instead of Result{T}).

5032740 fixes the type parameter list. 4ca6e40 adds union wording, following the existing class/struct resources: a new TypeTextUnion string in every DocumentationResources culture. Union constructors now expect, and the code fix inserts:

  • Initializes a new instance of the <see cref="Result{T}"/> union.
  • Initializes static members of the <see cref="Pet"/> union.
  • The private-constructor form ("Prevents a default instance of the ... union from being created.") comes from the same templates.

The struct wording on a union constructor is now reported. documentation/SA1642.md has a union example. SA1643 (destructors) has no type-kind text, and unions can't have destructors, so it needed no change.

The translations are best effort: de "Union", fr/es/nl/en-GB "union", pt-BR "união", cs "sjednocení", pl "unii", ru "объединения". The French template is de la {0}, so it produces "de la union" rather than "de l'union"; the Spanish template gives "de la union". Fixing the article would mean changing the shared template, which I left alone.

Tests

There are new C# 15 tests for SA1106, SA1110, SA1111, SA1113–SA1117, SA1137 (2), SA1200, SA1205, SA1207, SA1214, SA1500, SA1502, SA1505, SA1506, SA1508, SA1514, SA1516, SA1604, SA1606, SA1611, SA1618, SA1620, SA1642 (5) and SA1648.

  • Each expects exactly one diagnostic per violation.
  • Each rule that has a code fix gets a code-fix test.
  • They rely on Default the C# 15 test project to the preview language version #4192's preview default instead of passing LanguageVersion.Preview.
  • Negative check: with the product changes reverted, every new test fails except the SA1611 one, which guards against the shared-list change.
  • Not separately tested, but covered by the shared lists: SA1112, SA1605, SA1607, SA1608, SA1612–SA1614, SA1616, SA1619, SA1621, SA1622, SA1625, SA1629.

Local run (C# 15, net6.0, Linux): 9,593 tests. The only new failures are the 5 new code-fix tests that show the known Linux CRLF difference; Windows CI is authoritative for those.

@AArnott
AArnott added this pull request to stack #4194 October 9, 2026 13:53
@AArnott AArnott changed the title csharp15 union remaining Support C# 15 unions in the remaining type declaration rules Oct 9, 2026
Base automatically changed from csharp15-default-preview to master October 9, 2026 13:56
@AArnott
AArnott force-pushed the csharp15-union-remaining branch from 1de14de to ee5c0af Compare October 9, 2026 13:56
A union declaration is a struct type, but SA1642 expected union constructors
to be documented as "Initializes a new instance of the <see cref="T"/> class",
and the code fix inserted the class text. The code fix also had no case for
unions in GetTypeParameterList: in Debug builds it failed an assertion, and in
Release builds the cref for a generic union dropped its type parameters.

SA1642 now expects the struct text for union constructors, and the code fix
inserts it with the union's type parameters.
A union declaration is a TypeDeclarationSyntax, so it now appears in
SyntaxKinds.BaseTypeDeclaration and SyntaxKinds.TypeDeclaration, the same way
records do. Every rule that registers for those lists now also analyzes unions:

- Layout: SA1500, SA1502, SA1505, SA1508, SA1516
- Readability (the union's case type list): SA1106, SA1110, SA1111, SA1112,
  SA1113, SA1114, SA1115, SA1116, SA1117, SA1137
- Ordering: SA1205
- Documentation: SA1604, SA1605, SA1606, SA1607, SA1608, SA1611, SA1612,
  SA1613, SA1614, SA1616, SA1618, SA1619, SA1620, SA1621, SA1622, SA1625, SA1629

The separate union registrations that #4191 added to SA1201, SA1202, SA1203,
SA1400, SA1600 and SA1601 are removed, because the shared lists now cover them
(keeping them would run those rules twice per union).

Rules with their own lists of type declaration kinds now include unions too:
SA1207, SA1214, SA1506, SA1514 and SA1648, plus the type kind checks in SA1137
(attribute lists of nested types) and SA1200 (a union in the global namespace
suppresses the rule, like other types).

SA1611 skips unions: the parameter list of a union declares its case types,
which have no names to document. The SA1205 and SA1502 code fixes handle unions.

All of these are syntax kind registrations, so code without unions does no extra
work. The new C# 15 tests expect exactly one diagnostic per violation, with code
fix tests where the rule has a fix.

Closes #4182
@AArnott
AArnott force-pushed the csharp15-union-remaining branch from ee5c0af to 6f5c835 Compare October 9, 2026 13:59
@codecov

codecov Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.48187% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.54%. Comparing base (a19eede) to head (4ca6e40).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4193      +/-   ##
==========================================
+ Coverage   97.53%   97.54%   +0.01%     
==========================================
  Files        1250     1277      +27     
  Lines      133401   134157     +756     
  Branches     4290     4291       +1     
==========================================
+ Hits       130109   130863     +754     
- Misses       2150     2152       +2     
  Partials     1142     1142              
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@AArnott
AArnott marked this pull request as ready for review October 9, 2026 14:10
@AArnott
AArnott marked this pull request as draft October 9, 2026 14:26
Union constructors now expect and the code fix now inserts
"Initializes a new instance of the <see cref="T"/> union." (and
"Initializes static members of the ... union.") instead of the struct
wording. Adds a TypeTextUnion resource to every DocumentationResources
culture and documents the union form in SA1642.md.
@AArnott
AArnott marked this pull request as ready for review October 9, 2026 14:36
@AArnott
AArnott merged commit 868775d into master Oct 9, 2026
25 checks passed
@AArnott
AArnott deleted the csharp15-union-remaining branch October 9, 2026 14:39
This was referenced Nov 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Review impact of union types on existing rules

1 participant