Reflection: add test on introspection of local classes

kotlin-reflect works correctly already for Kotlin-generated local
classes and anonymous objects, but not for Java ones. This is fixed in a
subsequent commit.

 #KT-41373 In Progress
This commit is contained in:
Alexander Udalov
2023-03-28 23:44:42 +02:00
committed by Space Team
parent 9fcdc10019
commit 1e031d9fb8
16 changed files with 345 additions and 0 deletions
@@ -45305,6 +45305,22 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("localClassesAndAnonymousObjects.kt")
public void testLocalClassesAndAnonymousObjects() throws Exception {
runTest("compiler/testData/codegen/box/reflection/localClasses/localClassesAndAnonymousObjects.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@@ -45305,6 +45305,22 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("localClassesAndAnonymousObjects.kt")
public void testLocalClassesAndAnonymousObjects() throws Exception {
runTest("compiler/testData/codegen/box/reflection/localClasses/localClassesAndAnonymousObjects.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@@ -0,0 +1,144 @@
// TARGET_BACKEND: JVM
// WITH_REFLECT
// FILE: anonymousObjects.kt
package test
import kotlin.reflect.*
import kotlin.reflect.jvm.isAccessible
import kotlin.test.*
interface I
fun check(x: KClass<*>, value: Any) {
assertEquals(null, x.qualifiedName)
assertEquals(
setOf(
"foo", "bar",
"equals", "hashCode", "toString"
),
x.members.mapTo(hashSetOf()) { it.name }
)
assertEquals(emptyList(), x.annotations)
assertEquals(emptyList(), x.nestedClasses)
assertEquals(null, x.objectInstance)
assertEquals(emptyList(), x.sealedSubclasses)
assertEquals(listOf(typeOf<I>(), typeOf<Any>()), x.supertypes)
// Local class visibility cannot be represented in Kotlin, so `KClass.visibility` is null.
assertEquals(null, x.visibility)
// It's not really important whether the class is considered final or open, but it shouldn't be both (or neither).
assertTrue(x.isFinal xor x.isOpen)
assertFalse(x.isAbstract)
assertFalse(x.isSealed)
assertFalse(x.isData)
assertFalse(x.isInner)
assertFalse(x.isCompanion)
assertFalse(x.isFun)
assertFalse(x.isValue)
assertFalse(x.isInstance(42))
assertTrue(x.isInstance(value))
val equals = x.members.single { it.name == "equals" } as KFunction<Boolean>
assertTrue(equals.call(value, value))
val foo = x.members.single { it.name == "foo" }.apply { isAccessible = true } as KFunction<String>
assertEquals("OK", foo.call(value))
val bar = x.members.single { it.name == "bar" }.apply { isAccessible = true } as KProperty1<Any, Int>
assertEquals(42, bar.get(value))
}
fun checkKotlinAnonymousObject() {
val anonymousObject = object : I {
val bar: Int = 42
fun foo(): String = "OK"
}
val klass = anonymousObject::class
// isAnonymousClass/simpleName behavior is different for Kotlin anonymous classes in JDK 1.8 and 9+, see KT-23072.
if (klass.java.isAnonymousClass) {
assertEquals(null, klass.simpleName)
} else {
assertEquals("anonymousObject\$1", klass.simpleName)
}
assertEquals(emptyList(), klass.constructors)
check(klass, anonymousObject)
}
fun checkKotlinLocalClass() {
class Local : I {
val bar: Int = 42
fun foo(): String = "OK"
}
val instance = Local()
val klass = instance::class
// simpleName behavior is different for Kotlin anonymous classes in JDK 1.8 and 9+, see KT-23072.
assertTrue(klass.simpleName!!.endsWith("Local"))
assertEquals(listOf("fun `<init>`(): test.`AnonymousObjectsKt\$checkKotlinLocalClass\$Local`"), klass.constructors.map { it.toString() })
check(klass, instance)
}
fun checkJavaAnonymousObject() {
val anonymousObject = JavaClass.anonymousObject()
val klass = anonymousObject::class
assertEquals(null, klass.simpleName)
assertEquals(listOf("fun `<init>`(): `JavaClass$1`"), klass.constructors.map { it.toString() })
check(klass, anonymousObject)
}
fun checkJavaLocalClass() {
val instance = JavaClass.localClassInstance()
val klass = instance::class
assertEquals("Local", klass.simpleName)
assertEquals(listOf("fun `<init>`(): Local"), klass.constructors.map { it.toString() })
check(klass, instance)
}
fun box(): String {
checkKotlinAnonymousObject()
checkKotlinLocalClass()
// TODO: fails with KotlinReflectionInternalError: Unresolved class: class JavaClass$1 (kind = null)
// checkJavaAnonymousObject()
// checkJavaLocalClass()
return "OK"
}
// FILE: JavaClass.java
public class JavaClass {
public static Object anonymousObject() {
return new test.I() {
int bar = 42;
String foo() { return "OK"; }
};
}
public static Object localClassInstance() {
class Local implements test.I {
int bar = 42;
String foo() { return "OK"; }
}
return new Local();
}
}
@@ -42647,6 +42647,22 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@Test
@TestMetadata("localClassesAndAnonymousObjects.kt")
public void testLocalClassesAndAnonymousObjects() throws Exception {
runTest("compiler/testData/codegen/box/reflection/localClasses/localClassesAndAnonymousObjects.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@@ -45305,6 +45305,22 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("localClassesAndAnonymousObjects.kt")
public void testLocalClassesAndAnonymousObjects() throws Exception {
runTest("compiler/testData/codegen/box/reflection/localClasses/localClassesAndAnonymousObjects.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@@ -45305,6 +45305,22 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("localClassesAndAnonymousObjects.kt")
public void testLocalClassesAndAnonymousObjects() throws Exception {
runTest("compiler/testData/codegen/box/reflection/localClasses/localClassesAndAnonymousObjects.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@@ -36008,6 +36008,24 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
}
}
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class LocalClasses extends AbstractLightAnalysisModeTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
}
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("localClassesAndAnonymousObjects.kt")
public void testLocalClassesAndAnonymousObjects() throws Exception {
runTest("compiler/testData/codegen/box/reflection/localClasses/localClassesAndAnonymousObjects.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -32537,6 +32537,16 @@ public class FirJsCodegenBoxTestGenerated extends AbstractFirJsCodegenBoxTest {
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@@ -32537,6 +32537,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@@ -32537,6 +32537,16 @@ public class IrJsES6CodegenBoxTestGenerated extends AbstractIrJsES6CodegenBoxTes
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@@ -35884,6 +35884,19 @@ public class FirNativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTe
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
@Tag("frontend-fir")
@FirPipeline()
@UseExtTestCaseGroupProvider()
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@@ -36760,6 +36760,21 @@ public class FirNativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenB
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
@Tag("frontend-fir")
@FirPipeline()
@UseExtTestCaseGroupProvider()
@UsePartialLinkage(mode = Mode.DISABLED)
@Tag("no-partial-linkage-may-be-skipped")
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@@ -35447,6 +35447,18 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
@UseExtTestCaseGroupProvider()
@DisabledTestsIfProperty(sourceLocations = { "compiler/testData/codegen/box/coroutines/featureIntersection/defaultExpect.kt", "compiler/testData/codegen/box/multiplatform/defaultArguments/*.kt", "compiler/testData/codegen/box/multiplatform/migratedOldTests/*.kt", "compiler/testData/codegen/boxInline/multiplatform/defaultArguments/receiversAndParametersInLambda.kt" }, property = ClassLevelProperty.TEST_MODE, propertyValue = "ONE_STAGE_MULTI_MODULE")
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@@ -35885,6 +35885,19 @@ public class NativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenBoxT
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
@UseExtTestCaseGroupProvider()
@UsePartialLinkage(mode = Mode.DISABLED)
@Tag("no-partial-linkage-may-be-skipped")
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@@ -32345,6 +32345,16 @@ public class FirWasmCodegenBoxTestGenerated extends AbstractFirWasmCodegenBoxTes
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")
@@ -32345,6 +32345,16 @@ public class K1WasmCodegenBoxTestGenerated extends AbstractK1WasmCodegenBoxTest
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/localClasses")
@TestDataPath("$PROJECT_ROOT")
public class LocalClasses {
@Test
public void testAllFilesPresentInLocalClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/localClasses"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/mapping")
@TestDataPath("$PROJECT_ROOT")