From 4266e50be8c0b2c32f193020d44b4346df3e0b7a Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 5 Jan 2018 15:23:49 +0100 Subject: [PATCH] Use manual type mapping in reflection for members from built-ins There are cases when members deserialized from JVM classes have no JVM signature in the proto. For example, if a member is inherited from a built-in class (such as Map.getOrDefault in some Map implementations), or if a member is synthesized in the compiler front-end and back-end separately (such as enum values/valueOf). In these cases, we'll use the naive type mapping to try to recover the signature. #KT-16616 Fixed #KT-17542 Fixed --- .../reflection/builtins/collections.kt} | 12 ++-- .../reflection/builtins/enumNameOrdinal.kt | 13 ++++ .../box/reflection/builtins/stringLength.kt | 10 ++++ .../reflection/functions/enumValuesValueOf.kt | 15 +++++ .../builtinFunctionsToString.kt | 25 ++++++++ .../getMembersOfStandardJavaClasses.kt | 30 ---------- .../ir/IrBlackBoxCodegenTestGenerated.java | 56 +++++++++++------ .../codegen/BlackBoxCodegenTestGenerated.java | 56 +++++++++++------ .../LightAnalysisModeTestGenerated.java | 56 +++++++++++------ .../load/kotlin/methodSignatureMapping.kt | 35 +++++------ .../kotlin/resolve/DescriptorFactory.java | 13 ++++ .../reflect/jvm/internal/KPropertyImpl.kt | 15 +++++ .../reflect/jvm/internal/RuntimeTypeMapper.kt | 60 +++++++++++++------ .../IrJsCodegenBoxTestGenerated.java | 56 +++++++++++------ .../semantics/JsCodegenBoxTestGenerated.java | 56 +++++++++++------ 15 files changed, 347 insertions(+), 161 deletions(-) rename compiler/testData/codegen/{java6/box/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt => box/reflection/builtins/collections.kt} (68%) create mode 100644 compiler/testData/codegen/box/reflection/builtins/enumNameOrdinal.kt create mode 100644 compiler/testData/codegen/box/reflection/builtins/stringLength.kt create mode 100644 compiler/testData/codegen/box/reflection/functions/enumValuesValueOf.kt create mode 100644 compiler/testData/codegen/box/reflection/methodsFromAny/builtinFunctionsToString.kt delete mode 100644 compiler/testData/codegen/box/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt diff --git a/compiler/testData/codegen/java6/box/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt b/compiler/testData/codegen/box/reflection/builtins/collections.kt similarity index 68% rename from compiler/testData/codegen/java6/box/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt rename to compiler/testData/codegen/box/reflection/builtins/collections.kt index e10c57f7343..9310bebd6ed 100644 --- a/compiler/testData/codegen/java6/box/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt +++ b/compiler/testData/codegen/box/reflection/builtins/collections.kt @@ -1,12 +1,11 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS, NATIVE - +// IGNORE_BACKEND: JVM_IR, JS_IR, JS, NATIVE // WITH_REFLECT // FULL_JDK -// See KT-11258 Incorrect resolution sequence for Java field -//SHOULD BE deleted after KT-16616 fix +// See KT-11258, KT-16616 + import java.util.* +import kotlin.test.assertEquals fun box(): String { listOf( @@ -22,5 +21,8 @@ fun box(): String { ).map { it.members.map(Any::toString) } + + assertEquals(1, Collection::size.getter(listOf(1))) + return "OK" } diff --git a/compiler/testData/codegen/box/reflection/builtins/enumNameOrdinal.kt b/compiler/testData/codegen/box/reflection/builtins/enumNameOrdinal.kt new file mode 100644 index 00000000000..4e97f9c22df --- /dev/null +++ b/compiler/testData/codegen/box/reflection/builtins/enumNameOrdinal.kt @@ -0,0 +1,13 @@ +// IGNORE_BACKEND: JS_IR, JS, NATIVE +// WITH_REFLECT + +import kotlin.test.assertEquals + +enum class E { X, Y, Z } + +fun box(): String { + assertEquals(11, E::class.members.size) + assertEquals("Y", E::name.call(E.Y)) + assertEquals(2, E::ordinal.call(E.Z)) + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/builtins/stringLength.kt b/compiler/testData/codegen/box/reflection/builtins/stringLength.kt new file mode 100644 index 00000000000..3644a4c104c --- /dev/null +++ b/compiler/testData/codegen/box/reflection/builtins/stringLength.kt @@ -0,0 +1,10 @@ +// IGNORE_BACKEND: JS_IR, JS, NATIVE +// WITH_REFLECT + +import kotlin.test.assertEquals + +fun box(): String { + String::class.members + assertEquals(2, String::length.call("OK")) + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/functions/enumValuesValueOf.kt b/compiler/testData/codegen/box/reflection/functions/enumValuesValueOf.kt new file mode 100644 index 00000000000..eb2b515416a --- /dev/null +++ b/compiler/testData/codegen/box/reflection/functions/enumValuesValueOf.kt @@ -0,0 +1,15 @@ +// IGNORE_BACKEND: JS_IR, JS, NATIVE +// WITH_REFLECT + +import kotlin.test.assertEquals + +enum class E { X, Y, Z } + +fun box(): String { + assertEquals("fun values(): kotlin.Array", E::values.toString()) + assertEquals(listOf(E.X, E.Y, E.Z), E::values.call().toList()) + assertEquals("fun valueOf(kotlin.String): E", E::valueOf.toString()) + assertEquals(E.Y, E::valueOf.call("Y")) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/methodsFromAny/builtinFunctionsToString.kt b/compiler/testData/codegen/box/reflection/methodsFromAny/builtinFunctionsToString.kt new file mode 100644 index 00000000000..1dbdd9577b4 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/methodsFromAny/builtinFunctionsToString.kt @@ -0,0 +1,25 @@ +// IGNORE_BACKEND: JVM_IR, JS_IR, JS, NATIVE +// FULL_JDK +// WITH_REFLECT + +import kotlin.test.assertEquals +import java.util.* + +fun assertToString(s: String, x: Any) { + assertEquals(s, x.toString()) +} + +fun box(): String { + assertToString("fun kotlin.collections.Map.getOrDefault(K, V): V", Map<*, *>::getOrDefault) + assertToString("fun java.util.HashMap.getOrDefault(K, V): V", HashMap<*, *>::getOrDefault) + + // TODO: uncomment once KT-11754 is fixed + // assertToString("", MutableList<*>::removeAt) + + assertToString("fun kotlin.collections.Collection.contains(E): kotlin.Boolean", Collection<*>::contains) + assertToString("fun kotlin.collections.Set.contains(E): kotlin.Boolean", Set<*>::contains) + + assertToString("fun kotlin.collections.Collection.isEmpty(): kotlin.Boolean", Collection<*>::isEmpty) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt b/compiler/testData/codegen/box/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt deleted file mode 100644 index 1cde78c745e..00000000000 --- a/compiler/testData/codegen/box/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt +++ /dev/null @@ -1,30 +0,0 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND: JS_IR -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS, NATIVE - -// WITH_REFLECT -// FULL_JDK -// See KT-11258 Incorrect resolution sequence for Java field - -// TODO: enable this test on JVM, see KT-16616 -// IGNORE_BACKEND: JVM - -import java.util.* - -fun box(): String { - listOf( - ArrayList::class, - LinkedList::class, - AbstractList::class, - HashSet::class, - TreeSet::class, - HashMap::class, - TreeMap::class, - AbstractMap::class, - AbstractMap.SimpleEntry::class - ).map { - it.members.map(Any::toString) - } - return "OK" -} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 55849084d15..521dc72e6cb 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -16408,6 +16408,34 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes } } + @TestMetadata("compiler/testData/codegen/box/reflection/builtins") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Builtins extends AbstractIrBlackBoxCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInBuiltins() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/builtins"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); + } + + @TestMetadata("collections.kt") + public void testCollections() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/collections.kt"); + } + + @TestMetadata("enumNameOrdinal.kt") + public void testEnumNameOrdinal() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/enumNameOrdinal.kt"); + } + + @TestMetadata("stringLength.kt") + public void testStringLength() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/stringLength.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/reflection/call") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -17129,6 +17157,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/functions/declaredVsInheritedFunctions.kt"); } + @TestMetadata("enumValuesValueOf.kt") + public void testEnumValuesValueOf() throws Exception { + runTest("compiler/testData/codegen/box/reflection/functions/enumValuesValueOf.kt"); + } + @TestMetadata("functionFromStdlib.kt") public void testFunctionFromStdlib() throws Exception { runTest("compiler/testData/codegen/box/reflection/functions/functionFromStdlib.kt"); @@ -17581,6 +17614,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/methodsFromAny"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); } + @TestMetadata("builtinFunctionsToString.kt") + public void testBuiltinFunctionsToString() throws Exception { + runTest("compiler/testData/codegen/box/reflection/methodsFromAny/builtinFunctionsToString.kt"); + } + @TestMetadata("callableReferencesEqualToCallablesFromAPI.kt") public void testCallableReferencesEqualToCallablesFromAPI() throws Exception { runTest("compiler/testData/codegen/box/reflection/methodsFromAny/callableReferencesEqualToCallablesFromAPI.kt"); @@ -18224,24 +18262,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes } } - @TestMetadata("compiler/testData/codegen/box/reflection/specialBuiltIns") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class SpecialBuiltIns extends AbstractIrBlackBoxCodegenTest { - private void runTest(String testDataFilePath) throws Exception { - KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); - } - - public void testAllFilesPresentInSpecialBuiltIns() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/specialBuiltIns"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); - } - - @TestMetadata("getMembersOfStandardJavaClasses.kt") - public void testGetMembersOfStandardJavaClasses() throws Exception { - runTest("compiler/testData/codegen/box/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt"); - } - } - @TestMetadata("compiler/testData/codegen/box/reflection/supertypes") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index aa0d57d033c..3cf3fd5af1e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -16408,6 +16408,34 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } + @TestMetadata("compiler/testData/codegen/box/reflection/builtins") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Builtins extends AbstractBlackBoxCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInBuiltins() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/builtins"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("collections.kt") + public void testCollections() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/collections.kt"); + } + + @TestMetadata("enumNameOrdinal.kt") + public void testEnumNameOrdinal() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/enumNameOrdinal.kt"); + } + + @TestMetadata("stringLength.kt") + public void testStringLength() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/stringLength.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/reflection/call") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -17129,6 +17157,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/functions/declaredVsInheritedFunctions.kt"); } + @TestMetadata("enumValuesValueOf.kt") + public void testEnumValuesValueOf() throws Exception { + runTest("compiler/testData/codegen/box/reflection/functions/enumValuesValueOf.kt"); + } + @TestMetadata("functionFromStdlib.kt") public void testFunctionFromStdlib() throws Exception { runTest("compiler/testData/codegen/box/reflection/functions/functionFromStdlib.kt"); @@ -17581,6 +17614,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/methodsFromAny"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("builtinFunctionsToString.kt") + public void testBuiltinFunctionsToString() throws Exception { + runTest("compiler/testData/codegen/box/reflection/methodsFromAny/builtinFunctionsToString.kt"); + } + @TestMetadata("callableReferencesEqualToCallablesFromAPI.kt") public void testCallableReferencesEqualToCallablesFromAPI() throws Exception { runTest("compiler/testData/codegen/box/reflection/methodsFromAny/callableReferencesEqualToCallablesFromAPI.kt"); @@ -18224,24 +18262,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } - @TestMetadata("compiler/testData/codegen/box/reflection/specialBuiltIns") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class SpecialBuiltIns extends AbstractBlackBoxCodegenTest { - private void runTest(String testDataFilePath) throws Exception { - KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); - } - - public void testAllFilesPresentInSpecialBuiltIns() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/specialBuiltIns"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); - } - - @TestMetadata("getMembersOfStandardJavaClasses.kt") - public void testGetMembersOfStandardJavaClasses() throws Exception { - runTest("compiler/testData/codegen/box/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt"); - } - } - @TestMetadata("compiler/testData/codegen/box/reflection/supertypes") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 28b877b5e80..7a6c587f7c4 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -16408,6 +16408,34 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes } } + @TestMetadata("compiler/testData/codegen/box/reflection/builtins") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Builtins extends AbstractLightAnalysisModeTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInBuiltins() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/builtins"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("collections.kt") + public void testCollections() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/collections.kt"); + } + + @TestMetadata("enumNameOrdinal.kt") + public void testEnumNameOrdinal() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/enumNameOrdinal.kt"); + } + + @TestMetadata("stringLength.kt") + public void testStringLength() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/stringLength.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/reflection/call") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -17129,6 +17157,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/functions/declaredVsInheritedFunctions.kt"); } + @TestMetadata("enumValuesValueOf.kt") + public void testEnumValuesValueOf() throws Exception { + runTest("compiler/testData/codegen/box/reflection/functions/enumValuesValueOf.kt"); + } + @TestMetadata("functionFromStdlib.kt") public void testFunctionFromStdlib() throws Exception { runTest("compiler/testData/codegen/box/reflection/functions/functionFromStdlib.kt"); @@ -17581,6 +17614,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/methodsFromAny"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("builtinFunctionsToString.kt") + public void testBuiltinFunctionsToString() throws Exception { + runTest("compiler/testData/codegen/box/reflection/methodsFromAny/builtinFunctionsToString.kt"); + } + @TestMetadata("callableReferencesEqualToCallablesFromAPI.kt") public void testCallableReferencesEqualToCallablesFromAPI() throws Exception { runTest("compiler/testData/codegen/box/reflection/methodsFromAny/callableReferencesEqualToCallablesFromAPI.kt"); @@ -18224,24 +18262,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes } } - @TestMetadata("compiler/testData/codegen/box/reflection/specialBuiltIns") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class SpecialBuiltIns extends AbstractLightAnalysisModeTest { - @TestMetadata("getMembersOfStandardJavaClasses.kt") - public void ignoreGetMembersOfStandardJavaClasses() throws Exception { - runTest("compiler/testData/codegen/box/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt"); - } - - private void runTest(String testDataFilePath) throws Exception { - KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); - } - - public void testAllFilesPresentInSpecialBuiltIns() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/specialBuiltIns"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); - } - } - @TestMetadata("compiler/testData/codegen/box/reflection/supertypes") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/methodSignatureMapping.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/methodSignatureMapping.kt index 94d62554a7d..86486f2e795 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/methodSignatureMapping.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/methodSignatureMapping.kt @@ -18,26 +18,27 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.kotlin.types.KotlinType -fun FunctionDescriptor.computeJvmDescriptor(withReturnType: Boolean = true) - = StringBuilder().apply { - append(if (this@computeJvmDescriptor is ConstructorDescriptor) "" else name.asString()) - append("(") +fun FunctionDescriptor.computeJvmDescriptor(withReturnType: Boolean = true, withName: Boolean = true): String = buildString { + if (withName) { + append(if (this@computeJvmDescriptor is ConstructorDescriptor) "" else name.asString()) + } - valueParameters.forEach { - appendErasedType(it.type) - } + append("(") - append(")") + for (parameter in valueParameters) { + appendErasedType(parameter.type) + } - if (withReturnType) { - if (hasVoidReturnType(this@computeJvmDescriptor)) { - append("V") - } - else { - appendErasedType(returnType!!) - } - } - }.toString() + append(")") + + if (withReturnType) { + if (hasVoidReturnType(this@computeJvmDescriptor)) { + append("V") + } else { + appendErasedType(returnType!!) + } + } +} // Boxing is only necessary for 'remove(E): Boolean' of a MutableCollection implementation // Otherwise this method might clash with 'remove(I): E' defined in the java.util.List JDK interface (mapped to kotlin 'removeAt') diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorFactory.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorFactory.java index 496d6f337ab..b919e4b10ea 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorFactory.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorFactory.java @@ -152,6 +152,19 @@ public class DescriptorFactory { Modality.FINAL, Visibilities.PUBLIC); } + public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor descriptor) { + return descriptor.getName().equals(DescriptorUtils.ENUM_VALUES) && isEnumSpecialMethod(descriptor); + } + + public static boolean isEnumValueOfMethod(@NotNull FunctionDescriptor descriptor) { + return descriptor.getName().equals(DescriptorUtils.ENUM_VALUE_OF) && isEnumSpecialMethod(descriptor); + } + + private static boolean isEnumSpecialMethod(@NotNull FunctionDescriptor descriptor) { + return descriptor.getKind() == CallableMemberDescriptor.Kind.SYNTHESIZED && + DescriptorUtils.isEnumClass(descriptor.getContainingDeclaration()); + } + @Nullable public static ReceiverParameterDescriptor createExtensionReceiverParameterForCallable( @NotNull CallableDescriptor owner, diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt index ef3a392adf0..0e6ff59950a 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt @@ -75,6 +75,7 @@ internal abstract class KPropertyImpl private constructor( } is JavaField -> jvmSignature.field is JavaMethodProperty -> null + is MappedKotlinProperty -> null } } @@ -268,5 +269,19 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool if (isBound) FunctionCaller.BoundInstanceMethod(method, property.boundReceiver) else FunctionCaller.InstanceMethod(method) } + is MappedKotlinProperty -> { + val signature = + if (isGetter) jvmSignature.getterSignature + else (jvmSignature.setterSignature + ?: throw KotlinReflectionInternalError("No setter found for property $property")) + val accessor = property.container.findMethodBySignature( + signature.methodName, signature.methodDesc, descriptor.isPublicInBytecode + ) ?: throw KotlinReflectionInternalError("No accessor found for property $property") + + assert(!Modifier.isStatic(accessor.modifiers)) { "Mapped property cannot have a static accessor: $property" } + + return if (isBound) FunctionCaller.BoundInstanceMethod(accessor, property.boundReceiver) + else FunctionCaller.InstanceMethod(accessor) + } } } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt index e037659241c..99b51da97b0 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt @@ -18,16 +18,15 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.PrimitiveType -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.descriptors.JavaClassConstructorDescriptor import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor +import org.jetbrains.kotlin.load.java.getJvmMethodNameIfSpecial import org.jetbrains.kotlin.load.java.sources.JavaSourceElement import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource +import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.NameResolver import org.jetbrains.kotlin.metadata.deserialization.TypeTable @@ -39,7 +38,9 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.NameUtils import org.jetbrains.kotlin.platform.JavaToKotlinClassMap +import org.jetbrains.kotlin.resolve.DescriptorFactory import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor @@ -150,6 +151,13 @@ internal sealed class JvmPropertySignature { override fun asString(): String = JvmAbi.getterName(field.name) + "()" + field.type.desc } + + class MappedKotlinProperty( + val getterSignature: JvmFunctionSignature.KotlinFunction, + val setterSignature: JvmFunctionSignature.KotlinFunction? + ) : JvmPropertySignature() { + override fun asString(): String = getterSignature.asString() + } } private val Method.signature: String @@ -182,10 +190,7 @@ internal object RuntimeTypeMapper { return JvmFunctionSignature.KotlinConstructor(signature) } } - // If it's a deserialized function but has no JVM signature, it must be from built-ins - throw KotlinReflectionInternalError( - "Reflection on built-in Kotlin types is not yet fully supported. No metadata found for $function" - ) + return mapJvmFunctionSignature(function) } is JavaMethodDescriptor -> { val method = ((function.source as? JavaSourceElement)?.javaElement as? ReflectJavaMethod)?.member @@ -203,25 +208,28 @@ internal object RuntimeTypeMapper { else -> throw KotlinReflectionInternalError("Incorrect resolution sequence for Java constructor $function ($element)") } } - else -> throw KotlinReflectionInternalError("Unknown origin of $function (${function.javaClass})") } + + if (DescriptorFactory.isEnumValueOfMethod(function) || DescriptorFactory.isEnumValuesMethod(function)) { + return mapJvmFunctionSignature(function) + } + + throw KotlinReflectionInternalError("Unknown origin of $function (${function.javaClass})") } fun mapPropertySignature(possiblyOverriddenProperty: PropertyDescriptor): JvmPropertySignature { val property = DescriptorUtils.unwrapFakeOverride(possiblyOverriddenProperty).original - return when (property) { + when (property) { is DeserializedPropertyDescriptor -> { val proto = property.proto val signature = proto.getExtensionOrNull(JvmProtoBuf.propertySignature) - ?: // If this property has no JVM signature, it must be from built-ins - throw KotlinReflectionInternalError( - "Reflection on built-in Kotlin types is not yet fully supported. No metadata found for $property" - ) - JvmPropertySignature.KotlinProperty(property, proto, signature, property.nameResolver, property.typeTable) + if (signature != null) { + return JvmPropertySignature.KotlinProperty(property, proto, signature, property.nameResolver, property.typeTable) + } } is JavaPropertyDescriptor -> { val element = (property.source as? JavaSourceElement)?.javaElement - when (element) { + return when (element) { is ReflectJavaField -> JvmPropertySignature.JavaField(element.member) is ReflectJavaMethod -> JvmPropertySignature.JavaMethodProperty( element.member, @@ -230,12 +238,26 @@ internal object RuntimeTypeMapper { else -> throw KotlinReflectionInternalError("Incorrect resolution sequence for Java field $property (source = $element)") } } - else -> { - throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})") - } } + + return JvmPropertySignature.MappedKotlinProperty( + property.getter!!.let(this::mapJvmFunctionSignature), + property.setter?.let(this::mapJvmFunctionSignature) + ) } + private fun mapJvmFunctionSignature(descriptor: FunctionDescriptor): JvmFunctionSignature.KotlinFunction = + JvmFunctionSignature.KotlinFunction( + JvmMemberSignature.Method(mapName(descriptor), descriptor.computeJvmDescriptor(withName = false)) + ) + + private fun mapName(descriptor: CallableMemberDescriptor): String = + getJvmMethodNameIfSpecial(descriptor) ?: when (descriptor) { + is PropertyGetterDescriptor -> JvmAbi.getterName(descriptor.propertyIfAccessor.name.asString()) + is PropertySetterDescriptor -> JvmAbi.setterName(descriptor.propertyIfAccessor.name.asString()) + else -> descriptor.name.asString() + } + private fun mapIntrinsicFunctionSignature(function: FunctionDescriptor): JvmFunctionSignature? { val parameters = function.valueParameters diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java index d86e9dace9f..629ab3f7995 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java @@ -14723,6 +14723,34 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { } } + @TestMetadata("compiler/testData/codegen/box/reflection/builtins") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Builtins extends AbstractIrJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath); + } + + public void testAllFilesPresentInBuiltins() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/builtins"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true); + } + + @TestMetadata("collections.kt") + public void testCollections() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/collections.kt"); + } + + @TestMetadata("enumNameOrdinal.kt") + public void testEnumNameOrdinal() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/enumNameOrdinal.kt"); + } + + @TestMetadata("stringLength.kt") + public void testStringLength() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/stringLength.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/reflection/call") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -15444,6 +15472,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/functions/declaredVsInheritedFunctions.kt"); } + @TestMetadata("enumValuesValueOf.kt") + public void testEnumValuesValueOf() throws Exception { + runTest("compiler/testData/codegen/box/reflection/functions/enumValuesValueOf.kt"); + } + @TestMetadata("functionFromStdlib.kt") public void testFunctionFromStdlib() throws Exception { runTest("compiler/testData/codegen/box/reflection/functions/functionFromStdlib.kt"); @@ -15886,6 +15919,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/methodsFromAny"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true); } + @TestMetadata("builtinFunctionsToString.kt") + public void testBuiltinFunctionsToString() throws Exception { + runTest("compiler/testData/codegen/box/reflection/methodsFromAny/builtinFunctionsToString.kt"); + } + @TestMetadata("callableReferencesEqualToCallablesFromAPI.kt") public void testCallableReferencesEqualToCallablesFromAPI() throws Exception { runTest("compiler/testData/codegen/box/reflection/methodsFromAny/callableReferencesEqualToCallablesFromAPI.kt"); @@ -16499,24 +16537,6 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { } } - @TestMetadata("compiler/testData/codegen/box/reflection/specialBuiltIns") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class SpecialBuiltIns extends AbstractIrJsCodegenBoxTest { - private void runTest(String testDataFilePath) throws Exception { - KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath); - } - - public void testAllFilesPresentInSpecialBuiltIns() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/specialBuiltIns"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true); - } - - @TestMetadata("getMembersOfStandardJavaClasses.kt") - public void testGetMembersOfStandardJavaClasses() throws Exception { - runTest("compiler/testData/codegen/box/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt"); - } - } - @TestMetadata("compiler/testData/codegen/box/reflection/supertypes") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index a644c22cd69..353e2734bf8 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -14723,6 +14723,34 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { } } + @TestMetadata("compiler/testData/codegen/box/reflection/builtins") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Builtins extends AbstractJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath); + } + + public void testAllFilesPresentInBuiltins() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/builtins"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); + } + + @TestMetadata("collections.kt") + public void testCollections() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/collections.kt"); + } + + @TestMetadata("enumNameOrdinal.kt") + public void testEnumNameOrdinal() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/enumNameOrdinal.kt"); + } + + @TestMetadata("stringLength.kt") + public void testStringLength() throws Exception { + runTest("compiler/testData/codegen/box/reflection/builtins/stringLength.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/reflection/call") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -15444,6 +15472,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/functions/declaredVsInheritedFunctions.kt"); } + @TestMetadata("enumValuesValueOf.kt") + public void testEnumValuesValueOf() throws Exception { + runTest("compiler/testData/codegen/box/reflection/functions/enumValuesValueOf.kt"); + } + @TestMetadata("functionFromStdlib.kt") public void testFunctionFromStdlib() throws Exception { runTest("compiler/testData/codegen/box/reflection/functions/functionFromStdlib.kt"); @@ -15886,6 +15919,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/methodsFromAny"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); } + @TestMetadata("builtinFunctionsToString.kt") + public void testBuiltinFunctionsToString() throws Exception { + runTest("compiler/testData/codegen/box/reflection/methodsFromAny/builtinFunctionsToString.kt"); + } + @TestMetadata("callableReferencesEqualToCallablesFromAPI.kt") public void testCallableReferencesEqualToCallablesFromAPI() throws Exception { runTest("compiler/testData/codegen/box/reflection/methodsFromAny/callableReferencesEqualToCallablesFromAPI.kt"); @@ -16499,24 +16537,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { } } - @TestMetadata("compiler/testData/codegen/box/reflection/specialBuiltIns") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class SpecialBuiltIns extends AbstractJsCodegenBoxTest { - private void runTest(String testDataFilePath) throws Exception { - KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath); - } - - public void testAllFilesPresentInSpecialBuiltIns() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/specialBuiltIns"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); - } - - @TestMetadata("getMembersOfStandardJavaClasses.kt") - public void testGetMembersOfStandardJavaClasses() throws Exception { - runTest("compiler/testData/codegen/box/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt"); - } - } - @TestMetadata("compiler/testData/codegen/box/reflection/supertypes") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)