Skip to content

Commit 4e364ba

Browse files
jpobstjonpryor
authored andcommitted
[generator] Ensure all intended ctors get generated. (#434)
Context: https://bugzilla.novell.com/show_bug.cgi?id=632575 As part of a [long-ago size optimization][0], `ClassGen` does not bind `protected` constructors on `final` (`sealed`) types, as they are inaccessible. Skipping such constructors "save[d] 250KB" in `Mono.Android.dll` (in 2010!). The optimization itself was fine. Between then and now, though, `ClassGen.GenConstructors()` changed such that when applying the optimization, it would (accidentally) *skip subsequent constructors*. Thus, given the Java type: public final class JavaExample { protected JavaExample () {} public JavaExample (int value) {} } *no* public constructor may be generated, because: 1. `JavaExample` cannot be subclassed, and 2. `JavaExample` contained a `protected` constructor *first*. Oops. Fix `ClassGen.GenConstructors()` so that we only skip `protected` constructors and *continue binding* subsequent, non-`protected` constructors. [0]: https://github.com/xamarin/monodroid/commit/480e4c1403156056967f4ee767ec77b2f0be1185
1 parent 94b9551 commit 4e364ba

File tree

4 files changed

+71
-2
lines changed

4 files changed

+71
-2
lines changed

tools/generator/ClassGen.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ void GenConstructors (StreamWriter sw, string indent, CodeGenerationOptions opt)
313313

314314
foreach (Ctor ctor in ctors) {
315315
if (IsFinal && ctor.Visibility == "protected")
316-
return;
316+
continue;
317317
ctor.Name = Name;
318318
ctor.Generate (sw, indent, opt, inherits_object, this);
319319
}

tools/generator/Tests/expected.ji/Constructors/Mono.Android.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<Compile Include="$(MSBuildThisFileDirectory)\Java.Interop.__TypeRegistrations.cs" />
99
<Compile Include="$(MSBuildThisFileDirectory)\Java.Lang.Object.cs" />
1010
<Compile Include="$(MSBuildThisFileDirectory)\Xamarin.Test.SomeObject.cs" />
11+
<Compile Include="$(MSBuildThisFileDirectory)\Xamarin.Test.SomeObject2.cs" />
1112
<Compile Include="$(MSBuildThisFileDirectory)\__NamespaceMapping__.cs" />
1213
</ItemGroup>
1314
<!-- Enums -->

tools/generator/Tests/expected/Constructors/Constructors.xml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.0" encoding="UTF-8" ?>
1+
<?xml version="1.0" encoding="UTF-8" ?>
22
<api>
33
<package name="java.lang">
44
<class abstract="false" deprecated="not deprecated" final="false" name="Object" static="false" visibility="public">
@@ -14,6 +14,15 @@
1414
</parameter>
1515
</constructor>
1616
</class>
17+
<class abstract="false" deprecated="not deprecated" extends="java.lang.Object" extends-generic-aware="java.lang.Object"
18+
final="true" name="SomeObject2" static="false" visibility="public">
19+
<constructor deprecated="not deprecated" final="false" name="SomeObject" static="false" type="xamarin.test.SomeObject" visibility="protected">
20+
</constructor>
21+
<constructor deprecated="not deprecated" final="false" name="SomeObject" static="false" type="xamarin.test.SomeObject" visibility="public">
22+
<parameter name="aint" type="int">
23+
</parameter>
24+
</constructor>
25+
</class>
1726
</package>
1827
</api>
1928

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Android.Runtime;
4+
5+
namespace Xamarin.Test {
6+
7+
// Metadata.xml XPath class reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject2']"
8+
[global::Android.Runtime.Register ("xamarin/test/SomeObject2", DoNotGenerateAcw=true)]
9+
public sealed partial class SomeObject2 : global::Java.Lang.Object {
10+
11+
internal static new IntPtr java_class_handle;
12+
internal static new IntPtr class_ref {
13+
get {
14+
return JNIEnv.FindClass ("xamarin/test/SomeObject2", ref java_class_handle);
15+
}
16+
}
17+
18+
protected override IntPtr ThresholdClass {
19+
get { return class_ref; }
20+
}
21+
22+
protected override global::System.Type ThresholdType {
23+
get { return typeof (SomeObject2); }
24+
}
25+
26+
internal SomeObject2 (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {}
27+
28+
static IntPtr id_ctor_I;
29+
// Metadata.xml XPath constructor reference: path="/api/package[@name='xamarin.test']/class[@name='SomeObject2']/constructor[@name='SomeObject2' and count(parameter)=1 and parameter[1][@type='int']]"
30+
[Register (".ctor", "(I)V", "")]
31+
public unsafe SomeObject2 (int aint)
32+
: base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer)
33+
{
34+
if (((global::Java.Lang.Object) this).Handle != IntPtr.Zero)
35+
return;
36+
37+
try {
38+
JValue* __args = stackalloc JValue [1];
39+
__args [0] = new JValue (aint);
40+
if (((object) this).GetType () != typeof (SomeObject2)) {
41+
SetHandle (
42+
global::Android.Runtime.JNIEnv.StartCreateInstance (((object) this).GetType (), "(I)V", __args),
43+
JniHandleOwnership.TransferLocalRef);
44+
global::Android.Runtime.JNIEnv.FinishCreateInstance (((global::Java.Lang.Object) this).Handle, "(I)V", __args);
45+
return;
46+
}
47+
48+
if (id_ctor_I == IntPtr.Zero)
49+
id_ctor_I = JNIEnv.GetMethodID (class_ref, "<init>", "(I)V");
50+
SetHandle (
51+
global::Android.Runtime.JNIEnv.StartCreateInstance (class_ref, id_ctor_I, __args),
52+
JniHandleOwnership.TransferLocalRef);
53+
JNIEnv.FinishCreateInstance (((global::Java.Lang.Object) this).Handle, class_ref, id_ctor_I, __args);
54+
} finally {
55+
}
56+
}
57+
58+
}
59+
}

0 commit comments

Comments
 (0)