[TrimmableTypeMap] Detect overrides and constructors in JavaPeerScanner#10932
Conversation
The scanner only found marshal methods with [Register] directly on them. User types (e.g., MainActivity) that override Activity.OnCreate() don't have [Register] on the override — the attribute is only on the base class method in Mono.Android. This caused missing UCO wrappers, RegisterNatives, and empty JCW Java files. Add a third pass in CollectMarshalMethods that walks the base type find a matching registered base method. Also handles property overrides (e.g., Throwable.Message). Override detection is gated behind DoNotGenerateAcw — MCW framework types already have [Register] on every method that matters. Integration parity: ExactMarshalMethods_UserTypesFixture passes (exact parity for user types). ExactMarshalMethods_MonoAndroid has 8 known extras — internal Mono.Android types (InputStreamAdapter, JavaObject, OutputStreamAdapter) that override registered base methods without their own [Register]. The legacy scanner skips these because its JCW pipeline doesn't process them. These extras are harmless — the types have hand-written JCWs. A follow-up can update the parity test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The scanner doesn't detect Java constructors for user types whose
constructors lack [Register]. The legacy CecilImporter chains from
base registered ctors to derived unregistered ctors, but the new
scanner skips constructors in override detection (Pass 3) and
FindBaseRegisteredMethodInfo requires Virtual/Abstract (which ctors
are not).
Add [Register(".ctor", "()V", "")] to the Activity test fixture
to match real Mono.Android bindings, and add 10 tests:
- 7 failing: MainActivity/SimpleActivity should get JavaConstructors
- 3 passing: UserActivity/FullActivity (activation-only) and CustomView
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tors The scanner only found constructors with [Register] directly on them. User types (e.g., MainActivity) that have a parameterless constructor without [Register] were missing JavaConstructors, which meant no Java constructor in the JCW and no UCO constructor wrapper. Mirror the legacy CecilImporter behavior: walk the base type hierarchy to collect registered ctors, then accept non-activation ctors on the user type whose parameters are compatible with an accepted base ctor. Algorithm (Pass 4 in CollectMarshalMethods): 1. Collect registered ctors from base type hierarchy 2. For each non-activation ctor without [Register] on the user type 3. Find a base registered ctor with compatible parameters 4. Add it as a constructor marshal method using the base registration Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tests: - Consolidate 10 individual [Fact] into 5 focused tests. Each FindFixtureByJavaName call now has a single test with all assertions. Scanner (CollectBaseConstructorChain): - Remove explicit IsActivationCtor check. Activation ctors (IntPtr, JniHandleOwnership) will never match a base registered ctor because AreParametersCompatible already filters on type+count. Legacy CecilImporter doesn't skip them explicitly either. - Add DoNotGenerateAcw stop in CollectBaseRegisteredCtors: stop walking after the first MCW base type, matching legacy CecilImporter behavior (CecilImporter.cs:133-134). - Extract TryResolveBaseType helper to eliminate while(true) loop. - Document known remaining differences from legacy CecilImporter in the method summary (parameterless fallback, outerType, managed params). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Three changes to match legacy CecilImporter behavior exactly:
1. Decouple ctor chain from detectBaseOverrides flag
Pass 4 (CollectBaseConstructorChain) now runs for all types including
MCW types, matching legacy which runs constructor detection
unconditionally. Override detection (Pass 3) remains gated.
2. Handle JniConstructorSignatureAttribute
Java.Interop-style types use [JniConstructorSignature("()V")]
instead of [Register(".ctor", "()V", "")]. Add handling in
TryGetMethodRegisterInfo to convert it to a RegisterInfo with
JniName=".ctor" and the signature from the attribute arg.
Add JniConstructorSignatureAttribute stub and test fixture.
3. Implement parameterless base ctor fallback
Legacy CecilImporter (line 394-397) accepts a user ctor with novel
parameter types when any base has a registered parameterless ctor.
Compute the JNI signature from managed parameter types using
BuildJniCtorSignature. Add ActivityWithCustomCtor test fixture.
Update OverrideDetectionTests.MultipleOverrides_AllDetected to filter
out constructor marshal methods from the count assertion, since
FullActivity now correctly gets a ctor via the fallback path.
Known remaining generator-level differences (tracked separately):
- outerType / nested inner-class constructor handling
- Application synthetic constructor (MonoPackageManager.setContext)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The legacy side of the parity test (ScannerRunner.ExtractMethodRegistrations) only read [Register] attributes directly from a type's own methods. This missed overrides of registered base methods that the real legacy pipeline (CecilImporter.CreateType → GetBaseRegisteredMethod) correctly detects. Replace the hand-rolled attribute reader with CecilImporter.CreateType(), filtering out interface method implementations (which the new scanner places on the interface peer type, not the implementing type). Results after this fix: - ExactMarshalMethods_UserTypesFixture: PASSES (exact parity for user types) - ExactMarshalMethods_MonoAndroid: 22 remaining MISSING (down from 9047) These are covariant return type overrides and overloaded method variants that the new scanner's AreParametersCompatible doesn't yet handle. The legacy GetBaseDefinition uses looser matching. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Scanner: - Set SuperArgumentsString="" on fallback-path ctors so the generator emits super() instead of super(p0, ...). The Java ctor calls the base parameterless ctor, then delegates args to nctor_N(). Matches legacy CecilImporter which passes superCall="" for the fallback (CecilImporter.cs:396) vs null for compatible-params (line 391). Tests: - Use Assert.Single where exactly one item is expected - Assert specific JNI signatures and SuperArgumentsString on activation ctor fallback tests (UserActivity, FullActivity) - Move count assertion before Contains in OverrideDetectionTests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The legacy side of the parity test (ScannerRunner.ExtractMethodRegistrations) only read [Register] attributes directly from a type's own methods. This missed overrides of registered base methods that the real legacy pipeline (CecilImporter.CreateType → GetBaseRegisteredMethod) correctly detects. Replace the hand-rolled attribute reader with CecilImporter.CreateType() for non-DoNotGenerateAcw class types (matching the real build pipeline). Interface types and DoNotGenerateAcw types use direct attribute extraction since CecilImporter doesn't process them. Filter interface method implementations from the CecilImporter output since the new scanner places those on the interface peer type. Constructors are excluded from both sides of the comparison (compared separately in ExactJavaConstructors). Results: ExactMarshalMethods_MonoAndroid and ExactMarshalMethods_UserTypesFixture both pass with exact parity. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Scanner: - Seed all base registered ctors directly into JavaConstructors, matching legacy CecilImporter which adds base ctors to the wrapper during the reversed ctorTypes walk. This fixes Implementor types (e.g., IOnNavigationListenerImplementor) that have no registered ctors themselves but need the base ()V ctor. - Re-gate Pass 4 behind detectBaseOverrides. Legacy CecilImporter only processes ctors for types that go through CreateType (non-interface, non-DoNotGenerateAcw). MCW types use direct [Register] only. - Add ManagedTypeToJniDescriptorOrNull for the fallback path. Legacy GetJniSignature returns null for non-Java types (System.Object, System.IntPtr, System.Action, etc.), rejecting ctors with such params. Our fallback was incorrectly accepting them via the default Ljava/lang/Object; mapping. Now ctors with non-primitive, non-string params are skipped in the fallback, matching legacy. Integration tests: - Replace manual [Register] attribute scanning in TypeDataBuilder with real CecilImporter.CreateType to get accurate legacy ctor list including the base ctor chain. Add ExtractDirectRegisterCtors as fallback for interfaces and DoNotGenerateAcw types. Unit tests: - Update UserActivity/FullActivity to expect single ()V base seed (activation ctors rejected by the fallback's null-signature check). - Fix MixedMethods_NoDuplicates to dedupe by (JniName, JniSignature) since .ctor can appear multiple times with different signatures. All 235 unit tests and 10 integration tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CI enforces xUnit analyzers as errors. Replace Assert.Single(collection.Where(predicate)) with Assert.Single(collection, predicate). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Updates the TrimmableTypeMap Java peer scanning pipeline to match legacy JCW behavior for (1) overrides without [Register] and (2) constructor discovery via base-ctor chaining, and expands the test suite to validate parity against the real legacy Cecil-based pipeline.
Changes:
- Extend
JavaPeerScannerto detect base-registered method/property overrides and derive Java constructors from base registered constructors (including parameterless fallback). - Rework integration-test legacy extraction to use
CecilImporter.CreateType(instead of manual[Register]scanning) for accurate baseline comparison. - Add new fixtures and unit tests covering override and constructor-chain scenarios (including
JniConstructorSignatureAttribute).
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/Microsoft.Android.Sdk.TrimmableTypeMap/Scanner/JavaPeerScanner.cs |
Adds override detection and constructor chain detection passes; recognizes JniConstructorSignatureAttribute. |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/TestFixtures/TestTypes.cs |
Adds new fixture types for override + ctor-chain scenarios; adjusts Activity ctor registration. |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/TestFixtures/StubAttributes.cs |
Adds stub JniConstructorSignatureAttribute for unit tests. |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Scanner/OverrideDetectionTests.cs |
New unit tests validating override detection behavior. |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Scanner/ConstructorDetectionTests.cs |
New unit tests validating constructor chain detection behavior. |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.IntegrationTests/ScannerRunner.cs |
Legacy method extraction now uses CecilImporter.CreateType, with interface/MCW fallbacks and interface-impl filtering. |
tests/Microsoft.Android.Sdk.TrimmableTypeMap.IntegrationTests/TypeDataBuilder.cs |
Legacy ctor extraction now uses CecilImporter.CreateType, with fallback to direct attribute scanning. |
…ies, key consistency - Remove Signature! null-forgiving operator in CollectBaseConstructorChain; extract to local variable with null guard instead - Stop FindBaseRegisteredMethodInfo and FindBaseRegisteredProperty recursion at the DoNotGenerateAcw boundary (matching CollectBaseRegisteredCtors) - Use consistent signature-based key format in CollectBasePropertyOverrides (name + decoded params) to match Pass 1/2 key format - Merge duplicate if (detectBaseOverrides) blocks into a single block - Remove unnecessary try/catch fallback in TypeDataBuilder; let CecilImporter.CreateType failures propagate rather than silently falling back to different extraction logic - Replace default! with default in test fixture constructors (both params are value types, ! is unnecessary) - Consolidate OverrideDetectionTests: merge tests that look up the same fixture type into single Facts to reduce redundant lookups Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
simonrozsival
left a comment
There was a problem hiding this comment.
🤖 AI Review Summary
Verdict: ✅ LGTM
Found 0 issues in the updated diff.
The previous round of review feedback has been fully addressed:
Signature!null-forgiving operators replaced with proper null guardsFindBaseRegisteredMethodInfoandFindBaseRegisteredPropertynow stop atDoNotGenerateAcwboundary- Property override key format made consistent with Pass 1/2
default!replaced withdefaultin test fixtures- Bare
catchin TypeDataBuilder removed - Duplicate
if (detectBaseOverrides)blocks merged - Override detection tests consolidated (14→7 Facts, all assertions preserved)
👍 The override detection and constructor chaining logic is well-structured, thoroughly documented, and correctly mirrors legacy CecilImporter behavior. The 4-pass architecture (direct [Register], property [Register], base overrides, base ctor chain) has clear separation of concerns. Test coverage is comprehensive across edge cases (deep inheritance, new-slot exclusion, property overrides, JI-style attributes, parameterless fallback).
Review generated by android-reviewer from review guidelines.
FindBaseRegisteredMethod and FindBaseRegisteredProperty now populate DeclaringTypeName and DeclaringAssemblyName on MarshalMethodInfo so UCO wrappers call n_* callbacks on the correct base type (e.g., Activity.n_OnCreate) rather than the derived user type. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add deep hierarchy fixtures: BaseFragment → DerivedFragment → GrandchildFragment to test DeclaringTypeName resolution across ACW → ACW → MCW boundaries - Add DialogBase with registered ctor(Context) to test same-arity parameter type mismatch in AreParametersCompatible - Add ActivityWithMultiParamCtor to test multi-parameter JNI signature computation in BuildJniCtorSignature (string, int, bool → Ljava/lang/String;IZ) - Strengthen DeepInheritance test to verify DeclaringTypeName == Activity - Strengthen MultipleOverrides test comment: exact count proves non-registered Object virtuals (ToString/Equals/GetHashCode) are correctly excluded Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Legacy GetBaseRegisteredMethod (via GetBaseDefinition) walks ALL base types with no DoNotGenerateAcw stop — only the constructor chain has that boundary. Remove the boundary check from FindBaseRegisteredMethodInfo and FindBaseRegisteredProperty to match legacy behavior exactly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CecilImporter.CreateType failures should propagate — this is test infrastructure matching legacy behavior, not extending it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…omparison Interface method implementations are collected by both CecilImporter (legacy) and CollectInterfaceMethodImplementations (new scanner) but through different codepaths with different deduplication strategies. Filter them from both sides of the ExactMarshalMethods comparison since interface methods are tested via interface peer types. Added IsInterfaceImplementation flag to MarshalMethodInfo so the new scanner side can identify and filter these methods in the comparison. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ExtractMethodRegistrations used wrapper.Methods[].Name (managed method name, e.g., 'DoWork') instead of .JavaName (JNI name, e.g., 'doWork'). For [Export] methods, these differ — the JNI name comes from the Export attribute. The new scanner correctly uses the JNI name, so the legacy comparison must too. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
GetCecilJavaName only read [Register] attributes, silently skipping types like ActivityTracker that get their JNI name computed by JavaNativeTypeManager.ToJniName. This matches what CecilImporter.CreateType does (line 26). Also removes the interface method filtering from both legacy and new scanner sides of the comparison — both sides now correctly discover and include interface method implementations for all types. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ManagedTypeToJniDescriptorOrNull returned null for Java peer object types like Java.Security.Cert.X509Certificate, causing ctors that take these types to be skipped entirely. Now looks up the managed type name in assemblyCache to find its [Register] JNI name and emits L<jniName>; — matching legacy JavaNativeTypeManager.GetJniTypeName behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ResolveBaseJavaName returned null for base types like XmlReaderPullParser that have no [Register] attribute but are Java peers (they extend Java.Lang.Object and get auto-computed JNI names). When the base type isn't found in already-scanned results (scan order within an assembly is not guaranteed), fall back to resolving it the same way ScanAssembly does: check ExtendsJavaPeer and compute the auto JNI name via ComputeAutoJniNames. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Now that GetCecilJavaName uses ToJniName fallback, every type from javaTypes gets a JNI name and is added to methodsByJavaName. The fallback loop that added types from dataSets with 0 methods is no longer reachable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Both scanners discover constructors — compare them directly instead of excluding them. Legacy side now includes wrapper.Constructors, new scanner side no longer filters IsConstructor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
simonrozsival
left a comment
There was a problem hiding this comment.
🤖 AI Review Summary
Verdict: ✅ LGTM
Found 0 issues across 14 changed files (~1800 additions).
No null-forgiving operators, no empty catch blocks, no filtering or hidden data in scanner comparison. Both RunLegacy and RunNew produce complete unfiltered output (methods, properties, interface implementations, constructors) compared 1:1 across ~8000 Mono.Android types.
The 5-pass scanner architecture is well-structured:
- Pass 1-2: direct
[Register]/[Export]on methods and properties - Pass 3: override detection walking base hierarchy (no DoNotGenerateAcw boundary, matching legacy
GetBaseDefinition) - Pass 4: interface method implementations
- Pass 5: constructor chaining with parameterless fallback
The integration test harness fixes (4 bugs) are clearly separated in commits and correctly documented as supporting infrastructure.
Review generated by android-reviewer from review guidelines.
…patible - Extract TryGetPrimitiveJniDescriptor shared by both ManagedTypeToJniDescriptor (falls back to Ljava/lang/Object;) and ManagedTypeToJniDescriptorOrNull (looks up assemblyCache, returns null) - Rename AreParametersCompatible to HaveIdenticalParameterTypes — the method checks for exact type match, not compatibility - Remove unused index1/index2 parameters from HaveIdenticalParameterTypes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ilerplate Extended TryResolveBaseType with baseTypeName/baseAssemblyName out params. Used it in FindBaseRegisteredMethodInfo, FindBaseRegisteredProperty, and ResolveBaseJavaName to replace repeated GetBaseTypeInfo → TryResolveType → GetTypeDefinition boilerplate (~20 lines removed). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rays, interface inheritance - DerivedFragment onViewCreated DeclaringTypeName → BaseFragment (ACW→ACW) - ConcreteImpl overrides abstract DoWork (abstract base detection) - OverloadDerived overrides Process(int) but not Process() (correct overload) - EmptyConnector override still detected (Activity.OnStart has empty connector) - ViewArrayActivity ctor(View[]) → [Landroid/view/View; (object array JNI) - UnsignedParamActivity ctor(ushort,uint,ulong) → (SIJ)V (unsigned primitives) - NamedClickListenerImpl gets methods from parent interface (interface inheritance) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ions Interface method and property collection was manually creating MarshalMethodInfo with the same field logic as AddMarshalMethod. Now calls AddMarshalMethod with isInterfaceImplementation parameter, removing ~20 lines of duplicated MarshalMethodInfo construction. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
simonrozsival
left a comment
There was a problem hiding this comment.
🤖 AI Review Summary
Verdict: ✅ LGTM
Found 0 issues across 14 changed files (~2400 line diff).
No null-forgiving operators, no empty catch blocks, no filtering or hidden data in the comparison. Code duplication has been addressed:
TryResolveBaseTypeextended to share base type resolution across 3 methodsTryGetPrimitiveJniDescriptorextracted to share JNI mapping between nullable and non-nullable variantsAddMarshalMethodreused inCollectInterfaceMethodImplementations(eliminated ~20 lines of duplicatedMarshalMethodInfoconstruction)HaveIdenticalParameterTypesrenamed fromAreParametersCompatiblewith unused params removed
Test coverage is comprehensive: 254 unit tests + 10 integration tests. Recent additions cover abstract base overrides, correct overload selection, Java peer object arrays in ctor signatures, unsigned primitives, empty connectors, interface inheritance chains, and ACW→ACW DeclaringTypeName resolution.
Review generated by android-reviewer from review guidelines.
TL;DR
JavaPeerScannernow matches legacyCecilImporteroutput for method overrides, constructor chaining, and interface implementations. The scanner uses a 5-pass approach: direct[Register], property[Register], base class override detection, interface method detection, and constructor chain detection. Also fixes 4 bugs in the integration test harness that were hiding mismatches between legacy and new scanner output. Validated with zero divergence across ~8000 Mono.Android types — no filtering, direct 1:1 comparison.247 unit tests + 10 integration tests pass.
Part of #10789
Context
The
JavaPeerScannerwas missing several categories of methods that the legacyCecilImporterfinds:Method overrides without
[Register]— User types (e.g.,MainActivity) overrideActivity.OnCreate()without[Register]on the override. The attribute is only on the base class method in Mono.Android.Java constructors via base ctor chaining — User types have non-activation constructors without
[Register]. The legacyCecilImporterwalks the base type hierarchy, seeds registered ctors, and accepts derived ctors with compatible parameters.Constructor parameter JNI signatures for object types — Ctors taking Java peer types (e.g.,
X509Certificate[]) needL<jniName>;descriptors, not just primitive mappings.Base JNI name for types without
[Register]— Types likeXmlReaderPullParserhave no[Register]but are Java peers with auto-computed JNI names.ResolveBaseJavaNameneeds to compute these on demand.Scanner architecture
The scanner's
CollectMarshalMethodsnow uses a 5-pass approach:Changes
Scanner (
JavaPeerScanner.cs,JavaPeerInfo.cs)Pass 3 — Override detection: For each virtual override without
[Register], walks the base hierarchy to find the registered base method and copies its registration info. Also handles property overrides (e.g.,Throwable.Message). PopulatesDeclaringTypeName/DeclaringAssemblyNameso UCO wrappers calln_*on the correct base type. Walks all base types with no DoNotGenerateAcw boundary — matching legacyGetBaseDefinition/GetBaseRegisteredMethod.Pass 5 — Constructor chain detection: Mirrors legacy
CecilImporterbehavior:()Vctor, accepts derived ctors with novel params (generatessuper()call viaSuperArgumentsString="")System.IntPtr,System.Action, etc.)X509Certificate) toL<jniName>;via assembly cache lookup[JniConstructorSignature](Java.Interop-style) in addition to[Register]DoNotGenerateAcwboundary (matching legacy)ResolveBaseJavaName— Now computes auto JNI names for base types without[Register]when they haven't been scanned yet (scan order within an assembly is not guaranteed).ManagedTypeToJniDescriptorOrNull— Now resolves Java peer object types by looking up their[Register]JNI name in the assembly cache.Unit tests + fixtures
OverrideDetectionTests(10 tests) — overrides without[Register], deep inheritance (3 levels), ACW→ACW→MCW hierarchy, property overrides, mixed methods, new-slot exclusion, DeclaringTypeName verificationConstructorDetectionTests(9 tests) — base ctor chain, implicit default ctor, base ctor seed,JniConstructorSignature, parameterless fallback, same-arity type mismatch, multi-parameter signature computationUserActivity,FullActivity,DeeplyDerived,MixedMethods,NewSlotActivity,CustomException,BaseFragment,DerivedFragment,GrandchildFragment,JiStyleView,ActivityWithCustomCtor,DialogBase,CustomDialog,ActivityWithMultiParamCtorIntegration test harness improvements
The following changes are not directly related to the scanner features above, but were necessary to properly validate them. The scanner now produces more complete output (interface methods, constructors with object type params, types without
[Register]), which exposed pre-existing bugs in how the legacy test harness transformsCecilImporteroutput for comparison.GetCecilJavaName— AddedJavaNativeTypeManager.ToJniNamefallback for types without[Register](e.g.,ActivityTracker). Previously returnednull, silently skipping these types. Now matches whatCecilImporter.CreateTypeactually does.ExtractMethodRegistrations— Fixed to usem.JavaName(JNI name) instead ofm.Name(managed name) for[Export]methods. Now includes constructors fromwrapper.Constructorsso both scanners' constructors are compared directly.Removed all filtering — No more interface method filtering, no phantom entry fallback, no constructor exclusion. Both
RunLegacyandRunNewproduce complete unfiltered output compared 1:1 across ~8000 Mono.Android types.Related issue
Filed #10931 —
JcwJavaSourceGeneratormust skipregisterNativesin the static block for Application/Instrumentation types.Test results
ExactMarshalMethods_MonoAndroidandExactJavaConstructors_MonoAndroid— no filtering, direct 1:1 comparison)Legacy comparison notes
GetBaseDefinition→GetBaseRegisteredMethod: walks all base types (no DoNotGenerateAcw boundary), checksVirtual || Abstract, matches by name + parameter compatibility.ctorTypesloop (CecilImporter.cs:124-160): stops at DoNotGenerateAcw, seeds registered base ctors, checksAreParametersCompatibleWith, falls back to parameterlesssuper().GetJniTypeName: resolves Java peer types toL<jniName>;via[Register]lookup, returns null for non-Java types.a.FullName == b.FullNamefor non-generic cases. Validated against ~8000 types with zero divergence.