Java to Kotlin converter: more smartness about variables nullability

This commit is contained in:
Valentin Kipyatkov
2014-06-04 16:35:34 +04:00
parent f96721fa7e
commit 15ffb6768c
9 changed files with 104 additions and 12 deletions
+32 -2
View File
@@ -461,13 +461,43 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
var nullability = variable.nullabilityFromAnnotations()
if (nullability == Nullability.Default) {
val initializer = variable.getInitializer()
if (initializer != null && variable.hasModifierProperty(PsiModifier.FINAL)) {
nullability = initializer.nullability()
if (initializer != null) {
val initializerNullability = initializer.nullability()
if (variable.hasModifierProperty(PsiModifier.FINAL)) { //TODO: replace check for final modifier with effective final
nullability = initializerNullability
}
else if (initializerNullability == Nullability.Nullable) { // if variable is not final then non-nullability of initializer does not mean that variable is non-null
nullability = Nullability.Nullable
}
}
}
return convertType(variable.getType(), nullability)
}
private fun PsiExpression.nullability(): Nullability {
return when (this) {
is PsiLiteralExpression -> if (getValue() != null) Nullability.NotNull else Nullability.Nullable
is PsiNewExpression -> Nullability.NotNull
is PsiConditionalExpression -> {
val nullability1 = getThenExpression()?.nullability()
if (nullability1 == Nullability.Nullable) return Nullability.Nullable
val nullability2 = getElseExpression()?.nullability()
if (nullability2 == Nullability.Nullable) return Nullability.Nullable
if (nullability1 == Nullability.NotNull && nullability2 == Nullability.NotNull) return Nullability.NotNull
Nullability.Default
}
is PsiParenthesizedExpression -> getExpression()?.nullability() ?: Nullability.Default
//TODO: some other cases
else -> Nullability.Default
}
}
private fun convertToNotNullableTypes(types: Array<out PsiType?>): List<Type>
= types.map { convertType(it, Nullability.NotNull) }
-7
View File
@@ -62,13 +62,6 @@ fun PsiModifierListOwner.nullabilityFromAnnotations(): Nullability {
Nullability.Default
}
fun PsiElement?.nullability(): Nullability = when(this) {
is PsiLiteralExpression -> if (getValue() != null) Nullability.NotNull else Nullability.Nullable
is PsiNewExpression -> Nullability.NotNull
//TODO: other cases
else -> Nullability.Default
}
fun getDefaultInitializer(field: Field): String {
if (field.`type`.isNullable) {
return "null"
@@ -16,19 +16,22 @@
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")
@TestMetadata("j2k/tests/testData/ast")
@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinExclusion.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class})
@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinExclusion.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class})
public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConverterTest {
public void testAllFilesPresentInAst() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast"), Pattern.compile("^(.+)\\.java$"), true);
@@ -1771,6 +1774,29 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
}
@TestMetadata("j2k/tests/testData/ast/nullability")
public static class Nullability extends AbstractJavaToKotlinConverterTest {
public void testAllFilesPresentInNullability() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/nullability"), Pattern.compile("^(.+)\\.java$"), true);
}
@TestMetadata("FieldInitializedWithNull.java")
public void testFieldInitializedWithNull() throws Exception {
doTest("j2k/tests/testData/ast/nullability/FieldInitializedWithNull.java");
}
@TestMetadata("InitializedWithNull.java")
public void testInitializedWithNull() throws Exception {
doTest("j2k/tests/testData/ast/nullability/InitializedWithNull.java");
}
@TestMetadata("InitializedWithTernaryNull.java")
public void testInitializedWithTernaryNull() throws Exception {
doTest("j2k/tests/testData/ast/nullability/InitializedWithTernaryNull.java");
}
}
@TestMetadata("j2k/tests/testData/ast/objectLiteral")
public static class ObjectLiteral extends AbstractJavaToKotlinConverterTest {
public void testAllFilesPresentInObjectLiteral() throws Exception {
@@ -2404,6 +2430,7 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
suite.addTestSuite(MethodCallExpression.class);
suite.addTestSuite(Misc.class);
suite.addTestSuite(NewClassExpression.class);
suite.addTestSuite(Nullability.class);
suite.addTestSuite(ObjectLiteral.class);
suite.addTestSuite(OutProjectionType.class);
suite.addTestSuite(PackageStatement.class);
@@ -0,0 +1,8 @@
//file
class C {
private String s = null;
void foo() {
s = "x"
}
}
@@ -0,0 +1,7 @@
class C() {
private var s: String? = null
fun foo() {
s = "x"
}
}
@@ -0,0 +1,8 @@
//method
// !specifyLocalVariableTypeByDefault: true
void foo(boolean b) {
String s = null;
if (b) {
s = "abc"
}
}
@@ -0,0 +1,7 @@
// !specifyLocalVariableTypeByDefault: true
fun foo(b: Boolean) {
val s: String? = null
if (b) {
s = "abc"
}
}
@@ -0,0 +1,5 @@
//method
// !specifyLocalVariableTypeByDefault: true
void foo(boolean b) {
String s = (b ? "abc" : null);
}
@@ -0,0 +1,7 @@
// !specifyLocalVariableTypeByDefault: true
fun foo(b: Boolean) {
val s: String? = ((if (b)
"abc"
else
null))
}