[TrimmableTypeMap] Skip UCO constructor generation for abstract types#11461
[TrimmableTypeMap] Skip UCO constructor generation for abstract types#11461sbomer wants to merge 5 commits into
Conversation
Abstract types are never directly instantiated from Java — the ACW constructor's getClass() guard prevents activation. Generating UCO constructor wrappers for them is dead code and fails when the managed constructor is protected (which is legitimate for abstract types). This fixes XAGTT7009 errors when using the trimmable type map with abstract types like MAUI's CellAdapter that have protected constructors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Assisted-by: Claude:claude-opus-4.6-1m
…emap Verifies that abstract Java peer types with protected constructors do not cause XAGTT7009 when using _AndroidTypeMapImplementation=trimmable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Assisted-by: Claude:claude-opus-4.6-1m
Verifies that BuildUcoConstructors produces no UCO constructors for abstract types, even when the Java constructor has SuperArgumentsString and no matching public managed constructor exists. This complements the existing Build_ExportConstructorWithoutMatchingManagedCtor_Throws test which covers the concrete type case. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Assisted-by: Claude:claude-opus-4.6-1m
There was a problem hiding this comment.
Pull request overview
This PR updates the trimmable typemap generator to avoid generating UCO (Unified Constructor Override) constructor wrappers for abstract ACW types, since they can’t be directly instantiated from Java (and the generated JCW ctor guard prevents activation). This fixes build failures when an abstract managed type only exposes a protected constructor.
Changes:
- Skip UCO constructor wrapper generation for
peer.IsAbstractinModelBuilder.BuildUcoConstructors. - Add a unit test asserting abstract peers produce no UCO constructors.
- Add an integration build test covering an abstract type with a protected
(Context)ctor under_AndroidTypeMapImplementation=trimmable+ NativeAOT.
Show a summary per file
| File | Description |
|---|---|
src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/ModelBuilder.cs |
Early-return in UCO constructor generation for abstract peers. |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapModelBuilderTests.cs |
Unit test validating no UCO constructors are produced for an abstract peer. |
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/TrimmableTypeMapBuildTests.cs |
Integration test ensuring builds succeed with an abstract type with a protected ctor under trimmable typemaps. |
Copilot's findings
- Files reviewed: 3/3 changed files
- Comments generated: 1
Addresses Copilot review feedback: the test hard-codes NativeAOT without the IgnoreUnsupportedConfiguration guard, which can cause failures in environments where NativeAOT builds are skipped. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Assisted-by: Claude:claude-opus-4.6-1m
|
/review |
|
✅ Android PR Reviewer completed successfully! |
There was a problem hiding this comment.
✅ LGTM
Summary: Clean, well-scoped fix. The logic is correct — abstract types are never directly instantiated from Java (the ACW getClass() == ThisClass.class guard prevents it), so generating UCO constructor wrappers for them is dead code that can fail when constructors are protected.
Positives:
- Minimal fix at the right level (
BuildUcoConstructorsearly-out) - Good comment explaining why abstract types are skipped
- Both unit and integration tests cover the scenario
- Integration test uses NativeAOT + trimmable type maps matching the real failure scenario
One minor suggestion posted inline (collection expression syntax in test). No blocking issues.
Generated by Android PR Reviewer for issue #11461 · ● 5.5M
Summary
Abstract types are never directly instantiated from Java — the ACW constructor's
getClass() == ThisClass.classguard prevents activation. Generating UCO (Unified Constructor Override) constructor wrappers for them is dead code that fails at build time when the managed constructor is protected, which is the standard pattern for abstract types.Problem
When using
_AndroidTypeMapImplementation=trimmablewith a type hierarchy where an abstract C# type extending a Java type has a protected constructor (e.g. MAUI'sCellAdapter), the build fails with:Root Cause
BuildUcoConstructorsinModelBuilder.csthrows whenSuperArgumentsString != null && !HasMatchingManagedCtor. The scanner (TryGetMatchingPublicConstructorParameterTypes) only searches for public constructors, but abstract types legitimately have protected constructors. However, the real issue isn't visibility — abstract types should not get activation wrappers at all since they can never be activated from Java.Fix
Skip UCO constructor generation entirely for abstract types in
BuildUcoConstructorsby checkingpeer.IsAbstractearly.Tests
TypeMapModelBuilderTests.cs): AssertsBuildModelproduces no UCO constructors for an abstract peer with a protected constructor.TrimmableTypeMapBuildTests.cs): Verifies a full build succeeds with an abstract type extendingJava.Lang.Objectwith a protected(Context)constructor using trimmable type maps + NativeAOT.