Support C# 14 extension members in CsSig - #32
Merged
Merged
Conversation
Roslyn models each `extension(Receiver) { ... }` block as a nested type
with an unspeakable, compiler-generated name. The writer emitted these as
nameless `public class { ... }` declarations, producing broken `.cssig`
files for projects that use extension members.
- Add ExtensionMembers helper isolating the Roslyn-version-sensitive logic
(numeric TypeKind.Extension, reflective ExtensionParameter) so the
analyzer keeps targeting the older Roslyn baseline.
- CsSigWriter now emits proper `extension<T>(receiver) { ... }` blocks
(deterministically ordered), rendering the receiver with ref-kind and
nullability.
- SignatureModel keys extension markers by the fixed `<extension>`
discriminator plus their receiver type, so distinct blocks with the same
receiver are not conflated.
- ApiSurface no longer double-counts the implicit implementation methods the
compiler synthesises on the host static class; the members are tracked
through the extension marker types instead.
- Bump the test harness to Roslyn 5.x (Microsoft.CodeAnalysis.Analyzer.Testing
1.1.4, CSharp.Workspaces 5.3.0) and add round-trip + soundness regression
tests for extension members.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Now that the analyzer requires C# 14 extension support anyway, bump the analyzer/code-fix projects from the Microsoft.CodeAnalysis 4.0 baseline to 5.0 and drop the version-compatibility workarounds: - ExtensionMembers uses INamedTypeSymbol.IsExtension / ExtensionParameter and TypeKind.Extension directly instead of numeric enum values and reflection. - SignatureModel uses RefKind.RefReadOnlyParameter directly instead of the numeric (RefKind)4 fallback. - Suppress RS1035/RS1037 (newly enforced by the updated analyzer-rules package) via a global config: RS1035 only fires on the third-party IndentingBuilder source, and RS1037 is an orthogonal optimisation hint. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Apply consistent multiline formatting across the CsSig projects and refine the analyzer, recognizer, writer, signature model, and code-fix provider. Switch the test harness from the obsolete XUnitVerifier-based Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.XUnit package to Microsoft.CodeAnalysis.CSharp.Analyzer.Testing 1.1.4. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
C# 14 extension-member support is a new feature. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
agocke
added a commit
that referenced
this pull request
Jun 28, 2026
…e members (#33) Follow-up to #32. Fixes several cases where the `.cssig` writer and the analyzer disagreed about the public API surface, found by running the analyzer over the real `serde` project (which now builds clean against the updated analyzer). ## Fixes - **Positional records & record inheritance** — emit the primary constructor parameter list and the record base clause in the type header; skip the synthesized primary constructor and positional properties (carried by the header). - **Inaccessible-only constructors** — emit a `private` stub for records/classes whose only declared constructors are inaccessible (e.g. an abstract record with an explicit `private` parameterless ctor), suppressing the parameterless constructor the compiler would otherwise synthesize from the body-less form. - **Generic constraints** — carry `where` clauses on types and methods. Constraints change member semantics (`where T : struct` makes `T?` a `Nullable<T>`) and distinguish overloads differing only by constraint. - **Default & static interface members** — normalize away virtual/abstract/override/sealed for interface members (a body-less `.cssig` cannot express default-implementation-ness) and re-emit `static`, which `SymbolDisplay` strips on interface members. - **Type-parameter nullability** — collapse oblivious to not-annotated for bare type-parameter references, reconciling the project's lexical self-reference with the rebound reference the writer emits. Bumps the package version to **0.3.0**. ## Tests Adds round-trip tests: `RoundTripPositionalRecords`, `RoundTripPrivateConstructorClass`, `RoundTripDefaultInterfaceMethods`, `RoundTripGenericConstraints`. Full suite: 98 passing, 1 skipped. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Projects using C# 14 extension members (
extension(Receiver) { ... }) produced broken.cssigfiles: each block was emitted as a namelesspublic class { ... }. Roslyn models each block as a nested type with an unspeakable, compiler-generated name, which the writer rendered as an empty class name.Changes
ExtensionMembershelper — recognises extension marker types and their receivers viaINamedTypeSymbol.IsExtension/ExtensionParameter/TypeKind.Extension.extension<T>(receiver) { ... }blocks (deterministically ordered), rendering the receiver with ref-kind and nullability.<extension>discriminator plus the receiver type, so distinct blocks sharing a receiver are not conflated (soundness).Microsoft.CodeAnalysis4.0 baseline to 5.0 (extension members require it), removing the previous reflection/numeric-enum workarounds and the now-stale(RefKind)4fallback. RS1035/RS1037 (newly enforced) are suppressed via a documented global config.Microsoft.CodeAnalysis.Analyzer.Testing1.1.4,CSharp.Workspaces5.3.0) and add round-trip + soundness regression tests.Validation
CSSIG001/CSSIG002.PublicAPI.cssig(serde): allextension(...)blocks correct, no nameless classes, nullable receivers preserved.