Fixed KT-5434 J2K: incorrect conversion of main method
#KT-5434 Fixed
This commit is contained in:
@@ -16,80 +16,52 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.j2k
|
package org.jetbrains.jet.j2k
|
||||||
|
|
||||||
import java.text.MessageFormat
|
|
||||||
import com.intellij.psi.PsiMethod
|
import com.intellij.psi.PsiMethod
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
import com.intellij.psi.PsiJavaFile
|
import com.intellij.psi.PsiJavaFile
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import com.intellij.psi.PsiFile
|
|
||||||
import com.intellij.psi.PsiAnonymousClass
|
import com.intellij.psi.PsiAnonymousClass
|
||||||
import com.intellij.psi.PsiModifier
|
import com.intellij.psi.PsiModifier
|
||||||
import com.intellij.psi.PsiType
|
import com.intellij.psi.PsiType
|
||||||
import com.intellij.psi.PsiArrayType
|
import com.intellij.psi.PsiArrayType
|
||||||
|
|
||||||
fun createMainFunction(file: PsiFile): String {
|
fun createMainFunction(file: PsiJavaFile): String {
|
||||||
val classNamesWithMains = ArrayList<Pair<String, PsiMethod>>()
|
val classNamesWithMains = ArrayList<Pair<String, PsiMethod>>()
|
||||||
for (c in (file as PsiJavaFile).getClasses()) {
|
for (c in file.getClasses()) {
|
||||||
val main = findMainMethod(c)
|
val main = findMainMethod(c)
|
||||||
val name = c.getName()
|
val name = c.getName()
|
||||||
if (name != null && main != null) {
|
if (name != null && main != null) {
|
||||||
classNamesWithMains.add(Pair(name, main))
|
classNamesWithMains.add(name to main)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classNamesWithMains.size() > 0) {
|
if (classNamesWithMains.isNotEmpty()) {
|
||||||
var className = classNamesWithMains[0].first
|
var className = classNamesWithMains.first().first
|
||||||
return MessageFormat.format("fun main(args : Array<String>) = {0}.main(args as Array<String?>?)", className)
|
return "fun main(args : Array<String>) = $className.main(args)"
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findMainMethod(aClass: PsiClass): PsiMethod? {
|
private fun findMainMethod(aClass: PsiClass): PsiMethod?
|
||||||
if (isMainClass(aClass)) {
|
= if (isMainClass(aClass)) aClass.findMethodsByName("main", false).firstOrNull { it.isMainMethod() } else null
|
||||||
return findMainMethod(aClass.findMethodsByName("main", false))
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isMainClass(psiClass: PsiClass): Boolean {
|
private fun isMainClass(psiClass: PsiClass): Boolean
|
||||||
if (psiClass is PsiAnonymousClass)
|
= psiClass !is PsiAnonymousClass &&
|
||||||
return false
|
!psiClass.isInterface() &&
|
||||||
|
(psiClass.getContainingClass() == null || psiClass.hasModifierProperty(PsiModifier.STATIC))
|
||||||
|
|
||||||
if (psiClass.isInterface())
|
fun PsiMethod.isMainMethod(): Boolean {
|
||||||
return false
|
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
|
||||||
|
|
||||||
}
|
val `type` = parameters.single().getType()
|
||||||
|
if (`type` !is PsiArrayType) 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 componentType = `type`.getComponentType()
|
val componentType = `type`.getComponentType()
|
||||||
return componentType.equalsToText("java.lang.String")
|
return componentType.equalsToText("java.lang.String")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.assignNoPrototype
|
||||||
import org.jetbrains.jet.j2k.ast.ErrorType
|
import org.jetbrains.jet.j2k.ast.ErrorType
|
||||||
import com.intellij.codeInsight.NullableNotNullManager
|
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) {
|
class TypeConverter(val settings: ConverterSettings, val conversionScope: ConversionScope) {
|
||||||
private val nullabilityCache = HashMap<PsiElement, Nullability>()
|
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>
|
public fun convertTypes(types: Array<PsiType>): List<Type>
|
||||||
= types.map { convertType(it) }
|
= types.map { convertType(it) }
|
||||||
|
|
||||||
public fun convertVariableType(variable: PsiVariable): Type
|
public fun convertVariableType(variable: PsiVariable): Type {
|
||||||
= convertType(variable.getType(), variableNullability(variable)).assignPrototype(variable.getTypeElement())
|
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 {
|
public fun variableNullability(variable: PsiVariable): Nullability {
|
||||||
val cached = nullabilityCache[variable]
|
val cached = nullabilityCache[variable]
|
||||||
@@ -108,6 +120,10 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver
|
|||||||
return Nullability.Nullable
|
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 (!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,6 +174,8 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver
|
|||||||
return nullability
|
return nullability
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun PsiVariable.isMainMethodParameter() = this is PsiParameter && (getDeclarationScope() as? PsiMethod)?.isMainMethod() ?: false
|
||||||
|
|
||||||
public fun convertMethodReturnType(method: PsiMethod): Type
|
public fun convertMethodReturnType(method: PsiMethod): Type
|
||||||
= convertType(method.getReturnType(), methodNullability(method)).assignPrototype(method.getReturnTypeElement())
|
= 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");
|
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")
|
@TestMetadata("methodClassType.java")
|
||||||
public void testMethodClassType() throws Exception {
|
public void testMethodClassType() throws Exception {
|
||||||
doTest("j2k/tests/testData/ast/function/methodClassType.java");
|
doTest("j2k/tests/testData/ast/function/methodClassType.java");
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//file
|
||||||
|
public class A {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
@@ -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)
|
||||||
@@ -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)
|
||||||
@@ -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)
|
||||||
@@ -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)
|
||||||
@@ -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)
|
||||||
@@ -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)
|
||||||
Reference in New Issue
Block a user