Improve toString() for lambdas and function expressions
#KT-9952 Fixed
This commit is contained in:
+19
-12
@@ -1,28 +1,35 @@
|
|||||||
|
// WITH_REFLECT
|
||||||
|
|
||||||
fun check(expected: String, obj: Any?) {
|
fun check(expected: String, obj: Any?) {
|
||||||
val actual = obj.toString()
|
val actual = obj.toString()
|
||||||
if (actual != expected)
|
if (actual != expected)
|
||||||
throw AssertionError("Expected: $expected, actual: $actual")
|
throw AssertionError("Expected: $expected, actual: $actual")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
check("kotlin.jvm.functions.Function0<kotlin.Unit>")
|
check("() -> kotlin.Unit")
|
||||||
{ -> }
|
{ -> }
|
||||||
check("kotlin.jvm.functions.Function0<java.lang.Integer>")
|
check("() -> kotlin.Int")
|
||||||
{ -> 42 }
|
{ -> 42 }
|
||||||
check("kotlin.jvm.functions.Function1<java.lang.String, java.lang.Long>",
|
check("(kotlin.String) -> kotlin.Long",
|
||||||
fun (s: String) = 42.toLong())
|
fun (s: String) = 42.toLong())
|
||||||
check("kotlin.jvm.functions.Function2<java.lang.Integer, java.lang.Integer, kotlin.Unit>")
|
check("(kotlin.Int, kotlin.Int) -> kotlin.Unit")
|
||||||
{ x: Int, y: Int -> }
|
{ x: Int, y: Int -> }
|
||||||
|
|
||||||
check("kotlin.jvm.functions.Function1<java.lang.Integer, kotlin.Unit>",
|
check("kotlin.Int.() -> kotlin.Unit",
|
||||||
fun Int.() {})
|
fun Int.() {})
|
||||||
check("kotlin.jvm.functions.Function1<kotlin.Unit, java.lang.Integer>",
|
check("kotlin.Unit.() -> kotlin.Int?",
|
||||||
fun Unit.(): Int = 42)
|
fun Unit.(): Int? = 42)
|
||||||
check("kotlin.jvm.functions.Function2<java.lang.String, java.lang.String, java.lang.Long>",
|
check("kotlin.String.(kotlin.String?) -> kotlin.Long",
|
||||||
fun String.(s: String): Long = 42.toLong())
|
fun String.(s: String?): Long = 42.toLong())
|
||||||
check("kotlin.jvm.functions.Function3<java.lang.Integer, java.lang.Integer, java.lang.Integer, kotlin.Unit>",
|
check("kotlin.collections.List<kotlin.String>.(kotlin.collections.MutableSet<*>, kotlin.Nothing) -> kotlin.Unit",
|
||||||
fun Int.(x: Int, y: Int) {})
|
fun List<String>.(x: MutableSet<*>, y: Nothing) {})
|
||||||
|
|
||||||
|
check("(kotlin.IntArray, kotlin.ByteArray, kotlin.ShortArray, kotlin.CharArray, kotlin.LongArray, kotlin.BooleanArray, kotlin.FloatArray, kotlin.DoubleArray) -> kotlin.Array<kotlin.Int>",
|
||||||
|
fun (ia: IntArray, ba: ByteArray, sa: ShortArray, ca: CharArray, la: LongArray, za: BooleanArray, fa: FloatArray, da: DoubleArray): Array<Int> = null!!)
|
||||||
|
|
||||||
|
check("(kotlin.Array<kotlin.Array<kotlin.Array<kotlin.collections.List<kotlin.String>>>>) -> kotlin.Comparable<kotlin.String>",
|
||||||
|
fun (a: Array<Array<Array<List<String>>>>): Comparable<String> = null!!)
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
fun check(expected: String, obj: Any?) {
|
||||||
|
val actual = obj.toString()
|
||||||
|
if (actual != expected)
|
||||||
|
throw AssertionError("Expected: $expected, actual: $actual")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
check("Function0<kotlin.Unit>")
|
||||||
|
{ -> }
|
||||||
|
check("Function0<java.lang.Integer>")
|
||||||
|
{ -> 42 }
|
||||||
|
check("Function1<java.lang.String, java.lang.Long>",
|
||||||
|
fun (s: String) = 42.toLong())
|
||||||
|
check("Function2<java.lang.Integer, java.lang.Integer, kotlin.Unit>")
|
||||||
|
{ x: Int, y: Int -> }
|
||||||
|
|
||||||
|
check("Function1<java.lang.Integer, kotlin.Unit>",
|
||||||
|
fun Int.() {})
|
||||||
|
check("Function1<kotlin.Unit, java.lang.Integer>",
|
||||||
|
fun Unit.(): Int? = 42)
|
||||||
|
check("Function2<java.lang.String, java.lang.String, java.lang.Long>",
|
||||||
|
fun String.(s: String?): Long = 42.toLong())
|
||||||
|
check("Function3<java.util.List<? extends java.lang.String>, java.util.Set<?>, ?, kotlin.Unit>",
|
||||||
|
fun List<String>.(x: MutableSet<*>, y: Nothing) {})
|
||||||
|
|
||||||
|
check("Function8<int[], byte[], short[], char[], long[], boolean[], float[], double[], java.lang.Integer[]>",
|
||||||
|
fun (ia: IntArray, ba: ByteArray, sa: ShortArray, ca: CharArray, la: LongArray, za: BooleanArray, fa: FloatArray, da: DoubleArray): Array<Int> = null!!)
|
||||||
|
|
||||||
|
check("Function1<java.util.List<? extends java.lang.String>[][][], java.lang.Comparable<? super java.lang.String>>",
|
||||||
|
fun (a: Array<Array<Array<List<String>>>>): Comparable<String> = null!!)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -6175,6 +6175,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("functionNtoStringNoReflect.kt")
|
||||||
|
public void testFunctionNtoStringNoReflect() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/functionNtoStringNoReflect.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("infixRecursiveCall.kt")
|
@TestMetadata("infixRecursiveCall.kt")
|
||||||
public void testInfixRecursiveCall() throws Exception {
|
public void testInfixRecursiveCall() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/infixRecursiveCall.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/infixRecursiveCall.kt");
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package kotlin.reflect.jvm.internal;
|
|||||||
|
|
||||||
import kotlin.jvm.internal.*;
|
import kotlin.jvm.internal.*;
|
||||||
import kotlin.reflect.*;
|
import kotlin.reflect.*;
|
||||||
|
import kotlin.reflect.jvm.ReflectLambdaKt;
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @suppress
|
* @suppress
|
||||||
@@ -49,6 +51,18 @@ public class ReflectionFactoryImpl extends ReflectionFactory {
|
|||||||
return KClassCacheKt.getOrCreateKotlinClass(javaClass);
|
return KClassCacheKt.getOrCreateKotlinClass(javaClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String renderLambdaToString(Lambda lambda) {
|
||||||
|
KFunction kFunction = ReflectLambdaKt.reflect(lambda);
|
||||||
|
if (kFunction != null) {
|
||||||
|
KFunctionImpl impl = UtilKt.asKFunctionImpl(kFunction);
|
||||||
|
if (impl != null) {
|
||||||
|
return ReflectionObjectRenderer.INSTANCE.renderLambda(impl.getDescriptor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.renderLambdaToString(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ internal object ReflectionObjectRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun StringBuilder.appendReceiversAndName(callable: CallableDescriptor) {
|
private fun StringBuilder.appendReceivers(callable: CallableDescriptor) {
|
||||||
val dispatchReceiver = callable.dispatchReceiverParameter
|
val dispatchReceiver = callable.dispatchReceiverParameter
|
||||||
val extensionReceiver = callable.extensionReceiverParameter
|
val extensionReceiver = callable.extensionReceiverParameter
|
||||||
|
|
||||||
@@ -44,8 +44,6 @@ internal object ReflectionObjectRenderer {
|
|||||||
if (addParentheses) append("(")
|
if (addParentheses) append("(")
|
||||||
appendReceiverType(extensionReceiver)
|
appendReceiverType(extensionReceiver)
|
||||||
if (addParentheses) append(")")
|
if (addParentheses) append(")")
|
||||||
|
|
||||||
append(renderer.renderName(callable.name))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun renderCallable(descriptor: CallableDescriptor): String {
|
fun renderCallable(descriptor: CallableDescriptor): String {
|
||||||
@@ -60,7 +58,8 @@ internal object ReflectionObjectRenderer {
|
|||||||
fun renderProperty(descriptor: PropertyDescriptor): String {
|
fun renderProperty(descriptor: PropertyDescriptor): String {
|
||||||
return buildString {
|
return buildString {
|
||||||
append(if (descriptor.isVar) "var " else "val ")
|
append(if (descriptor.isVar) "var " else "val ")
|
||||||
appendReceiversAndName(descriptor)
|
appendReceivers(descriptor)
|
||||||
|
append(renderer.renderName(descriptor.name))
|
||||||
|
|
||||||
append(": ")
|
append(": ")
|
||||||
append(renderType(descriptor.type))
|
append(renderType(descriptor.type))
|
||||||
@@ -70,7 +69,8 @@ internal object ReflectionObjectRenderer {
|
|||||||
fun renderFunction(descriptor: FunctionDescriptor): String {
|
fun renderFunction(descriptor: FunctionDescriptor): String {
|
||||||
return buildString {
|
return buildString {
|
||||||
append("fun ")
|
append("fun ")
|
||||||
appendReceiversAndName(descriptor)
|
appendReceivers(descriptor)
|
||||||
|
append(renderer.renderName(descriptor.name))
|
||||||
|
|
||||||
descriptor.valueParameters.joinTo(this, separator = ", ", prefix = "(", postfix = ")") {
|
descriptor.valueParameters.joinTo(this, separator = ", ", prefix = "(", postfix = ")") {
|
||||||
renderType(it.type) // TODO: vararg
|
renderType(it.type) // TODO: vararg
|
||||||
@@ -81,6 +81,19 @@ internal object ReflectionObjectRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun renderLambda(invoke: FunctionDescriptor): String {
|
||||||
|
return buildString {
|
||||||
|
appendReceivers(invoke)
|
||||||
|
|
||||||
|
invoke.valueParameters.joinTo(this, separator = ", ", prefix = "(", postfix = ")") {
|
||||||
|
renderType(it.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
append(" -> ")
|
||||||
|
append(renderType(invoke.returnType!!))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun renderParameter(parameter: KParameterImpl): String {
|
fun renderParameter(parameter: KParameterImpl): String {
|
||||||
return buildString {
|
return buildString {
|
||||||
when (parameter.kind) {
|
when (parameter.kind) {
|
||||||
|
|||||||
@@ -19,6 +19,5 @@ package kotlin.jvm.internal
|
|||||||
abstract class Lambda(private val arity: Int) : FunctionImpl() {
|
abstract class Lambda(private val arity: Int) : FunctionImpl() {
|
||||||
override fun getArity() = arity
|
override fun getArity() = arity
|
||||||
|
|
||||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
override fun toString() = Reflection.renderLambdaToString(this)
|
||||||
override fun toString() = "${(this as Object).`class`.genericInterfaces[0]}"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ public class Reflection {
|
|||||||
return kClasses;
|
return kClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String renderLambdaToString(Lambda lambda) {
|
||||||
|
return factory.renderLambdaToString(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
|
|
||||||
public static KFunction function(FunctionReference f) {
|
public static KFunction function(FunctionReference f) {
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ package kotlin.jvm.internal;
|
|||||||
import kotlin.reflect.*;
|
import kotlin.reflect.*;
|
||||||
|
|
||||||
public class ReflectionFactory {
|
public class ReflectionFactory {
|
||||||
|
private static final String KOTLIN_JVM_FUNCTIONS = "kotlin.jvm.functions.";
|
||||||
|
|
||||||
public KClass createKotlinClass(Class javaClass) {
|
public KClass createKotlinClass(Class javaClass) {
|
||||||
return new ClassReference(javaClass);
|
return new ClassReference(javaClass);
|
||||||
}
|
}
|
||||||
@@ -39,6 +41,11 @@ public class ReflectionFactory {
|
|||||||
return new ClassReference(javaClass);
|
return new ClassReference(javaClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String renderLambdaToString(Lambda lambda) {
|
||||||
|
String result = lambda.getClass().getGenericInterfaces()[0].toString();
|
||||||
|
return result.startsWith(KOTLIN_JVM_FUNCTIONS) ? result.substring(KOTLIN_JVM_FUNCTIONS.length()) : result;
|
||||||
|
}
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
|
|
||||||
public KFunction function(FunctionReference f) {
|
public KFunction function(FunctionReference f) {
|
||||||
|
|||||||
Reference in New Issue
Block a user