Fixed KT-5434 J2K: incorrect conversion of main method

#KT-5434 Fixed
This commit is contained in:
Valentin Kipyatkov
2014-07-08 21:34:46 +04:00
parent 28e003e79f
commit 2ebaab867d
14 changed files with 83 additions and 57 deletions
@@ -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<Pair<String, PsiMethod>>()
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<String>) = {0}.main(args as Array<String?>?)", className)
if (classNamesWithMains.isNotEmpty()) {
var className = classNamesWithMains.first().first
return "fun main(args : Array<String>) = $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>): 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")
}
+20 -2
View File
@@ -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<PsiElement, Nullability>()
@@ -59,8 +62,17 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver
public fun convertTypes(types: Array<PsiType>): List<Type>
= 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())
@@ -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");
@@ -0,0 +1,5 @@
//file
public class A {
public static void main(String[] args) {
}
}
+7
View File
@@ -0,0 +1,7 @@
public class A {
class object {
public fun main(args: Array<String>) {
}
}
}
fun main(args: Array<String>) = A.main(args)
@@ -0,0 +1,6 @@
// !forceNotNullTypes: false
//file
public class A {
public static void main(String[] args) {
}
}
@@ -0,0 +1,8 @@
// !forceNotNullTypes: false
public class A {
class object {
public fun main(args: Array<String>) {
}
}
}
fun main(args: Array<String>) = A.main(args)
+1 -1
View File
@@ -31,4 +31,4 @@ public class User {
}
}
}
fun main(args: Array<String>) = User.main(args as Array<String?>?)
fun main(args: Array<String>) = User.main(args)
+1 -1
View File
@@ -7,4 +7,4 @@ class Program {
}
}
}
fun main(args: Array<String>) = Program.main(args as Array<String?>?)
fun main(args: Array<String>) = Program.main(args)
@@ -83,4 +83,4 @@ public class SwitchDemo {
}
}
}
fun main(args: Array<String>) = SwitchDemo.main(args as Array<String?>?)
fun main(args: Array<String>) = SwitchDemo.main(args)
+1 -1
View File
@@ -11,4 +11,4 @@ public class NonDefault {
}
}
}
fun main(args: Array<String>) = NonDefault.main(args as Array<String?>?)
fun main(args: Array<String>) = NonDefault.main(args)
+1 -1
View File
@@ -13,4 +13,4 @@ public class SwitchDemo {
}
}
}
fun main(args: Array<String>) = SwitchDemo.main(args as Array<String?>?)
fun main(args: Array<String>) = SwitchDemo.main(args)
+1 -1
View File
@@ -25,4 +25,4 @@ public class SwitchDemo {
}
}
}
fun main(args: Array<String>) = SwitchDemo.main(args as Array<String?>?)
fun main(args: Array<String>) = SwitchDemo.main(args)
+1 -1
View File
@@ -13,4 +13,4 @@ public class NonDefault {
}
}
}
fun main(args: Array<String>) = NonDefault.main(args as Array<String?>?)
fun main(args: Array<String>) = NonDefault.main(args)