diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/classSimpleName.kt b/compiler/testData/codegen/boxWithStdlib/reflection/classes/classSimpleName.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/classSimpleName.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/classes/classSimpleName.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/localClassSimpleName.kt b/compiler/testData/codegen/boxWithStdlib/reflection/classes/localClassSimpleName.kt similarity index 100% rename from compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/localClassSimpleName.kt rename to compiler/testData/codegen/boxWithStdlib/reflection/classes/localClassSimpleName.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/classes/qualifiedName.kt b/compiler/testData/codegen/boxWithStdlib/reflection/classes/qualifiedName.kt new file mode 100644 index 00000000000..66646bf5ce0 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/classes/qualifiedName.kt @@ -0,0 +1,37 @@ +import kotlin.test.assertEquals +import kotlin.reflect.jvm.kotlin + +class Klass { + class Nested + companion object +} + +fun box(): String { + assertEquals("Klass", Klass::class.qualifiedName) + assertEquals("Klass.Nested", Klass.Nested::class.qualifiedName) + assertEquals("Klass.Companion", Klass.Companion::class.qualifiedName) + + assertEquals("kotlin.Any", Any::class.qualifiedName) + assertEquals("kotlin.Int", Int::class.qualifiedName) + assertEquals("kotlin.Int.Companion", Int.Companion::class.qualifiedName) + assertEquals("kotlin.IntArray", IntArray::class.qualifiedName) + assertEquals("kotlin.List", List::class.qualifiedName) + assertEquals("kotlin.String", String::class.qualifiedName) + assertEquals("kotlin.String", java.lang.String::class.qualifiedName) + + assertEquals("kotlin.Array", Array::class.qualifiedName) + assertEquals("kotlin.Array", Array::class.qualifiedName) + assertEquals("kotlin.Array", Array>::class.qualifiedName) + + assertEquals("java.util.Date", java.util.Date::class.qualifiedName) + assertEquals("kotlin.jvm.internal.KotlinSyntheticClass.Kind", kotlin.jvm.internal.KotlinSyntheticClass.Kind::class.qualifiedName) + assertEquals("java.lang.Void", java.lang.Void::class.qualifiedName) + + class Local + assertEquals(null, Local::class.qualifiedName) + + val o = object {} + assertEquals(null, o.javaClass.kotlin.qualifiedName) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 0bd0f75a57e..2da111d3b3f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -2775,24 +2775,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } - @TestMetadata("classSimpleName.kt") - public void testClassSimpleName() throws Exception { - String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/classSimpleName.kt"); - doTestWithStdlib(fileName); - } - @TestMetadata("genericClass.kt") public void testGenericClass() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/genericClass.kt"); doTestWithStdlib(fileName); } - @TestMetadata("localClassSimpleName.kt") - public void testLocalClassSimpleName() throws Exception { - String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/localClassSimpleName.kt"); - doTestWithStdlib(fileName); - } - @TestMetadata("simpleClassLiteral.kt") public void testSimpleClassLiteral() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/simpleClassLiteral.kt"); @@ -2800,6 +2788,33 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classes") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Classes extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInClasses() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/classes"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("classSimpleName.kt") + public void testClassSimpleName() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classes/classSimpleName.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("localClassSimpleName.kt") + public void testLocalClassSimpleName() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classes/localClassSimpleName.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("qualifiedName.kt") + public void testQualifiedName() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classes/qualifiedName.kt"); + doTestWithStdlib(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/builtins/src/kotlin/reflect/KClass.kt b/core/builtins/src/kotlin/reflect/KClass.kt index 3a89c246fdb..12349130007 100644 --- a/core/builtins/src/kotlin/reflect/KClass.kt +++ b/core/builtins/src/kotlin/reflect/KClass.kt @@ -27,10 +27,17 @@ package kotlin.reflect public interface KClass { /** * The simple name of the class as it was declared in the source code, - * or `null` if the class has no name (e.g. anonymous object literals). + * or `null` if the class has no name (if, for example, it is an anonymous object literal). */ public val simpleName: String? + /** + * The fully qualified name of the class which consists of names of the declaring package, + * all outer classes of this class and the class itself separated by dots, + * or `null` if the class is local or it is an anonymous object literal. + */ + public val qualifiedName: String? + /** * Returns non-extension properties declared in this class and all of its superclasses. */ diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index f00a88bd7ed..d2a12db9b16 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -42,9 +42,10 @@ class KClassImpl(override val jClass: Class) : KCallableContainerImpl(), K override val scope: JetScope get() = descriptor.getDefaultType().getMemberScope() override val simpleName: String? get() { + if (jClass.isAnonymousClass()) return null + val classId = classId return when { - jClass.isAnonymousClass() -> null classId.isLocal() -> calculateLocalClassName(jClass) else -> classId.getShortClassName().asString() } @@ -61,6 +62,16 @@ class KClassImpl(override val jClass: Class) : KCallableContainerImpl(), K return name.substringAfter('$') } + override val qualifiedName: String? get() { + if (jClass.isAnonymousClass()) return null + + val classId = classId + return when { + classId.isLocal() -> null + else -> classId.asSingleFqName().asString() + } + } + override val properties: Collection> get() = getProperties(declared = false)