Skip to content

Commit 212a9f0

Browse files
committed
[XA.Tools.Bytecode] Add unit tests.
1 parent c39cb87 commit 212a9f0

31 files changed

+280
-43
lines changed

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

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,15 @@ public class KotlinClass : KotlinFile
3434
public List<string> EnumEntries { get; set; }
3535
public KotlinClassFlags Flags { get; set; }
3636
public string FullyQualifiedName { get; set; }
37+
public KotlinClassInheritability Inheritability { get; set; }
3738
public List<string> NestedClassNames { get; set; } = new List<string> ();
39+
public KotlinClassType ObjectType { get; set; }
3840
public List<string> SealedSubclassFullyQualifiedNames { get; set; }
3941
public List<string> SuperTypeIds { get; set; }
4042
public List<KotlinType> SuperTypes { get; set; }
4143
public List<KotlinTypeParameter> TypeParameters { get; set; }
4244
public int [] VersionRequirements { get; set; }
45+
public KotlinClassVisibility Visibility { get; set; }
4346

4447
internal static KotlinClass FromProtobuf (Class c, JvmNameResolver resolver)
4548
{
@@ -50,7 +53,9 @@ internal static KotlinClass FromProtobuf (Class c, JvmNameResolver resolver)
5053
Flags = (KotlinClassFlags)c.Flags,
5154
FullyQualifiedName = c.FqName > 0 ? resolver.GetString (c.FqName) : null,
5255
Functions = c.Functions?.Select (f => KotlinFunction.FromProtobuf (f, resolver)).ToList (),
56+
Inheritability = (KotlinClassInheritability)((c.Flags & 0b110000) >> 4),
5357
NestedClassNames = c.NestedClassNames?.Select (n => resolver.GetString (n)).ToList (),
58+
ObjectType = (KotlinClassType) ((c.Flags & 0b111000000) >> 6),
5459
Properties = c.Properties?.Select (p => KotlinProperty.FromProtobuf (p, resolver)).ToList (),
5560
SealedSubclassFullyQualifiedNames = c.SealedSubclassFqNames?.Select (n => resolver.GetString (n)).ToList (),
5661
SuperTypeIds = c.SupertypeIds?.Select (n => resolver.GetString (n)).ToList (),
@@ -59,7 +64,8 @@ internal static KotlinClass FromProtobuf (Class c, JvmNameResolver resolver)
5964
TypeParameters = c.TypeParameters?.Select (tp => KotlinTypeParameter.FromProtobuf (tp, resolver)).ToList (),
6065
VersionRequirements = c.VersionRequirements,
6166
TypeTable = KotlinTypeTable.FromProtobuf (c.TypeTable, resolver),
62-
VersionRequirementTable = KotlinVersionRequirementTable.FromProtobuf (c.VersionRequirementTable, resolver)
67+
VersionRequirementTable = KotlinVersionRequirementTable.FromProtobuf (c.VersionRequirementTable, resolver),
68+
Visibility = (KotlinClassVisibility)((c.Flags & 0b1110) >> 1)
6369
};
6470
}
6571
}
@@ -301,6 +307,8 @@ internal static KotlinProperty FromProtobuf (Property p, JvmNameResolver resolve
301307
VersionRequirements = p.VersionRequirements
302308
};
303309
}
310+
311+
public override string ToString () => Name;
304312
}
305313

306314
public class KotlinType
@@ -577,33 +585,42 @@ public enum KotlinClassFlags
577585
{
578586
HasAnnotations = 0b00_00_000_1,
579587

580-
Internal = 0b00_00_000_0,
581-
Private = 0b00_00_001_0,
582-
Protected = 0b00_00_010_0,
583-
Public = 0b00_00_011_0,
584-
PrivateToThis = 0b00_00_100_0,
585-
Local = 0b00_00_101_0,
586-
587-
Final = 0b00_00_000_0,
588-
Open = 0b00_01_000_0,
589-
Abstract = 0b00_10_000_0,
590-
Sealed = 0b00_11_000_0,
591-
592-
Class = 0b000_00_000_0,
593-
Interface = 0b001_00_000_0,
594-
EnumClass = 0b010_00_000_0,
595-
EnumEntry = 0b011_00_000_0,
596-
AnnotationClass = 0b100_00_000_0,
597-
Object = 0b101_00_000_0,
598-
CompanionObject = 0b111_00_000_0,
599-
600588
IsInner = 0b_00001_000_00_000_0,
601589
IsData = 0b_00010_000_00_000_0,
602590
IsExternalClass = 0b_00100_000_00_000_0,
603591
IsExpectClass = 0b_01000_000_00_000_0,
604592
IsInlineClass = 0b_10000_000_00_000_0
605593
}
606594

595+
public enum KotlinClassVisibility
596+
{
597+
Internal = 0,
598+
Private = 1,
599+
Protected = 2,
600+
Public = 3,
601+
PrivateToThis = 4,
602+
Local = 5
603+
}
604+
605+
public enum KotlinClassType
606+
{
607+
Class = 0,
608+
Interface = 1,
609+
EnumClass = 2,
610+
EnumEntry = 3,
611+
AnnotationClass = 4,
612+
Object = 5,
613+
CompanionObject = 6
614+
}
615+
616+
public enum KotlinClassInheritability
617+
{
618+
Final = 0,
619+
Open = 1,
620+
Abstract = 2,
621+
Sealed = 3
622+
}
623+
607624
[Flags]
608625
public enum KotlinConstructorFlags
609626
{

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public static void Fixup (IList<ClassFile> classes)
6060
static void FixupClassVisibility (ClassFile klass, KotlinClass metadata)
6161
{
6262
// Hide class if it isn't Public/Protected
63-
if (klass.AccessFlags.IsPubliclyVisible () && !metadata.Flags.IsPubliclyVisible ()) {
63+
if (klass.AccessFlags.IsPubliclyVisible () && !metadata.Visibility.IsPubliclyVisible ()) {
6464
Log.Debug ($"Kotlin: Hiding internal class {klass.ThisClass.Name.Value}");
6565
klass.AccessFlags = ClassAccessFlags.Private;
6666
return;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ static Version ParseVersion (Annotation annotation, string key)
114114

115115
static string GetValue (Annotation annotation, string key)
116116
{
117-
return (annotation.Values.FirstOrDefault (v => v.Key == key).Value as AnnotationElementConstant)?.Value;
117+
return annotation.Values.FirstOrDefault (v => v.Key == key).Value?.ToString ();
118118
}
119119

120120
static string[] GetValues (Annotation annotation, string key)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public static string GetMethodNameWithoutSuffix (this MethodInfo method)
7474

7575
public static bool IsPubliclyVisible (this ClassAccessFlags flags) => flags.HasFlag (ClassAccessFlags.Public) || flags.HasFlag (ClassAccessFlags.Protected);
7676

77-
public static bool IsPubliclyVisible (this KotlinClassFlags flags) => flags.HasFlag (KotlinClassFlags.Public) || flags.HasFlag (KotlinClassFlags.Protected);
77+
public static bool IsPubliclyVisible (this KotlinClassVisibility flags) => flags == KotlinClassVisibility.Public || flags == KotlinClassVisibility.Protected;
7878

7979
public static bool IsPubliclyVisible (this KotlinFunctionFlags flags) => flags.HasFlag (KotlinFunctionFlags.Public) || flags.HasFlag (KotlinFunctionFlags.Protected);
8080

src/Xamarin.Android.Tools.Bytecode/Tests/KotlinMetadataTests.cs

Lines changed: 179 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,49 +11,197 @@ public class KotlinMetadataTests : ClassFileFixture
1111
[Test]
1212
public void PublicKotlinClassFile ()
1313
{
14-
var meta = GetMetadataForClassFile ("PublicClass.class");
14+
var klass_meta = GetClassMetadata ("PublicClass.class");
1515

16-
Assert.AreEqual (KotlinMetadataKind.Class, meta.Kind);
16+
Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility);
17+
Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability);
18+
}
1719

18-
var klass_meta = meta.AsClassMetadata ();
20+
[Test]
21+
public void PrivateKotlinClassFile ()
22+
{
23+
var klass_meta = GetClassMetadata ("PrivateClass.class");
1924

20-
Assert.True (klass_meta.Flags.HasFlag (KotlinClassFlags.Public));
25+
Assert.AreEqual (KotlinClassVisibility.Private, klass_meta.Visibility);
26+
Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability);
2127
}
2228

2329
[Test]
24-
public void PrivateKotlinClassFile ()
30+
public void InternalKotlinClassFile ()
2531
{
26-
var meta = GetMetadataForClassFile ("PrivateClass.class");
32+
var klass_meta = GetClassMetadata ("InternalClass.class");
2733

28-
Assert.AreEqual (KotlinMetadataKind.Class, meta.Kind);
34+
Assert.AreEqual (KotlinClassVisibility.Internal, klass_meta.Visibility);
35+
Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability);
36+
}
2937

30-
var klass_meta = meta.AsClassMetadata ();
38+
[Test]
39+
public void ProtectedKotlinClassFile ()
40+
{
41+
var klass_meta = GetClassMetadata ("PublicClass$ProtectedClass.class");
3142

32-
Assert.True (klass_meta.Flags.HasFlag (KotlinClassFlags.Private));
43+
Assert.AreEqual (KotlinClassVisibility.Protected, klass_meta.Visibility);
44+
Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability);
3345
}
3446

3547
[Test]
36-
public void InternalKotlinClassFile ()
48+
public void SealedClassFile ()
3749
{
38-
var meta = GetMetadataForClassFile ("InternalClass.class");
50+
var klass_meta = GetClassMetadata ("SealedClass.class");
3951

40-
Assert.AreEqual (KotlinMetadataKind.Class, meta.Kind);
52+
Assert.AreEqual (KotlinClassInheritability.Sealed, klass_meta.Inheritability);
53+
}
4154

42-
var klass_meta = meta.AsClassMetadata ();
55+
[Test]
56+
public void Interface ()
57+
{
58+
var klass_meta = GetClassMetadata ("MyInterface.class");
4359

44-
Assert.True (klass_meta.Flags.HasFlag (KotlinClassFlags.Internal));
60+
Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility);
61+
Assert.AreEqual (KotlinClassInheritability.Abstract, klass_meta.Inheritability);
62+
Assert.AreEqual (KotlinClassType.Interface, klass_meta.ObjectType);
63+
64+
Assert.AreEqual (2, klass_meta.Functions.Count);
65+
Assert.AreEqual (2, klass_meta.Properties.Count);
4566
}
4667

4768
[Test]
48-
public void ProtectedKotlinClassFile ()
69+
public void InterfaceDefaultImpls ()
4970
{
50-
var meta = GetMetadataForClassFile ("PublicClass$ProtectedClass.class");
71+
var meta = GetMetadataForClassFile ("MyInterface$DefaultImpls.class");
5172

52-
Assert.AreEqual (KotlinMetadataKind.Class, meta.Kind);
73+
Assert.AreEqual (KotlinMetadataKind.SyntheticClass, meta.Kind);
74+
75+
// TODO: We don't support SyntheticClass yet
76+
}
5377

54-
var klass_meta = meta.AsClassMetadata ();
78+
[Test]
79+
public void InterfaceInheritingInterface ()
80+
{
81+
var klass_meta = GetClassMetadata ("MyInterface2.class");
82+
83+
Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility);
84+
Assert.AreEqual (KotlinClassInheritability.Abstract, klass_meta.Inheritability);
85+
Assert.AreEqual (KotlinClassType.Interface, klass_meta.ObjectType);
86+
87+
Assert.AreEqual (0, klass_meta.Functions.Count);
88+
Assert.AreEqual (2, klass_meta.Properties.Count);
89+
Assert.AreEqual ("MyInterface;", klass_meta.SuperTypes [0].ClassName);
90+
}
91+
92+
[Test]
93+
public void ClassInheritingInterface ()
94+
{
95+
var klass_meta = GetClassMetadata ("MyInterfaceChild.class");
96+
97+
Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility);
98+
Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability);
99+
100+
Assert.AreEqual (1, klass_meta.Functions.Count);
101+
Assert.AreEqual (1, klass_meta.Properties.Count);
102+
Assert.AreEqual ("MyInterface;", klass_meta.SuperTypes [0].ClassName);
103+
}
55104

56-
Assert.True (klass_meta.Flags.HasFlag (KotlinClassFlags.Protected));
105+
[Test]
106+
public void DataClass ()
107+
{
108+
var klass_meta = GetClassMetadata ("DataClass.class");
109+
110+
Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility);
111+
Assert.True (klass_meta.Flags.HasFlag (KotlinClassFlags.IsData));
112+
Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability);
113+
114+
Assert.AreEqual (1, klass_meta.Constructors.Count);
115+
Assert.AreEqual (6, klass_meta.Functions.Count);
116+
Assert.AreEqual (3, klass_meta.Properties.Count);
117+
}
118+
119+
[Test]
120+
public void EnumClassFile ()
121+
{
122+
var klass_meta = GetClassMetadata ("EnumClass.class");
123+
124+
Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility);
125+
Assert.AreEqual (KotlinClassType.EnumClass, klass_meta.ObjectType);
126+
Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability);
127+
128+
Assert.AreEqual (1, klass_meta.Constructors.Count);
129+
Assert.AreEqual (4, klass_meta.EnumEntries.Count);
130+
}
131+
132+
[Test]
133+
public void EnumClassWithInterfaces ()
134+
{
135+
var klass_meta = GetClassMetadata ("EnumClassWithInterfaces.class");
136+
137+
Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility);
138+
Assert.AreEqual (KotlinClassType.EnumClass, klass_meta.ObjectType);
139+
Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability);
140+
141+
Assert.AreEqual (1, klass_meta.Constructors.Count);
142+
Assert.AreEqual (1, klass_meta.Functions.Count);
143+
Assert.AreEqual (2, klass_meta.EnumEntries.Count);
144+
145+
Assert.AreEqual ("PLUS", klass_meta.EnumEntries [0]);
146+
Assert.AreEqual ("TIMES", klass_meta.EnumEntries [1]);
147+
148+
Assert.AreEqual (2, klass_meta.SuperTypes.Count);
149+
150+
Assert.AreEqual ("kotlin/Enum", klass_meta.SuperTypes [0].ClassName);
151+
Assert.AreEqual ("EnumClassWithInterfacesInterface;", klass_meta.SuperTypes [1].ClassName);
152+
}
153+
154+
[Test]
155+
public void EnumClassWithFunction ()
156+
{
157+
var klass_meta = GetClassMetadata ("EnumClassWithInterfaces$PLUS.class");
158+
159+
Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility);
160+
Assert.AreEqual (KotlinClassType.EnumEntry, klass_meta.ObjectType);
161+
Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability);
162+
163+
Assert.AreEqual (1, klass_meta.Functions.Count);
164+
Assert.AreEqual (1, klass_meta.SuperTypes.Count);
165+
166+
Assert.AreEqual ("EnumClassWithInterfaces;", klass_meta.SuperTypes [0].ClassName);
167+
}
168+
169+
[Test]
170+
public void InlineClass ()
171+
{
172+
var klass_meta = GetClassMetadata ("InlineClass.class");
173+
174+
Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability);
175+
Assert.True (klass_meta.Flags.HasFlag (KotlinClassFlags.IsInlineClass));
176+
}
177+
178+
[Test]
179+
public void Object ()
180+
{
181+
var klass_meta = GetClassMetadata ("Object.class");
182+
183+
Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability);
184+
185+
// One would expect this to be "Object" but it doesn't seem to be
186+
Assert.AreEqual (KotlinClassType.Class, klass_meta.ObjectType);
187+
}
188+
189+
[Test]
190+
public void CompanionObject ()
191+
{
192+
var klass_meta = GetClassMetadata ("CompanionObject$Companion.class");
193+
194+
Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability);
195+
Assert.AreEqual (KotlinClassType.CompanionObject, klass_meta.ObjectType);
196+
}
197+
198+
[Test]
199+
public void KotlinExtensionMethods ()
200+
{
201+
var klass_meta = GetClassMetadata ("ExtensionMethods.class");
202+
203+
Assert.AreEqual (KotlinClassInheritability.Final, klass_meta.Inheritability);
204+
Assert.AreEqual (KotlinClassVisibility.Public, klass_meta.Visibility);
57205
}
58206

59207
private KotlinMetadata GetMetadataForClassFile (string file)
@@ -68,6 +216,18 @@ private KotlinMetadata GetMetadataForClassFile (string file)
68216

69217
return meta;
70218
}
219+
220+
private KotlinClass GetClassMetadata (string file)
221+
{
222+
var meta = GetMetadataForClassFile (file);
223+
224+
Assert.AreEqual (KotlinMetadataKind.Class, meta.Kind);
225+
226+
Assert.AreEqual ("1.0.3", meta.ByteCodeVersion.ToString ());
227+
Assert.AreEqual ("1.1.15", meta.MetadataVersion.ToString ());
228+
229+
return meta.AsClassMetadata ();
230+
}
71231
}
72232
}
73233

752 Bytes
Binary file not shown.
705 Bytes
Binary file not shown.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class CompanionObject {
2+
companion object { }
3+
}
2.73 KB
Binary file not shown.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
data class DataClass(val name: String = "", val age: Int = 0) {
2+
var weight: Int = 0
3+
}

0 commit comments

Comments
 (0)