Skip to content

[TrimmableTypeMap] Skip UCO constructor generation for abstract types#11461

Open
sbomer wants to merge 5 commits into
mainfrom
dev/sbomer/abstract-fix
Open

[TrimmableTypeMap] Skip UCO constructor generation for abstract types#11461
sbomer wants to merge 5 commits into
mainfrom
dev/sbomer/abstract-fix

Conversation

@sbomer
Copy link
Copy Markdown
Member

@sbomer sbomer commented May 22, 2026

This content was created with assistance from AI.

Summary

Abstract types are never directly instantiated from Java — the ACW constructor's getClass() == ThisClass.class guard 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=trimmable with a type hierarchy where an abstract C# type extending a Java type has a protected constructor (e.g. MAUI's CellAdapter), the build fails with:

error XAGTT7009: Trimmable typemap cannot generate Java constructor wrapper
'(Landroid/content/Context;)V' for 'CellAdapter' because no matching
user-visible managed constructor was found.

Root Cause

BuildUcoConstructors in ModelBuilder.cs throws when SuperArgumentsString != 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 BuildUcoConstructors by checking peer.IsAbstract early.

Tests

  • Unit test (TypeMapModelBuilderTests.cs): Asserts BuildModel produces no UCO constructors for an abstract peer with a protected constructor.
  • Integration test (TrimmableTypeMapBuildTests.cs): Verifies a full build succeeds with an abstract type extending Java.Lang.Object with a protected (Context) constructor using trimmable type maps + NativeAOT.

sbomer and others added 3 commits May 22, 2026 15:32
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
Copilot AI review requested due to automatic review settings May 22, 2026 22:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.IsAbstract in ModelBuilder.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
@simonrozsival
Copy link
Copy Markdown
Member

/review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 23, 2026

Android PR Reviewer completed successfully!

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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 (BuildUcoConstructors early-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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants