Validate array/span parameters in the WinMD generator and add failure tests#2443
Open
Sergio0694 wants to merge 11 commits into
Open
Validate array/span parameters in the WinMD generator and add failure tests#2443Sergio0694 wants to merge 11 commits into
Sergio0694 wants to merge 11 commits into
Conversation
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>
…nerator 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 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>
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 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>
…ests 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>
… 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>
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>
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>
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>
…TSDK1151) 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>
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
Fix several ways the WinMD generator (
cswinrtwinmdgen) mishandled array/span method parameters when authoring a Windows Runtime component, add validation that rejects the shapes with no Windows Runtime representation, and stand up a newWinMDGeneratorTestproject that exercises the generator's failure modes end-to-end.Motivation
When authoring a component, the WinMD generator maps each method parameter to a Windows Runtime array convention (
ReadOnlySpan<T>→ PassArray,Span<T>→ FillArray,out T[]→ ReceiveArray). A few parameter shapes were handled incorrectly:modreq-wrapped signature fell through to theSystem.Objectfallback and was silently erased. This affectedinparameters on abstract/virtual/interface/delegate members — most notably a COM interopin Guid riidwas emitted as[in] objectinstead of[in] Guid&.ref/inarrays andoutspans have no Windows Runtime representation, but were silently emitted as invalid metadata rather than reported as errors.There was also no test coverage for the generator's failure behavior. Because these are build-time failures, they could not be asserted from the existing build-integrated test projects without breaking the build — so a dedicated end-to-end test project was needed.
Changes
src/WinRT.WinMD.Generator/Writers/WinMDWriter.TypeMapping.cs: strip custom modifiers (modreq/modopt) before mapping a type signature, so modifier-wrapped types are no longer erased toobject.src/WinRT.WinMD.Generator/Writers/WinMDWriter.Members.cs,WinMDWriter.Types.cs,Errors/WellKnownWinMDExceptions.cs: validate parameter conventions and reject the unsupported shapes with clear errors —ref/inarrays (CSWINRTWINMDGEN0011) and by-reference spans such asout Span<T>(CSWINRTWINMDGEN0012) — while preserving the deliberate COM interopref/inscalar behavior (e.g.ref Guid riid→[in]).src/WinRT.WinMD.Generator/Extensions/TypeSignatureExtensions.cs: new extension file housingStripCustomModifiers,IsTypeOfSpan, andIsTypeOfReadOnlySpan(consistent with the interop generator'sIsTypeOf*extensions), moved out of the writer partials.src/Tests/WinMDGeneratorTest/: new MSTest project that runs the actualcswinrtwinmdgentool as a subprocess.Test_ParameterConventionscovers the unsupported array/span shapes;Test_InvalidInputscovers invalid invocations (malformed/missing response files, bad arguments, missing/corrupt input assemblies, an unwritable output path, a missing debug-repro directory). TheWinMDGeneratorRunnerhelper exposes single-callAssertSuccess/AssertFailureentry points; valid.winmdshapes remain covered by the authoring tests.src/cswinrt.slnx: register the new test project..github/skills/testing/SKILL.md,.github/skills/update-testing-instructions/SKILL.md: document the new test project (new section, routing-table row, count bump) and add a matching per-project verification step to the update skill.