Skip to content

Add support for custom overload names to the WinMD generator - #2454

Merged
Sergio0694 merged 3 commits into
staging/3.0from
user/sergiopedri/overload-names
Jul 24, 2026
Merged

Add support for custom overload names to the WinMD generator#2454
Sergio0694 merged 3 commits into
staging/3.0from
user/sergiopedri/overload-names

Conversation

@Sergio0694

Copy link
Copy Markdown
Member

Summary

Honor an author-applied [Windows.Foundation.Metadata.Overload("Name")] attribute when generating a component's .winmd, emitting that name instead of an auto-generated sequential one. This ports #2275 (which targeted CsWinRT 2.x) to the CsWinRT 3.0 WinMD generator.

Motivation

Rust (windows-rs) and some other Windows Runtime consumers cannot represent overloaded methods, so they rely on the [Overload] attribute to give each overload a distinct, ergonomic ABI name. Previously, author-specified names were ignored and the generator always auto-generated sequential suffixes (Method2, Method3, …). PR #2275 added support for honoring them in CsWinRT 2.x. CsWinRT 3.0 produces the .winmd with a different, post-build tool (cswinrtwinmdgen, which analyzes the compiled .dll with AsmResolver rather than running a Roslyn source generator), so the behavior had to be re-implemented there.

Changes

Generator (src/WinRT.WinMD.Generator/):

  • Writers/WinMDWriter.Finalization.cs: AddOverloadAttributesForType now honors an author-specified [Overload("...")] name when present (otherwise it keeps auto-generating a sequential name). It also selects the default overload (the one that keeps the original ABI name) from the [DefaultOverload] attribute rather than from metadata order, so an author-specified name is not dropped when the default is not declared first, and auto-generated names skip any name already used by another member or overload to avoid collisions. Adds the RecordUserSpecifiedOverloadName and HasDefaultOverloadAttribute helpers.
  • Writers/WinMDWriter.Members.cs: records the author-specified overload name while emitting interface methods (authored and synthesized), so finalization can honor it.
  • Writers/WinMDWriter.Attributes.cs: ShouldCopyAttribute no longer copies [Overload] verbatim; it is emitted exactly once by the overload phase as the single source of truth, preventing duplicates.
  • Writers/WinMDWriter.cs: adds the _userSpecifiedOverloadNames map.

[Overload] is emitted only on interfaces (authored and synthesized), not on runtime classes, matching the Windows Runtime metadata convention and CsWinRT 2.x (a runtime class exposes its ABI through interfaces).

Tests:

  • src/Tests/AuthoringTest/Program.cs: the ICustomOverloadNames interface and CustomOverloadNamesClass from PR Add support for custom overload names to CsWinMD #2275, plus types covering additional behaviors (OverloadCollisionClass, IDefaultOverloadNotFirst / DefaultOverloadNotFirstClass).
  • src/Tests/AuthoringConsumptionTest/test.cpp: the ported CustomOverloadNames consumption test, plus new tests for an auto-generated name coexisting with an author-specified one, collision avoidance, and [DefaultOverload] on a non-first overload.
  • src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.exe.manifest: activatableClass entries for the newly activatable test classes (including CustomOverloadNamesClass, whose entry the original PR omitted).

Sergio0694 and others added 3 commits June 18, 2026 11:55
Port custom overload name support from PR #2275 (CsWinRT 2.x) to the
CsWinRT 3.0 WinMD generator (cswinrtwinmdgen). When an authored method
carries [Windows.Foundation.Metadata.Overload("Name")], emit that name in
the generated .winmd instead of an auto-generated sequential one. windows-rs
consumers require explicit overload names because Rust has no method overloading.

- Record author-specified overload names while emitting interface methods and
  honor them in AddOverloadAttributesForType; stop copying the [Overload]
  attribute verbatim so it is never duplicated.
- Select the default overload (which keeps the original name) from the
  [DefaultOverload] attribute rather than metadata order, so an author-specified
  name is not dropped when the default is not declared first.
- Auto-generated names skip any name already used by another method or an
  author-specified overload, avoiding collisions.
- Emit [Overload] only on interfaces (authored and synthesized), matching the
  Windows Runtime metadata convention; runtime classes expose their ABI through
  interfaces (consistent with CsWinRT 2.x).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the ICustomOverloadNames interface and CustomOverloadNamesClass authoring
types, and the CustomOverloadNames consumption test. The test validates that
author-specified [Overload] names (LookupByIndex, LookupByFlag, TransformNumber)
appear in the generated projection's ABI vtables, on both an authored interface
and a class's synthesized interface.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…lt selection

Extend the overload-name tests to cover behaviors beyond the original PR:

- Verify the auto-generated ABI name (Transform2) coexists with an author-
  specified one (TransformNumber) in the same overload group.
- OverloadCollisionClass: an author-specified overload name matching the auto
  pattern ("M2") forces the auto-generated name of the remaining overload to
  skip it ("M3").
- DefaultOverloadNotFirstClass / IDefaultOverloadNotFirst: [DefaultOverload] on
  a non-first overload keeps the original ABI name, while the author-specified
  name ("GetByIndex") on the first overload is still honored.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Sergio0694 Sergio0694 added enhancement New feature or request authoring Related to authoring feature work cswinmd CsWinRT 3.0 labels Jun 18, 2026
@Sergio0694
Sergio0694 requested a review from manodasanW June 18, 2026 19:01
@Sergio0694
Sergio0694 merged commit 29832e4 into staging/3.0 Jul 24, 2026
11 checks passed
@Sergio0694
Sergio0694 deleted the user/sergiopedri/overload-names branch July 24, 2026 00:09
Sergio0694 added a commit that referenced this pull request Jul 28, 2026
The custom overload names change (#2454) took error ids 0011 and 0012 for
'WindowsSdkNotFound' and 'CannotReadWindowsSdkXml', so renumber the new
by-reference array/span parameter errors to 0013 and 0014 and update the
tests and the testing skill accordingly.

Also update the new test project for the build changes on staging: drop
'LangVersion' (now centralized in 'src/Directory.Build.props') and drop the
removed 'ARM' platform from the solution entry (#2472, #2489). Finally, fix
the stale 'GlobalPropertiesToRemove' mention in the testing skill, which the
project file replaced with 'UndefineProperties'.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8ec1fee3-01c2-4213-baf0-bed82d056068
Sergio0694 added a commit that referenced this pull request Jul 28, 2026
The range was already stale at '0001'-'0010': the custom overload names change
(#2454) added 0011 and 0012. This adds 0013 and 0014, so bump the documented
range to '0001'-'0014'.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8ec1fee3-01c2-4213-baf0-bed82d056068
Sergio0694 added a commit that referenced this pull request Jul 28, 2026
… tests (#2443)

* Fix custom-modifier type erasure in the WinMD generator type mapping

MapTypeSignatureToOutput had no handling for CustomModifierTypeSignature, so any modifier-wrapped type fell through to the 'System.Object' fallback and was silently erased. This affects 'in' parameters on abstract/virtual/interface/delegate members, where the C# compiler emits a 'modreq(InAttribute)' on the by-reference type. For example, a COM interop 'in Guid riid' was emitted as '[in] object' instead of '[in] Guid&'. Strip leading custom modifiers before dispatching on the underlying type.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Validate unsupported array/span parameter conventions in the WinMD generator

Windows Runtime arrays use one of three conventions (ReadOnlySpan<T> for PassArray, Span<T> for FillArray, or 'out T[]' for ReceiveArray), and spans are always passed by value. The generator previously emitted invalid metadata for a few shapes: 'ref T[]'/'in T[]' became '[in] T[]&', and 'out Span<T>'/'out ReadOnlySpan<T>' became a ReceiveArray. Reject these with clear errors (CSWINRTWINMDGEN0011 for by-reference arrays, CSWINRTWINMDGEN0012 for by-reference spans), while preserving the deliberate COM interop 'ref'/'in' scalar behavior (e.g. 'ref Guid riid' -> '[in]') and the by-value array PassArray default.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add WinMD generator parameter-convention failure tests

Add a WinMDGeneratorTest project that runs the actual cswinrtwinmdgen tool end-to-end: it compiles small C# inputs with Roslyn, invokes the generator as a subprocess, and asserts a non-zero exit code plus the expected CSWINRTWINMDGEN error. The project deliberately focuses on failure cases (unsupported 'ref'/'in' arrays and 'out' spans), which can be exercised here without failing the build; the supported '.winmd' shapes (PassArray/FillArray/ReceiveArray) are covered by the authoring tests. The generator exposes no internals to the test project. Registers the project in the solution.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add WinMD generator invocation and invalid-input failure tests

Extend the WinMDGeneratorTest harness with a custom-response-file overload and a public CompileComponent helper, then add Test_InvalidInputs covering the generator's remaining end-to-end failure modes: a missing response file (CSWINRTWINMDGEN0001), a malformed or duplicate-argument response file (0002), a missing required or unparseable argument (0003), a missing or corrupt input assembly (0004), an unwritable output path (0006), and a missing debug-repro directory (0008).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Move WinMD generator TypeSignature helpers into an extension file

Move StripCustomModifiers (previously a private method in WinMDWriter.TypeMapping) and the span predicates into a new Extensions/TypeSignatureExtensions.cs, matching the existing TypeDefinitionExtensions pattern. Rename IsSpan/IsReadOnlySpan to IsTypeOfSpan/IsTypeOfReadOnlySpan as extension methods, consistent with the interop generator's IsTypeOf* extensions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add AssertSuccess/AssertFailure helpers to collapse WinMD generator tests

Rename the test helper to WinMDGeneratorRunner and give it AssertSuccess/AssertFailure entry points that run the generator and make the exit-code and error-output assertions, so each test is a single call. The run mechanics (Run, RunTool, GetGeneratorPath, the failure-result assertion, cleanup) are private; only the assertion entry points and CompileComponent (used by the response-file factory scenarios) are public.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Take full response file content as a single string in WinMD generator tests

Change the AssertFailure response-file factory from Func<string, IReadOnlyList<string>> to Func<string, string> so callers provide the entire '.rsp' content as one multiline raw interpolated string instead of a list of per-line expressions. The runner now writes the content verbatim with File.WriteAllText.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Document the WinMDGeneratorTest project in the testing skill

Add a 'WinMD generator tests' section describing the new src/Tests/WinMDGeneratorTest project (end-to-end failure-case tests for cswinrtwinmdgen), add a routing-table row, and bump the primary test area count to 6. Also add a matching per-project verification step to the update-testing-instructions skill and renumber the subsequent steps.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix stale comment in WinMDGeneratorTest project file

The tests run the generator tool end-to-end as a subprocess rather than exercising its managed logic in-process, so update the comment that justifies 'CsWinRTEnabled=false' to match.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Move new WinMD generator errors after the existing ones

Define the by-reference array/span parameter errors (0011/0012) after the debug-repro errors (0008-0010) instead of in the middle, so the methods appear in ascending error-id order.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Build the WinMD generator framework-dependent in the test project (NETSDK1151)

The generator's PublishAot build is self-contained, which a non self-contained
executable cannot reference (NETSDK1151). Replace GlobalPropertiesToRemove for
RuntimeIdentifier with UndefineProperties for BuildToolArch, PublishBuildTool,
RuntimeIdentifier and SelfContained so the tool is built framework-dependent for
the build host, matching the proven WinRT.Internal reference pattern. The output
stays under net10.0 (no RID subfolder), so the tool path used by the tests is
unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Wrap long exception messages for readability

Split long interpolated exception message strings into multi-line concatenated strings in src/WinRT.WinMD.Generator/Errors/WellKnownWinMDExceptions.cs (ByReferenceArrayParameterNotSupported and ByReferenceSpanParameterNotSupported) to improve readability and line-length compliance; no functional behavior changes.

* Adapt the WinMD generator parameter validation to staging/3.0

The custom overload names change (#2454) took error ids 0011 and 0012 for
'WindowsSdkNotFound' and 'CannotReadWindowsSdkXml', so renumber the new
by-reference array/span parameter errors to 0013 and 0014 and update the
tests and the testing skill accordingly.

Also update the new test project for the build changes on staging: drop
'LangVersion' (now centralized in 'src/Directory.Build.props') and drop the
removed 'ARM' platform from the solution entry (#2472, #2489). Finally, fix
the stale 'GlobalPropertiesToRemove' mention in the testing skill, which the
project file replaced with 'UndefineProperties'.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8ec1fee3-01c2-4213-baf0-bed82d056068

* Update the WinMD generator error id range in the instructions

The range was already stale at '0001'-'0010': the custom overload names change
(#2454) added 0011 and 0012. This adds 0013 and 0014, so bump the documented
range to '0001'-'0014'.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8ec1fee3-01c2-4213-baf0-bed82d056068

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8ec1fee3-01c2-4213-baf0-bed82d056068
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

authoring Related to authoring feature work cswinmd CsWinRT 3.0 enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants