From 0548786d3258de6ef1ac41b7af8075c83e4c4e5d Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Fri, 18 Sep 2020 10:11:04 -0500 Subject: [PATCH] [Bytecode] Hide nested types inside hidden Kotlin types. --- .../Kotlin/KotlinFixups.cs | 30 +++++++++++++++--- .../KotlinFixupsTests.cs | 9 ++++++ .../kotlin/InternalClass.class | Bin 460 -> 539 bytes .../kotlin/InternalClass.kt | 4 ++- .../kotlin/InternalInterface.class | Bin 318 -> 403 bytes .../kotlin/InternalInterface.kt | 4 ++- 6 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs index 542dc8404..ae4d78077 100644 --- a/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs +++ b/src/Xamarin.Android.Tools.Bytecode/Kotlin/KotlinFixups.cs @@ -67,21 +67,41 @@ static void FixupClassVisibility (ClassFile klass, KotlinClass metadata) // Hide class if it isn't Public/Protected if (klass.AccessFlags.IsPubliclyVisible () && !metadata.Visibility.IsPubliclyVisible ()) { - // Interfaces should be set to "package-private", which is "no visibility flags" + // Interfaces should be set to "package-private" if (klass.AccessFlags.HasFlag (ClassAccessFlags.Interface)) { - Log.Debug ($"Kotlin: Setting interface {klass.ThisClass.Name.Value} to package-private"); - klass.AccessFlags = (klass.AccessFlags ^ ClassAccessFlags.Public) & klass.AccessFlags; - klass.AccessFlags = (klass.AccessFlags ^ ClassAccessFlags.Protected) & klass.AccessFlags; - klass.AccessFlags = (klass.AccessFlags ^ ClassAccessFlags.Private) & klass.AccessFlags; + Log.Debug ($"Kotlin: Setting internal interface {klass.ThisClass.Name.Value} to package-private"); + klass.AccessFlags = SetPackagePrivate (klass.AccessFlags); + + foreach (var ic in klass.InnerClasses) { + Log.Debug ($"Kotlin: Setting nested type {ic.InnerClass.Name.Value} in an internal interface to package-private"); + ic.InnerClassAccessFlags = SetPackagePrivate (ic.InnerClassAccessFlags); + } + return; } Log.Debug ($"Kotlin: Hiding internal class {klass.ThisClass.Name.Value}"); klass.AccessFlags = ClassAccessFlags.Private; + + foreach (var ic in klass.InnerClasses) { + Log.Debug ($"Kotlin: Hiding nested internal type {ic.InnerClass.Name.Value}"); + ic.InnerClassAccessFlags = ClassAccessFlags.Private; + } + return; } } + static ClassAccessFlags SetPackagePrivate (ClassAccessFlags flags) + { + // Package-private is stored as "no visibility flags" + flags = (flags ^ ClassAccessFlags.Public) & flags; + flags = (flags ^ ClassAccessFlags.Protected) & flags; + flags = (flags ^ ClassAccessFlags.Private) & flags; + + return flags; + } + static void FixupJavaMethods (Methods methods) { // We do the following method level fixups here because we can operate on all methods, diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs b/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs index fed16412d..05e813456 100644 --- a/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs +++ b/tests/Xamarin.Android.Tools.Bytecode-Tests/KotlinFixupsTests.cs @@ -15,20 +15,25 @@ public class KotlinFixupsTests : ClassFileFixture public void HideInternalClass () { var klass = LoadClassFile ("InternalClass.class"); + var inner_class = klass.InnerClasses.First (); Assert.True (klass.AccessFlags.HasFlag (ClassAccessFlags.Public)); + Assert.True (inner_class.InnerClassAccessFlags.HasFlag (ClassAccessFlags.Public)); KotlinFixups.Fixup (new [] { klass }); Assert.False (klass.AccessFlags.HasFlag (ClassAccessFlags.Public)); + Assert.False (inner_class.InnerClassAccessFlags.HasFlag (ClassAccessFlags.Public)); } [Test] public void MakeInternalInterfacePackagePrivate () { var klass = LoadClassFile ("InternalInterface.class"); + var inner_class = klass.InnerClasses.First (); Assert.True (klass.AccessFlags.HasFlag (ClassAccessFlags.Public)); + Assert.True (inner_class.InnerClassAccessFlags.HasFlag (ClassAccessFlags.Public)); KotlinFixups.Fixup (new [] { klass }); @@ -36,6 +41,10 @@ public void MakeInternalInterfacePackagePrivate () Assert.False (klass.AccessFlags.HasFlag (ClassAccessFlags.Public)); Assert.False (klass.AccessFlags.HasFlag (ClassAccessFlags.Protected)); Assert.False (klass.AccessFlags.HasFlag (ClassAccessFlags.Private)); + + Assert.False (inner_class.InnerClassAccessFlags.HasFlag (ClassAccessFlags.Public)); + Assert.False (inner_class.InnerClassAccessFlags.HasFlag (ClassAccessFlags.Protected)); + Assert.False (inner_class.InnerClassAccessFlags.HasFlag (ClassAccessFlags.Private)); } [Test] diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalClass.class b/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalClass.class index aa615c801e97fdeecb0d041733703af99bec4e66..5708648aaf676e25f3b46f9db25d548352f3d1d7 100644 GIT binary patch delta 230 zcmX@ZJe!5<)W2Q(7#J9g7!)UR%?MXL(7?mRB*DbRBygaCi;07Y<3NMNfd(Tc14b)G zW+&D|i`bY1m>3zDQj8cG7#JBioij3XQe5*&a~T=LJ@ZOZi}Dh4oO2S3i&fw<>>i9ekudo$X&NB}kKGcW=n0|Tqpb_R}(Kn4?oB#>kS3ovl3?Ou5&*IeG;kzH9B43NGGMe~WSZEe z5XkAAk(ra?npc|3$RO>RSCU$kmzV>l(-MWr>L%XyD*tl3?Ou5&*IiBn~tfF&QvUoS-oAuJ~kT gMiYJ}24SFTCI%q}5g=_fIgHVmovD~XpqN1r06m5gO8@`> diff --git a/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalInterface.kt b/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalInterface.kt index 382d3537c..3a109d6ad 100644 --- a/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalInterface.kt +++ b/tests/Xamarin.Android.Tools.Bytecode-Tests/kotlin/InternalInterface.kt @@ -1 +1,3 @@ -internal interface InternalInterface \ No newline at end of file +internal interface InternalInterface { + enum class ChildEnum { VALUE1, VALUE2 } +} \ No newline at end of file