Skip to content

Commit 4d8b8aa

Browse files
committed
[Bytecode] Hide Kotlin synthetic default constructors.
1 parent dcaf794 commit 4d8b8aa

File tree

6 files changed

+59
-0
lines changed

6 files changed

+59
-0
lines changed

src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ static void FixupJavaMethods (Methods methods)
9393
method.AccessFlags = MethodAccessFlags.Private;
9494
}
9595

96+
// Hide constructor if it's the synthetic DefaultConstructorMarker one
97+
foreach (var method in methods.Where (method => method.IsDefaultConstructorMarker ())) {
98+
Log.Debug ($"Kotlin: Hiding synthetic default constructor in class '{method.DeclaringType?.ThisClass.Name.Value}' with signature '{method.Descriptor}'");
99+
method.AccessFlags = MethodAccessFlags.Private;
100+
}
101+
96102
// Better parameter names in extension methods
97103
foreach (var method in methods.Where (m => m.IsPubliclyVisible && m.AccessFlags.HasFlag (MethodAccessFlags.Static)))
98104
FixupExtensionMethod (method);

src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,29 @@ public static string GetMethodNameWithoutSuffix (this MethodInfo method)
7272
return index >= 0 ? method.Name.Substring (0, index) : method.Name;
7373
}
7474

75+
public static bool IsDefaultConstructorMarker (this MethodInfo method)
76+
{
77+
// A default constructor is synthetic and always has an int and a
78+
// DefaultConstructorMarker as its final 2 parameters.
79+
if (method.Name != "<init>")
80+
return false;
81+
82+
if (!method.AccessFlags.HasFlag (MethodAccessFlags.Synthetic))
83+
return false;
84+
85+
var parameters = method.GetParameters ();
86+
87+
if (parameters.Length < 2)
88+
return false;
89+
90+
// Final parameter is DefaultConstructorMarker
91+
if (parameters.Last ().Type.TypeSignature != "Lkotlin/jvm/internal/DefaultConstructorMarker;")
92+
return false;
93+
94+
// Next to final parameter is int
95+
return parameters [parameters.Length - 2].Type.TypeSignature == "I";
96+
}
97+
7598
public static bool IsPubliclyVisible (this ClassAccessFlags flags) => flags.HasFlag (ClassAccessFlags.Public) || flags.HasFlag (ClassAccessFlags.Protected);
7699

77100
public static bool IsPubliclyVisible (this KotlinClassVisibility flags) => flags == KotlinClassVisibility.Public || flags == KotlinClassVisibility.Protected;

tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,32 @@ public void HideInternalConstructor ()
5151
Assert.False (ctor.AccessFlags.HasFlag (MethodAccessFlags.Public));
5252
}
5353

54+
[Test]
55+
public void HideDefaultConstructorMarker ()
56+
{
57+
var klass = LoadClassFile ("DefaultConstructor.class");
58+
59+
// init ()
60+
var ctor_0p = klass.Methods.Single (m => m.Name == "<init>" && m.GetParameters ().Length == 0);
61+
62+
// init (string name)
63+
var ctor_1p = klass.Methods.Single (m => m.Name == "<init>" && m.GetParameters ().Length == 1);
64+
65+
// init (string p0, int p1, DefaultConstructorMarker p2)
66+
var ctor_3p = klass.Methods.Single (m => m.Name == "<init>" && m.GetParameters ().Length == 3);
67+
68+
Assert.True (ctor_3p.AccessFlags.HasFlag (MethodAccessFlags.Public));
69+
70+
KotlinFixups.Fixup (new [] { klass });
71+
72+
// Assert that the normal constructors are still public
73+
Assert.True (ctor_0p.AccessFlags.HasFlag (MethodAccessFlags.Public));
74+
Assert.True (ctor_1p.AccessFlags.HasFlag (MethodAccessFlags.Public));
75+
76+
// Assert that the synthetic "DefaultConstructorMarker" constructor has been marked private
77+
Assert.False (ctor_3p.AccessFlags.HasFlag (MethodAccessFlags.Public));
78+
}
79+
5480
[Test]
5581
public void HideImplementationMethod ()
5682
{
982 Bytes
Binary file not shown.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class DefaultConstructor (name: String = "bob") {
2+
}

tools/generator/generator.slnf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
"src\\Java.Interop.Tools.Diagnostics\\Java.Interop.Tools.Diagnostics.csproj",
1010
"src\\Xamarin.Android.Tools.AnnotationSupport\\Xamarin.Android.Tools.AnnotationSupport.csproj",
1111
"src\\Xamarin.Android.Tools.ApiXmlAdjuster\\Xamarin.Android.Tools.ApiXmlAdjuster.csproj",
12+
"src\\Xamarin.Android.Tools.Bytecode\\Xamarin.Android.Tools.Bytecode.csproj",
1213
"src\\Xamarin.SourceWriter\\Xamarin.SourceWriter.csproj",
1314
"tests\\generator-Tests\\generator-Tests.csproj",
15+
"tests\\Xamarin.Android.Tools.Bytecode-Tests\\Xamarin.Android.Tools.Bytecode-Tests.csproj",
1416
"tests\\Xamarin.SourceWriter-Tests\\Xamarin.SourceWriter-Tests.csproj",
1517
"tools\\generator\\generator.csproj",
1618
]

0 commit comments

Comments
 (0)