diff --git a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs index 95eb8c871..542dc8404 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 = ((method.AccessFlags ^ MethodAccessFlags.Public) & 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..0a8f03f37 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinUtilities.cs @@ -72,6 +72,26 @@ 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; + + // Parameter list ends with `int, DefaultConstructorMarker`. + return parameters [parameters.Length - 2].Type.TypeSignature == "I" && + parameters [parameters.Length - 1].Type.TypeSignature == "Lkotlin/jvm/internal/DefaultConstructorMarker;"; + } + 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/Resources/JvmOverloadsConstructor.xml b/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JvmOverloadsConstructor.xml index 3cf7ae7e2..91dfbc19a 100644 --- a/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JvmOverloadsConstructor.xml +++ b/tests/Xamarin.Android.Tools.Bytecode-Tests/Resources/JvmOverloadsConstructor.xml @@ -75,44 +75,6 @@ type="boolean" jni-type="Z" /> - - - - - - - - -