Java to Kotlin converter: better treatment of nullable expressions
This commit is contained in:
@@ -35,10 +35,11 @@ open class MethodCallExpression(
|
||||
}
|
||||
|
||||
class object {
|
||||
fun build(receiver: Expression, methodName: String, arguments: List<Expression> = ArrayList()): MethodCallExpression {
|
||||
public fun build(receiver: Expression, methodName: String, arguments: List<Expression> = ArrayList()): MethodCallExpression {
|
||||
return MethodCallExpression(QualifiedExpression(receiver, Identifier(methodName, false)),
|
||||
arguments,
|
||||
ArrayList(), false)
|
||||
listOf(),
|
||||
false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.jetbrains.jet.lang.psi.psiUtil.isExtensionDeclaration
|
||||
import org.jetbrains.jet.lang.psi.JetPropertyAccessor
|
||||
import com.intellij.psi.impl.light.LightField
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi
|
||||
import org.jetbrains.jet.lang.psi.JetNullableType
|
||||
|
||||
class ExpressionVisitor(private val converter: Converter,
|
||||
private val typeConverter: TypeConverter,
|
||||
@@ -91,7 +92,7 @@ class ExpressionVisitor(private val converter: Converter,
|
||||
|
||||
override fun visitClassObjectAccessExpression(expression: PsiClassObjectAccessExpression) {
|
||||
val typeElement = converter.convertTypeElement(expression.getOperand())
|
||||
result = MethodCallExpression(Identifier("javaClass"), listOf(), listOf(typeElement.`type`.toNotNullType()), true)
|
||||
result = MethodCallExpression(Identifier("javaClass"), listOf(), listOf(typeElement.`type`.toNotNullType()), false)
|
||||
}
|
||||
|
||||
override fun visitConditionalExpression(expression: PsiConditionalExpression) {
|
||||
@@ -152,6 +153,9 @@ class ExpressionVisitor(private val converter: Converter,
|
||||
val methodExpr = expression.getMethodExpression()
|
||||
val arguments = expression.getArgumentList().getExpressions()
|
||||
val target = methodExpr.resolve()
|
||||
val isNullable = if (target is PsiMethod) typeConverter.convertMethodReturnType(target).isNullable else false
|
||||
val typeArguments = typeConverter.convertTypes(expression.getTypeArguments())
|
||||
|
||||
if (target is KotlinLightMethod) {
|
||||
val origin = target.origin
|
||||
val isTopLevel = origin?.getParentByType(javaClass<JetClassOrObject>(), true) == null
|
||||
@@ -159,7 +163,7 @@ class ExpressionVisitor(private val converter: Converter,
|
||||
val property = if (origin is JetProperty) origin else origin.getParent() as JetProperty
|
||||
val parameterCount = target.getParameterList().getParameters().size
|
||||
if (parameterCount == arguments.size) {
|
||||
val propertyName = Identifier(property.getName()!!, false)
|
||||
val propertyName = Identifier(property.getName()!!, isNullable)
|
||||
val isExtension = property.isExtensionDeclaration()
|
||||
val propertyAccess = if (isTopLevel) {
|
||||
if (isExtension)
|
||||
@@ -191,18 +195,17 @@ class ExpressionVisitor(private val converter: Converter,
|
||||
val qualifier = converter.convertExpression(arguments.firstOrNull())
|
||||
MethodCallExpression(QualifiedExpression(qualifier, Identifier(origin.getName()!!, false)),
|
||||
convertArguments(expression, isExtension = true),
|
||||
typeConverter.convertTypes(expression.getTypeArguments()),
|
||||
typeConverter.convertType(expression.getType()).isNullable)
|
||||
typeArguments,
|
||||
isNullable)
|
||||
}
|
||||
else {
|
||||
MethodCallExpression(Identifier(origin.getName()!!, false),
|
||||
convertArguments(expression),
|
||||
typeConverter.convertTypes(expression.getTypeArguments()),
|
||||
typeConverter.convertType(expression.getType()).isNullable)
|
||||
typeArguments,
|
||||
isNullable)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,8 +219,8 @@ class ExpressionVisitor(private val converter: Converter,
|
||||
|
||||
result = MethodCallExpression(converter.convertExpression(methodExpr),
|
||||
convertArguments(expression),
|
||||
typeConverter.convertTypes(expression.getTypeArguments()),
|
||||
typeConverter.convertType(expression.getType()).isNullable)
|
||||
typeArguments,
|
||||
isNullable)
|
||||
}
|
||||
|
||||
private fun isObjectEquals(method: PsiMethod): Boolean {
|
||||
|
||||
@@ -16,14 +16,17 @@
|
||||
|
||||
package org.jetbrains.jet.j2k.test;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
import org.jetbrains.jet.JetTestUtils;
|
||||
import org.jetbrains.jet.test.InnerTestClasses;
|
||||
import org.jetbrains.jet.test.TestMetadata;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
import org.jetbrains.jet.j2k.test.AbstractJavaToKotlinConverterTest;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@@ -1596,6 +1599,16 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
|
||||
doTest("j2k/tests/testData/ast/kotlinApiAccess/ClassObjectMembers.java");
|
||||
}
|
||||
|
||||
@TestMetadata("CorrectFunNullabilityDetected.java")
|
||||
public void testCorrectFunNullabilityDetected() throws Exception {
|
||||
doTest("j2k/tests/testData/ast/kotlinApiAccess/CorrectFunNullabilityDetected.java");
|
||||
}
|
||||
|
||||
@TestMetadata("CorrectNullabilityDetected.java")
|
||||
public void testCorrectNullabilityDetected() throws Exception {
|
||||
doTest("j2k/tests/testData/ast/kotlinApiAccess/CorrectNullabilityDetected.java");
|
||||
}
|
||||
|
||||
@TestMetadata("ExtensionFunction.java")
|
||||
public void testExtensionFunction() throws Exception {
|
||||
doTest("j2k/tests/testData/ast/kotlinApiAccess/ExtensionFunction.java");
|
||||
@@ -1958,6 +1971,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
|
||||
doTest("j2k/tests/testData/ast/nullability/MethodReturnsTernaryNull.java");
|
||||
}
|
||||
|
||||
@TestMetadata("NullableMethodDotAccess.java")
|
||||
public void testNullableMethodDotAccess() throws Exception {
|
||||
doTest("j2k/tests/testData/ast/nullability/NullableMethodDotAccess.java");
|
||||
}
|
||||
|
||||
@TestMetadata("NullableVariableDotAccess.java")
|
||||
public void testNullableVariableDotAccess() throws Exception {
|
||||
doTest("j2k/tests/testData/ast/nullability/NullableVariableDotAccess.java");
|
||||
|
||||
@@ -2,6 +2,7 @@ package kotlinApi
|
||||
|
||||
public open class KotlinClass {
|
||||
public var property: String = ""
|
||||
public var nullableProperty: String? = ""
|
||||
|
||||
class object {
|
||||
public fun staticFun(p: Int): Int = p
|
||||
@@ -9,10 +10,19 @@ public open class KotlinClass {
|
||||
public var staticProperty: Int
|
||||
get() = 1
|
||||
set(value) {}
|
||||
|
||||
public fun nullableStaticFun(p: Int?): Int? = p
|
||||
public var nullableStaticVar: Int? = 1
|
||||
}
|
||||
}
|
||||
|
||||
public trait KotlinTrait {
|
||||
public fun nullableFun(): String?
|
||||
public fun notNullableFun(): String
|
||||
}
|
||||
|
||||
public fun globalFunction(s: String): String = s
|
||||
public fun nullableGlobalFunction(s: String?): String? = s
|
||||
public fun globalGenericFunction<T>(t: T): T = t
|
||||
|
||||
public fun Int.extensionFunction(): String = toString()
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
//file
|
||||
import kotlinApi.*
|
||||
|
||||
class A {
|
||||
int foo(KotlinTrait t) {
|
||||
return t.nullableFun().length() + t.notNullableFun().length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import kotlinApi.*
|
||||
|
||||
class A() {
|
||||
fun foo(t: KotlinTrait): Int {
|
||||
return t.nullableFun()?.length()!! + t.notNullableFun().length()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
//file
|
||||
import kotlinApi.*;
|
||||
|
||||
class A {
|
||||
int foo(KotlinClass c) {
|
||||
return c.getNullableProperty().length()
|
||||
+ c.getProperty().length()
|
||||
+ KotlinClass.object$.getNullableStaticVar()
|
||||
+ KotlinClass.object$.getStaticVar()
|
||||
+ KotlinClass.object$.nullableStaticFun(1)
|
||||
+ KotlinClass.object$.staticFun(1)
|
||||
+ KotlinApiPackage.nullableGlobalFunction("").length()
|
||||
+ KotlinApiPackage.globalFunction("").length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import kotlinApi.*
|
||||
|
||||
class A() {
|
||||
fun foo(c: KotlinClass): Int {
|
||||
return c.nullableProperty?.length()!! + c.property.length() + KotlinClass.nullableStaticVar!! + KotlinClass.staticVar + KotlinClass.nullableStaticFun(1)!! + KotlinClass.staticFun(1) + nullableGlobalFunction("")?.length()!! + globalFunction("").length()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
//file
|
||||
class C {
|
||||
String getString(boolean b) {
|
||||
return b ? "a" : null;
|
||||
}
|
||||
|
||||
int foo() {
|
||||
return getString(true).length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class C() {
|
||||
fun getString(b: Boolean): String? {
|
||||
return if (b)
|
||||
"a"
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
fun foo(): Int {
|
||||
return getString(true)?.length()!!
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user