J2K: convert method references according to special methods

This commit is contained in:
Natalia Ukhorskaya
2016-01-21 13:37:55 +03:00
parent 25b64b198c
commit 9d66852ae2
3 changed files with 43 additions and 12 deletions
@@ -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 {
@@ -1,4 +1,4 @@
// ERROR: Type inference failed: Not enough information to infer parameter T in fun <T : kotlin.Any!> emptyList(): kotlin.collections.(Mutable)List<T!>! Please specify it explicitly.
// ERROR: Type inference failed: Not enough information to infer parameter T in fun <T> emptyList(): kotlin.collections.List<T> 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()
}
@@ -117,11 +117,11 @@ internal class Java8Class {
}
fun testLibraryFunctions() {
val memberFunFromClass = JFunction2<String, Int> { it.length() }
val memberFunFromClass = JFunction2<String, Int> { 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<List<String>> { Collections.emptyList() }
val emptyList = JFunction1<List<String>> { emptyList() }
emptyList.foo()
MethodReferenceHelperClass.staticFun1(JFunction1<List<String>> { Collections.emptyList() })
h.memberFun1(JFunction1<List<String>> { Collections.emptyList() })
MethodReferenceHelperClass.staticFun1(JFunction1<List<String>> { emptyList() })
h.memberFun1(JFunction1<List<String>> { emptyList() })
}
fun memberFun(): Int {