From 4d8b8aab65a35141fed806cf16c3d1d591bd5d23 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Thu, 27 Aug 2020 14:07:58 -0500 Subject: [PATCH] [Bytecode] Hide Kotlin synthetic default constructors. --- .../Kotlin/KotlinFixups.cs | 6 ++++ .../Kotlin/KotlinUtilities.cs | 23 ++++++++++++++++ .../KotlinFixupsTests.cs | 26 ++++++++++++++++++ .../kotlin/DefaultConstructor.class | Bin 0 -> 982 bytes .../kotlin/DefaultConstructor.kt | 2 ++ tools/generator/generator.slnf | 2 ++ 6 files changed, 59 insertions(+) create mode 100644 tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DefaultConstructor.class create mode 100644 tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DefaultConstructor.kt diff --git a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs index 95eb8c871..75f3aeabe 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs @@ -93,6 +93,12 @@ static void FixupJavaMethods (Methods methods) method.AccessFlags = MethodAccessFlags.Private; } + // Hide constructor if it's the synthetic DefaultConstructorMarker one + foreach (var method in methods.Where (method => method.IsDefaultConstructorMarker ())) { + Log.Debug ($"Kotlin: Hiding synthetic default constructor in class '{method.DeclaringType?.ThisClass.Name.Value}' with signature '{method.Descriptor}'"); + method.AccessFlags = MethodAccessFlags.Private; + } + // Better parameter names in extension methods foreach (var method in methods.Where (m => m.IsPubliclyVisible && m.AccessFlags.HasFlag (MethodAccessFlags.Static))) FixupExtensionMethod (method); diff --git a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs index fd9e692f7..be7033625 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs @@ -72,6 +72,29 @@ public static string GetMethodNameWithoutSuffix (this MethodInfo method) return index >= 0 ? method.Name.Substring (0, index) : method.Name; } + public static bool IsDefaultConstructorMarker (this MethodInfo method) + { + // A default constructor is synthetic and always has an int and a + // DefaultConstructorMarker as its final 2 parameters. + if (method.Name != "") + return false; + + if (!method.AccessFlags.HasFlag (MethodAccessFlags.Synthetic)) + return false; + + var parameters = method.GetParameters (); + + if (parameters.Length < 2) + return false; + + // Final parameter is DefaultConstructorMarker + if (parameters.Last ().Type.TypeSignature != "Lkotlin/jvm/internal/DefaultConstructorMarker;") + return false; + + // Next to final parameter is int + return parameters [parameters.Length - 2].Type.TypeSignature == "I"; + } + public static bool IsPubliclyVisible (this ClassAccessFlags flags) => flags.HasFlag (ClassAccessFlags.Public) || flags.HasFlag (ClassAccessFlags.Protected); public static bool IsPubliclyVisible (this KotlinClassVisibility flags) => flags == KotlinClassVisibility.Public || flags == KotlinClassVisibility.Protected; diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs b/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs index ddaf5c9e6..fed16412d 100644 --- a/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs +++ b/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs @@ -51,6 +51,32 @@ public void HideInternalConstructor () Assert.False (ctor.AccessFlags.HasFlag (MethodAccessFlags.Public)); } + [Test] + public void HideDefaultConstructorMarker () + { + var klass = LoadClassFile ("DefaultConstructor.class"); + + // init () + var ctor_0p = klass.Methods.Single (m => m.Name == "" && m.GetParameters ().Length == 0); + + // init (string name) + var ctor_1p = klass.Methods.Single (m => m.Name == "" && m.GetParameters ().Length == 1); + + // init (string p0, int p1, DefaultConstructorMarker p2) + var ctor_3p = klass.Methods.Single (m => m.Name == "" && m.GetParameters ().Length == 3); + + Assert.True (ctor_3p.AccessFlags.HasFlag (MethodAccessFlags.Public)); + + KotlinFixups.Fixup (new [] { klass }); + + // Assert that the normal constructors are still public + Assert.True (ctor_0p.AccessFlags.HasFlag (MethodAccessFlags.Public)); + Assert.True (ctor_1p.AccessFlags.HasFlag (MethodAccessFlags.Public)); + + // Assert that the synthetic "DefaultConstructorMarker" constructor has been marked private + Assert.False (ctor_3p.AccessFlags.HasFlag (MethodAccessFlags.Public)); + } + [Test] public void HideImplementationMethod () { diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DefaultConstructor.class b/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DefaultConstructor.class new file mode 100644 index 0000000000000000000000000000000000000000..491cd1975253a9b83031568586379a4911aff71a GIT binary patch literal 982 zcmZuvT~8B16g@L7?XrAyS<9!0AD}={7I?*I6k^h3K_jLwJk2g6OuL;myVE`z{)Vsq z1D`NH7~-Qp%6O+Of+@-D%sqGRIdkUD{{HjhCx9JnGx+=Rqv#}NFV(rpIv zJ-qEE!NJ4c)MGmcVl*{5R7^d z7Sh|W7Nt(;NrTIC&*gL6<=*AFOM`opw9H+e@9-`5y5c(y_xJ+eD*XCd;$G3xb{Oem zdf4w~%TSN@(i6#036++IopvO%4G9qprh))BWdz5yvSiVtKcz&SK=qubHVw)ONq$|^<$ujkhaE;JQS~;y_8~*5b zRB9LSzY*lvpt(e)_Ipb4Our0wP$fhJIGCorXB3yIk0=A4Ri2^PDsK_No>*Bde*S`z zKNr?EF0jy7-=qyPGWy>!mhBDLRpL^2;nY}>U0~7DtgWCouai2kM-}&ovviC?9rt_V h0UlnVM|CV?g|c{j43^^wR*x}~qncwahtr!&e*qcO+>!tQ literal 0 HcmV?d00001 diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DefaultConstructor.kt b/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DefaultConstructor.kt new file mode 100644 index 000000000..ce8653b26 --- /dev/null +++ b/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/DefaultConstructor.kt @@ -0,0 +1,2 @@ +class DefaultConstructor (name: String = "bob") { +} diff --git a/tools/generator/generator.slnf b/tools/generator/generator.slnf index f222103bf..f697d9753 100644 --- a/tools/generator/generator.slnf +++ b/tools/generator/generator.slnf @@ -9,8 +9,10 @@ "src\\Java.Interop.Tools.Diagnostics\\Java.Interop.Tools.Diagnostics.csproj", "src\\Xamarin.Android.Tools.AnnotationSupport\\Xamarin.Android.Tools.AnnotationSupport.csproj", "src\\Xamarin.Android.Tools.ApiXmlAdjuster\\Xamarin.Android.Tools.ApiXmlAdjuster.csproj", + "src\\Xamarin.Android.Tools.Bytecode\\Xamarin.Android.Tools.Bytecode.csproj", "src\\Xamarin.SourceWriter\\Xamarin.SourceWriter.csproj", "tests\\generator-Tests\\generator-Tests.csproj", + "tests\\Xamarin.Android.Tools.Bytecode-Tests\\Xamarin.Android.Tools.Bytecode-Tests.csproj", "tests\\Xamarin.SourceWriter-Tests\\Xamarin.SourceWriter-Tests.csproj", "tools\\generator\\generator.csproj", ]