diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt index 11da7210f2e..28aa928cea1 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt @@ -35,10 +35,11 @@ open class MethodCallExpression( } class object { - fun build(receiver: Expression, methodName: String, arguments: List = ArrayList()): MethodCallExpression { + public fun build(receiver: Expression, methodName: String, arguments: List = ArrayList()): MethodCallExpression { return MethodCallExpression(QualifiedExpression(receiver, Identifier(methodName, false)), arguments, - ArrayList(), false) + listOf(), + false) } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index 7f132a268fa..0bc0680800e 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -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(), 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 { diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index 62505f2840f..78ab6c8ae7a 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -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"); diff --git a/j2k/tests/testData/KotlinApi.kt b/j2k/tests/testData/KotlinApi.kt index 62373cf504b..344233b6959 100644 --- a/j2k/tests/testData/KotlinApi.kt +++ b/j2k/tests/testData/KotlinApi.kt @@ -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 public fun Int.extensionFunction(): String = toString() diff --git a/j2k/tests/testData/ast/kotlinApiAccess/CorrectFunNullabilityDetected.java b/j2k/tests/testData/ast/kotlinApiAccess/CorrectFunNullabilityDetected.java new file mode 100644 index 00000000000..6edd26552cb --- /dev/null +++ b/j2k/tests/testData/ast/kotlinApiAccess/CorrectFunNullabilityDetected.java @@ -0,0 +1,8 @@ +//file +import kotlinApi.* + +class A { + int foo(KotlinTrait t) { + return t.nullableFun().length() + t.notNullableFun().length(); + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/kotlinApiAccess/CorrectFunNullabilityDetected.kt b/j2k/tests/testData/ast/kotlinApiAccess/CorrectFunNullabilityDetected.kt new file mode 100644 index 00000000000..636dbbc12e0 --- /dev/null +++ b/j2k/tests/testData/ast/kotlinApiAccess/CorrectFunNullabilityDetected.kt @@ -0,0 +1,7 @@ +import kotlinApi.* + +class A() { + fun foo(t: KotlinTrait): Int { + return t.nullableFun()?.length()!! + t.notNullableFun().length() + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/kotlinApiAccess/CorrectNullabilityDetected.java b/j2k/tests/testData/ast/kotlinApiAccess/CorrectNullabilityDetected.java new file mode 100644 index 00000000000..c49f0fbe036 --- /dev/null +++ b/j2k/tests/testData/ast/kotlinApiAccess/CorrectNullabilityDetected.java @@ -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(); + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/kotlinApiAccess/CorrectNullabilityDetected.kt b/j2k/tests/testData/ast/kotlinApiAccess/CorrectNullabilityDetected.kt new file mode 100644 index 00000000000..c6e87d24074 --- /dev/null +++ b/j2k/tests/testData/ast/kotlinApiAccess/CorrectNullabilityDetected.kt @@ -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() + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/nullability/NullableMethodDotAccess.java b/j2k/tests/testData/ast/nullability/NullableMethodDotAccess.java new file mode 100644 index 00000000000..e80b0728fa2 --- /dev/null +++ b/j2k/tests/testData/ast/nullability/NullableMethodDotAccess.java @@ -0,0 +1,10 @@ +//file +class C { + String getString(boolean b) { + return b ? "a" : null; + } + + int foo() { + return getString(true).length(); + } +} diff --git a/j2k/tests/testData/ast/nullability/NullableMethodDotAccess.kt b/j2k/tests/testData/ast/nullability/NullableMethodDotAccess.kt new file mode 100644 index 00000000000..7ad01bb24c9 --- /dev/null +++ b/j2k/tests/testData/ast/nullability/NullableMethodDotAccess.kt @@ -0,0 +1,12 @@ +class C() { + fun getString(b: Boolean): String? { + return if (b) + "a" + else + null + } + + fun foo(): Int { + return getString(true)?.length()!! + } +} \ No newline at end of file