From 2ebaab867d3c561a95248d7f9a087fc04b715d56 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 8 Jul 2014 21:34:46 +0400 Subject: [PATCH] Fixed KT-5434 J2K: incorrect conversion of main method #KT-5434 Fixed --- .../org/jetbrains/jet/j2k/MainMethodUtils.kt | 68 ++++++------------- .../org/jetbrains/jet/j2k/TypeConverter.kt | 22 +++++- .../JavaToKotlinConverterTestGenerated.java | 10 +++ j2k/tests/testData/ast/function/main2.java | 5 ++ j2k/tests/testData/ast/function/main2.kt | 7 ++ .../function/mainAndNullabilitySetting.java | 6 ++ .../ast/function/mainAndNullabilitySetting.kt | 8 +++ j2k/tests/testData/ast/issues/kt-638.kt | 2 +- j2k/tests/testData/ast/issues/kt-871.kt | 2 +- .../testData/ast/switch/comlicatedFallDown.kt | 2 +- j2k/tests/testData/ast/switch/emptySwitch.kt | 2 +- j2k/tests/testData/ast/switch/fallDown.kt | 2 +- j2k/tests/testData/ast/switch/kt-539.kt | 2 +- j2k/tests/testData/ast/switch/nondefault.kt | 2 +- 14 files changed, 83 insertions(+), 57 deletions(-) create mode 100644 j2k/tests/testData/ast/function/main2.java create mode 100644 j2k/tests/testData/ast/function/main2.kt create mode 100644 j2k/tests/testData/ast/function/mainAndNullabilitySetting.java create mode 100644 j2k/tests/testData/ast/function/mainAndNullabilitySetting.kt diff --git a/j2k/src/org/jetbrains/jet/j2k/MainMethodUtils.kt b/j2k/src/org/jetbrains/jet/j2k/MainMethodUtils.kt index c508d8dd507..9b64bce9f4f 100644 --- a/j2k/src/org/jetbrains/jet/j2k/MainMethodUtils.kt +++ b/j2k/src/org/jetbrains/jet/j2k/MainMethodUtils.kt @@ -16,80 +16,52 @@ package org.jetbrains.jet.j2k -import java.text.MessageFormat import com.intellij.psi.PsiMethod import com.intellij.psi.PsiClass import com.intellij.psi.PsiJavaFile import java.util.ArrayList -import com.intellij.psi.PsiFile import com.intellij.psi.PsiAnonymousClass import com.intellij.psi.PsiModifier import com.intellij.psi.PsiType import com.intellij.psi.PsiArrayType -fun createMainFunction(file: PsiFile): String { +fun createMainFunction(file: PsiJavaFile): String { val classNamesWithMains = ArrayList>() - for (c in (file as PsiJavaFile).getClasses()) { + for (c in file.getClasses()) { val main = findMainMethod(c) val name = c.getName() if (name != null && main != null) { - classNamesWithMains.add(Pair(name, main)) + classNamesWithMains.add(name to main) } } - if (classNamesWithMains.size() > 0) { - var className = classNamesWithMains[0].first - return MessageFormat.format("fun main(args : Array) = {0}.main(args as Array?)", className) + if (classNamesWithMains.isNotEmpty()) { + var className = classNamesWithMains.first().first + return "fun main(args : Array) = $className.main(args)" } return "" - } -private fun findMainMethod(aClass: PsiClass): PsiMethod? { - if (isMainClass(aClass)) { - return findMainMethod(aClass.findMethodsByName("main", false)) - } - return null -} +private fun findMainMethod(aClass: PsiClass): PsiMethod? + = if (isMainClass(aClass)) aClass.findMethodsByName("main", false).firstOrNull { it.isMainMethod() } else null -private fun isMainClass(psiClass: PsiClass): Boolean { - if (psiClass is PsiAnonymousClass) - return false +private fun isMainClass(psiClass: PsiClass): Boolean + = psiClass !is PsiAnonymousClass && + !psiClass.isInterface() && + (psiClass.getContainingClass() == null || psiClass.hasModifierProperty(PsiModifier.STATIC)) - if (psiClass.isInterface()) - return false +fun PsiMethod.isMainMethod(): Boolean { + if (getReturnType() != PsiType.VOID) return false + if (!hasModifierProperty(PsiModifier.STATIC)) return false + if (!hasModifierProperty(PsiModifier.PUBLIC)) return false - return psiClass.getContainingClass() == null || psiClass.hasModifierProperty(PsiModifier.STATIC) + val parameters = getParameterList().getParameters() + if (parameters.size != 1) return false -} - -private fun findMainMethod(mainMethods: Array): PsiMethod? { - return mainMethods.find { isMainMethod(it) } -} - -fun isMainMethod(method: PsiMethod): Boolean { - if (method.getContainingClass() == null) - return false - - if (PsiType.VOID != method.getReturnType()) - return false - - if (!method.hasModifierProperty(PsiModifier.STATIC)) - return false - - if (!method.hasModifierProperty(PsiModifier.PUBLIC)) - return false - - val parameters = method.getParameterList().getParameters() - if (parameters.size != 1) - return false - - val `type` = parameters[0].getType() - if (`type` !is PsiArrayType) - return false + val `type` = parameters.single().getType() + if (`type` !is PsiArrayType) return false val componentType = `type`.getComponentType() return componentType.equalsToText("java.lang.String") } - diff --git a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt index 546e54442ad..683d327f3a4 100644 --- a/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/TypeConverter.kt @@ -29,6 +29,9 @@ import com.intellij.psi.CommonClassNames.JAVA_LANG_OBJECT import org.jetbrains.jet.j2k.ast.assignNoPrototype import org.jetbrains.jet.j2k.ast.ErrorType import com.intellij.codeInsight.NullableNotNullManager +import org.jetbrains.jet.j2k.ast.ArrayType +import org.jetbrains.jet.j2k.ast.ClassType +import org.jetbrains.jet.j2k.ast.Identifier class TypeConverter(val settings: ConverterSettings, val conversionScope: ConversionScope) { private val nullabilityCache = HashMap() @@ -59,8 +62,17 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver public fun convertTypes(types: Array): List = types.map { convertType(it) } - public fun convertVariableType(variable: PsiVariable): Type - = convertType(variable.getType(), variableNullability(variable)).assignPrototype(variable.getTypeElement()) + public fun convertVariableType(variable: PsiVariable): Type { + val result = if (variable.isMainMethodParameter()) { + ArrayType(ClassType(Identifier("String").assignNoPrototype(), listOf(), Nullability.NotNull, settings).assignNoPrototype(), + Nullability.NotNull, + settings) + } + else { + convertType(variable.getType(), variableNullability(variable)) + } + return result.assignPrototype(variable.getTypeElement()) + } public fun variableNullability(variable: PsiVariable): Nullability { val cached = nullabilityCache[variable] @@ -108,6 +120,10 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver return Nullability.Nullable } + if (nullability == Nullability.Default && variable.isMainMethodParameter() ) { + return Nullability.NotNull + } + if (!conversionScope.contains(variable)) { // do not analyze usages out of our conversion scope if (variable is PsiParameter) { // Object.equals corresponds to Any.equals which has nullable parameter: @@ -158,6 +174,8 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver return nullability } + private fun PsiVariable.isMainMethodParameter() = this is PsiParameter && (getDeclarationScope() as? PsiMethod)?.isMainMethod() ?: false + public fun convertMethodReturnType(method: PsiMethod): Type = convertType(method.getReturnType(), methodNullability(method)).assignPrototype(method.getReturnTypeElement()) 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 fec40a87653..6cf4b25102e 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -1391,6 +1391,16 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv doTest("j2k/tests/testData/ast/function/main.java"); } + @TestMetadata("main2.java") + public void testMain2() throws Exception { + doTest("j2k/tests/testData/ast/function/main2.java"); + } + + @TestMetadata("mainAndNullabilitySetting.java") + public void testMainAndNullabilitySetting() throws Exception { + doTest("j2k/tests/testData/ast/function/mainAndNullabilitySetting.java"); + } + @TestMetadata("methodClassType.java") public void testMethodClassType() throws Exception { doTest("j2k/tests/testData/ast/function/methodClassType.java"); diff --git a/j2k/tests/testData/ast/function/main2.java b/j2k/tests/testData/ast/function/main2.java new file mode 100644 index 00000000000..aa603b44eee --- /dev/null +++ b/j2k/tests/testData/ast/function/main2.java @@ -0,0 +1,5 @@ +//file +public class A { + public static void main(String[] args) { + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/function/main2.kt b/j2k/tests/testData/ast/function/main2.kt new file mode 100644 index 00000000000..e8db5f60a82 --- /dev/null +++ b/j2k/tests/testData/ast/function/main2.kt @@ -0,0 +1,7 @@ +public class A { + class object { + public fun main(args: Array) { + } + } +} +fun main(args: Array) = A.main(args) \ No newline at end of file diff --git a/j2k/tests/testData/ast/function/mainAndNullabilitySetting.java b/j2k/tests/testData/ast/function/mainAndNullabilitySetting.java new file mode 100644 index 00000000000..15557c69446 --- /dev/null +++ b/j2k/tests/testData/ast/function/mainAndNullabilitySetting.java @@ -0,0 +1,6 @@ +// !forceNotNullTypes: false +//file +public class A { + public static void main(String[] args) { + } +} \ No newline at end of file diff --git a/j2k/tests/testData/ast/function/mainAndNullabilitySetting.kt b/j2k/tests/testData/ast/function/mainAndNullabilitySetting.kt new file mode 100644 index 00000000000..39bef204e6b --- /dev/null +++ b/j2k/tests/testData/ast/function/mainAndNullabilitySetting.kt @@ -0,0 +1,8 @@ +// !forceNotNullTypes: false +public class A { + class object { + public fun main(args: Array) { + } + } +} +fun main(args: Array) = A.main(args) \ No newline at end of file diff --git a/j2k/tests/testData/ast/issues/kt-638.kt b/j2k/tests/testData/ast/issues/kt-638.kt index 0a1e2e8c56d..4423bbd03f7 100644 --- a/j2k/tests/testData/ast/issues/kt-638.kt +++ b/j2k/tests/testData/ast/issues/kt-638.kt @@ -31,4 +31,4 @@ public class User { } } } -fun main(args: Array) = User.main(args as Array?) \ No newline at end of file +fun main(args: Array) = User.main(args) \ No newline at end of file diff --git a/j2k/tests/testData/ast/issues/kt-871.kt b/j2k/tests/testData/ast/issues/kt-871.kt index d39c20b6e45..742b143033b 100644 --- a/j2k/tests/testData/ast/issues/kt-871.kt +++ b/j2k/tests/testData/ast/issues/kt-871.kt @@ -7,4 +7,4 @@ class Program { } } } -fun main(args: Array) = Program.main(args as Array?) \ No newline at end of file +fun main(args: Array) = Program.main(args) \ No newline at end of file diff --git a/j2k/tests/testData/ast/switch/comlicatedFallDown.kt b/j2k/tests/testData/ast/switch/comlicatedFallDown.kt index dcd8cd667a1..539e559599b 100644 --- a/j2k/tests/testData/ast/switch/comlicatedFallDown.kt +++ b/j2k/tests/testData/ast/switch/comlicatedFallDown.kt @@ -83,4 +83,4 @@ public class SwitchDemo { } } } -fun main(args: Array) = SwitchDemo.main(args as Array?) \ No newline at end of file +fun main(args: Array) = SwitchDemo.main(args) \ No newline at end of file diff --git a/j2k/tests/testData/ast/switch/emptySwitch.kt b/j2k/tests/testData/ast/switch/emptySwitch.kt index 2dca28060d9..c6a174a6a0c 100644 --- a/j2k/tests/testData/ast/switch/emptySwitch.kt +++ b/j2k/tests/testData/ast/switch/emptySwitch.kt @@ -11,4 +11,4 @@ public class NonDefault { } } } -fun main(args: Array) = NonDefault.main(args as Array?) \ No newline at end of file +fun main(args: Array) = NonDefault.main(args) \ No newline at end of file diff --git a/j2k/tests/testData/ast/switch/fallDown.kt b/j2k/tests/testData/ast/switch/fallDown.kt index 90e6a0e3f6b..ca70bca2f2a 100644 --- a/j2k/tests/testData/ast/switch/fallDown.kt +++ b/j2k/tests/testData/ast/switch/fallDown.kt @@ -13,4 +13,4 @@ public class SwitchDemo { } } } -fun main(args: Array) = SwitchDemo.main(args as Array?) \ No newline at end of file +fun main(args: Array) = SwitchDemo.main(args) \ No newline at end of file diff --git a/j2k/tests/testData/ast/switch/kt-539.kt b/j2k/tests/testData/ast/switch/kt-539.kt index e67c0f7e5be..6c29952d18b 100644 --- a/j2k/tests/testData/ast/switch/kt-539.kt +++ b/j2k/tests/testData/ast/switch/kt-539.kt @@ -25,4 +25,4 @@ public class SwitchDemo { } } } -fun main(args: Array) = SwitchDemo.main(args as Array?) \ No newline at end of file +fun main(args: Array) = SwitchDemo.main(args) \ No newline at end of file diff --git a/j2k/tests/testData/ast/switch/nondefault.kt b/j2k/tests/testData/ast/switch/nondefault.kt index 874defa3f72..80ac26c286f 100644 --- a/j2k/tests/testData/ast/switch/nondefault.kt +++ b/j2k/tests/testData/ast/switch/nondefault.kt @@ -13,4 +13,4 @@ public class NonDefault { } } } -fun main(args: Array) = NonDefault.main(args as Array?) \ No newline at end of file +fun main(args: Array) = NonDefault.main(args) \ No newline at end of file