Java to Kotlin converter: added heuristics that values of types like Integer are likely nullable

This commit is contained in:
Valentin Kipyatkov
2014-06-25 00:04:14 +04:00
parent 30a7c67aaa
commit 427280a365
12 changed files with 40 additions and 15 deletions
+27 -2
View File
@@ -72,7 +72,8 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver
private fun variableNullabilityNoCache(variable: PsiVariable): Nullability { private fun variableNullabilityNoCache(variable: PsiVariable): Nullability {
if (variable is PsiEnumConstant) return Nullability.NotNull if (variable is PsiEnumConstant) return Nullability.NotNull
if (variable.getType() is PsiPrimitiveType) return Nullability.NotNull val variableType = variable.getType()
if (variableType is PsiPrimitiveType) return Nullability.NotNull
var nullability = variable.nullabilityFromAnnotations() var nullability = variable.nullabilityFromAnnotations()
@@ -102,6 +103,11 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver
} }
} }
// variables of types like Integer are most likely nullable
if (nullability == Nullability.Default && variableType.getCanonicalText() in boxingTypes) {
return Nullability.Nullable
}
if (!conversionScope.contains(variable)) { // do not analyze usages out of our conversion scope if (!conversionScope.contains(variable)) { // do not analyze usages out of our conversion scope
if (variable is PsiParameter) { if (variable is PsiParameter) {
// Object.equals corresponds to Any.equals which has nullable parameter: // Object.equals corresponds to Any.equals which has nullable parameter:
@@ -158,7 +164,8 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver
} }
private fun methodNullabilityNoCache(method: PsiMethod): Nullability { private fun methodNullabilityNoCache(method: PsiMethod): Nullability {
if (method.getReturnType() is PsiPrimitiveType) return Nullability.NotNull val returnType = method.getReturnType()
if (returnType is PsiPrimitiveType) return Nullability.NotNull
var nullability = method.nullabilityFromAnnotations() var nullability = method.nullabilityFromAnnotations()
@@ -167,6 +174,11 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver
nullability = superSignatures.map { methodNullability(it.getMethod()) }.firstOrNull { it != Nullability.Default } ?: Nullability.Default nullability = superSignatures.map { methodNullability(it.getMethod()) }.firstOrNull { it != Nullability.Default } ?: Nullability.Default
} }
// methods of types like Integer are most likely nullable
if (nullability == Nullability.Default && returnType?.getCanonicalText() in boxingTypes) {
return Nullability.Nullable
}
if (!conversionScope.contains(method)) return nullability // do not analyze body and usages of methods out of our conversion scope if (!conversionScope.contains(method)) return nullability // do not analyze body and usages of methods out of our conversion scope
if (nullability == Nullability.Default) { if (nullability == Nullability.Default) {
@@ -265,4 +277,17 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver
else else
Nullability.Default Nullability.Default
} }
class object {
private val boxingTypes: Set<String> = setOf(
CommonClassNames.JAVA_LANG_BYTE,
CommonClassNames.JAVA_LANG_CHARACTER,
CommonClassNames.JAVA_LANG_DOUBLE,
CommonClassNames.JAVA_LANG_FLOAT,
CommonClassNames.JAVA_LANG_INTEGER,
CommonClassNames.JAVA_LANG_LONG,
CommonClassNames.JAVA_LANG_SHORT,
CommonClassNames.JAVA_LANG_BOOLEAN
)
}
} }
+1 -1
View File
@@ -1,5 +1,5 @@
class A() { class A() {
private var i = getByte().toInt() private var i: Int? = getByte().toInt()
fun foo() { fun foo() {
i = 10 i = 10
@@ -5,7 +5,7 @@ class F() {
fun f2() { fun f2() {
} }
var i = 0 var i: Int? = 0
fun f3() { fun f3() {
} }
@@ -16,7 +16,7 @@ class F() {
fun f2() { fun f2() {
} }
var i = 0 var i: Int? = 0
fun f3() { fun f3() {
} }
@@ -24,7 +24,7 @@ class F() {
fun f1() { fun f1() {
} }
var i = 0 var i: Int? = 0
//c5 //c5
@@ -17,7 +17,7 @@ class F() {
fun f2() { fun f2() {
} }
var i = 0 var i: Int? = 0
fun f3() { fun f3() {
} }
@@ -1,7 +1,7 @@
package demo package demo
class Test() { class Test() {
fun putInt(i: Int) { fun putInt(i: Int?) {
} }
fun test() { fun test() {
@@ -1,7 +1,7 @@
package demo package demo
class Test() { class Test() {
fun putInt(i: Int) { fun putInt(i: Int?) {
} }
fun test() { fun test() {
@@ -1,6 +1,6 @@
package demo package demo
class Test(i: Int) { class Test(i: Int?) {
fun test() { fun test() {
val i = 10 val i = 10
@@ -1,11 +1,11 @@
package demo package demo
class Test() { class Test() {
fun getInteger(i: Int): Int { fun getInteger(i: Int?): Int? {
return i return i
} }
fun test() { fun test() {
val i = getInteger(10) val i = getInteger(10)!!
} }
} }
@@ -1,4 +1,4 @@
fun foo(i: Int) { fun foo(i: Int?) {
var i1 = i var i1 = i!!
i1++ i1++
} }
@@ -1,4 +1,4 @@
fun foo(b: Byte) { fun foo(b: Byte) {
var i = b.toInt() var i: Int? = b.toInt()
if (p) i = 10 if (p) i = 10
} }