From 9d66852ae2fe6936b9a8ea4bd1e36290f67c3adf Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Thu, 21 Jan 2016 13:37:55 +0300 Subject: [PATCH] J2K: convert method references according to special methods --- .../kotlin/j2k/ExpressionConverter.kt | 37 +++++++++++++++++-- .../function/java8MRKFunctionExpectedType.kt | 6 +-- .../function/java8MRSamConstructor.kt | 12 +++--- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt index 2c8fe8aed29..065fc8ecc57 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.j2k import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key import com.intellij.psi.* import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.tree.IElementType @@ -728,14 +729,42 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { } val callParams = if (needThis) parameters.drop(1) else parameters - val statement = if (expression.isConstructor) { - MethodCallExpression.build(null, convertMethodReferenceQualifier(qualifier), callParams.map { it.first }, emptyList(), false).assignNoPrototype() + + val specialMethod = method?.let { SpecialMethod.match(it, callParams.size, converter.services) } + val statement: Statement = if (expression.isConstructor) { + MethodCallExpression.build(null, convertMethodReferenceQualifier(qualifier), callParams.map { it.first }, emptyList(), false) + } + else if (specialMethod != null) { + val factory = PsiElementFactory.SERVICE.getInstance(converter.project) + val fakeReceiver = receiver?.let { + val psiExpression = if (qualifier is PsiExpression) qualifier else factory.createExpressionFromText("fakeReceiver", null) + psiExpression.convertedExpression = it.first + psiExpression + } + val fakeParams = callParams.mapIndexed { + i, param -> + with(factory.createExpressionFromText("fake$i", null)) { + this.convertedExpression = param.first + this + } + } + val patchedConverter = codeConverter.withSpecialExpressionConverter(object : SpecialExpressionConverter { + override fun convertExpression(expression: PsiExpression, codeConverter: CodeConverter): Expression? { + val convertedExpression = expression.convertedExpression + expression.convertedExpression = null + return convertedExpression + } + }) + + specialMethod.convertCall(fakeReceiver, fakeParams.toTypedArray(), emptyList(), patchedConverter)!! } else { val referenceName = expression.referenceName!! - MethodCallExpression.build(receiver?.first, referenceName, callParams.map { it.first }, emptyList(), false).assignNoPrototype() + MethodCallExpression.build(receiver?.first, referenceName, callParams.map { it.first }, emptyList(), false) } + statement.assignNoPrototype() + val lambdaParameterList = ParameterList( if (parameters.size == 1 && !isKotlinFunctionType) { // for lambdas all parameters with types should be present @@ -766,6 +795,8 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { } } + private var PsiExpression.convertedExpression: Expression? by UserDataProperty(Key.create("CONVERTED_EXPRESSION")) + private fun isFunctionType(functionalType: PsiType?) = functionalType?.canonicalText?.startsWith("kotlin.jvm.functions.Function") ?: false private fun convertMethodReferenceQualifier(qualifier: PsiElement): String { diff --git a/j2k/testData/fileOrElement/function/java8MRKFunctionExpectedType.kt b/j2k/testData/fileOrElement/function/java8MRKFunctionExpectedType.kt index c4d28abf35f..e632eaf672c 100644 --- a/j2k/testData/fileOrElement/function/java8MRKFunctionExpectedType.kt +++ b/j2k/testData/fileOrElement/function/java8MRKFunctionExpectedType.kt @@ -1,4 +1,4 @@ -// ERROR: Type inference failed: Not enough information to infer parameter T in fun emptyList(): kotlin.collections.(Mutable)List! Please specify it explicitly. +// ERROR: Type inference failed: Not enough information to infer parameter T in fun emptyList(): kotlin.collections.List Please specify it explicitly. package test import java.util.Collections @@ -72,7 +72,7 @@ internal class Java8Class { } fun testLibraryFunctions() { - val memberFunFromClass = { obj: String -> obj.length() } + val memberFunFromClass = { obj: String -> obj.length } memberFunFromClass.invoke("str") } @@ -85,7 +85,7 @@ internal class Java8Class { } fun testGenericFunctions() { - val emptyList = { Collections.emptyList() } + val emptyList = { emptyList() } emptyList.invoke() } diff --git a/j2k/testData/fileOrElement/function/java8MRSamConstructor.kt b/j2k/testData/fileOrElement/function/java8MRSamConstructor.kt index 3eb5e443fa1..b056b550e5a 100644 --- a/j2k/testData/fileOrElement/function/java8MRSamConstructor.kt +++ b/j2k/testData/fileOrElement/function/java8MRSamConstructor.kt @@ -117,11 +117,11 @@ internal class Java8Class { } fun testLibraryFunctions() { - val memberFunFromClass = JFunction2 { it.length() } + val memberFunFromClass = JFunction2 { it.length } memberFunFromClass.foo("str") - Thread(Runnable { System.out.println() }).start() - Runnable { System.out.println() }.run() + Thread(Runnable { println() }).start() + Runnable { println() }.run() } fun testOverloads() { @@ -137,10 +137,10 @@ internal class Java8Class { } fun testGenericFunctions() { - val emptyList = JFunction1> { Collections.emptyList() } + val emptyList = JFunction1> { emptyList() } emptyList.foo() - MethodReferenceHelperClass.staticFun1(JFunction1> { Collections.emptyList() }) - h.memberFun1(JFunction1> { Collections.emptyList() }) + MethodReferenceHelperClass.staticFun1(JFunction1> { emptyList() }) + h.memberFun1(JFunction1> { emptyList() }) } fun memberFun(): Int {