-
Notifications
You must be signed in to change notification settings - Fork 566
Description
Overview
Systematic comparison of the new trimmable scanner (JavaPeerScanner) and JCW generator (JcwJavaSourceGenerator) against the legacy Cecil-based pipeline (CecilImporter + CallableWrapperType.Generate) revealed several gaps. These were discovered while building the samples/HelloWorld app with _AndroidTypeMapImplementation=trimmable and by deep analysis of the legacy code paths.
The existing integration parity tests (ExactMarshalMethods, ExactTypeMap, etc.) cover the scanner output. The gaps below are in areas not yet covered by parity tests, primarily in the JCW generator and interface handling.
Gaps
1. ❌ Interface method implementations without [Register] on the implementing method
Severity: High — common user pattern
When a user class implements a Java interface (e.g., IOnClickListener), the implementing method may not have [Register] directly on it. The legacy pipeline handles this via the interface loop in CecilImporter.cs lines 100-120 — it iterates type.Interfaces, resolves each interface, and adds its registered methods to the JCW.
The new scanner only finds methods via:
- Direct
[Register]on the method - Base class override detection (added in [TrimmableTypeMap] Add GenerateTrimmableTypeMap MSBuild task and targets #10924)
It does NOT iterate implemented interfaces to find methods that need JCW entries. This means user types that implement Java interfaces without explicit [Register] on each method will have incomplete JCWs.
Example:
// User code — no [Register] on OnClick
public class MyListener : Java.Lang.Object, IOnClickListener
{
public void OnClick(View v) { } // Missing from JCW
}2. ⚠️ [Export] method Java access modifiers
Severity: Low — rare pattern
The legacy JCW generator respects the JavaAccess property from [Export] attributes (e.g., protected instead of public). The new JcwJavaSourceGenerator always emits public for all methods.
Legacy code: CallableWrapperMethod.Generate() uses IsExport ? JavaAccess : "public".
3. ⚠️ [ExportField] attributes
Severity: Medium
The legacy pipeline generates Java fields via CallableWrapperField for methods decorated with [ExportField]. The new generator does not handle ExportField at all — no Java field declarations are emitted.
Legacy code: CecilImporter.AddMethod() lines 471-480 creates fields via CreateField().
4. ✅ Application/Instrumentation onCreate special casing
Tracked separately in #10931.
5. ⚠️ Constructor super() argument matching for complex hierarchies
Severity: Medium
The legacy CecilImporter walks the base type constructor chain (lines 125-160) to find the right constructor signatures for super(...) calls. The new generator uses JavaConstructorInfo.SuperArgumentsString from [Export] constructors and falls back to forwarding all parameters. For deep hierarchies with multiple constructors at different levels, the super arguments may not match what the legacy pipeline would generate.
6. 💡 Covariant return type overrides in framework types
Severity: Low — no user impact (gated by DoNotGenerateAcw)
18 methods in Mono.Android types (e.g., StringBuilder.append, CursorLoader.loadInBackground) where the C# override narrows the return type. The legacy GetBaseDefinition matches these, but the new scanner's AreParametersCompatible doesn't find them because the parameter matching is done at the managed type level. These are all DoNotGenerateAcw=true framework types, so they don't affect user apps.
7. 💡 Unit test coverage for JCW generator edge cases
The JCW Java output is not compared against the legacy pipeline (and shouldn't be — the formats are deliberately different). However, the following edge cases should have targeted unit tests:
- Nested JCW types
- Multiple constructors with different
super()argument patterns [Export]methods withThrownNames,SuperArgumentsString, and custom access modifiers- Interface implementation methods on class JCWs
- Abstract class JCWs
Proposed approach
Address gaps in priority order:
- Interface method detection — extend
CollectBaseMethodOverridesto also check implemented interfaces (or add a new pass) - ExportField — add support in
JcwJavaSourceGenerator - Constructor super() matching — improve constructor hierarchy walking
- Export access modifiers — add
JavaAccesssupport - Unit tests — add targeted tests for each gap
- Covariant returns — low priority, only affects framework types
Part of #10789