mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-31 08:31:31 +00:00
KT-13628 New line is not preserved when converting java to Kotlin
#KT-13628 Fixed
This commit is contained in:
@@ -132,7 +132,8 @@ class AnnotationConverter(private val converter: Converter) {
|
||||
val name = it.name
|
||||
null to converter.deferredElement<Expression> {
|
||||
QualifiedExpression(Identifier.withNoPrototype("AnnotationTarget", isNullable = false),
|
||||
Identifier.withNoPrototype(name, isNullable = false))
|
||||
Identifier.withNoPrototype(name, isNullable = false),
|
||||
null)
|
||||
}
|
||||
}
|
||||
return Identifier.withNoPrototype("Target") to deferredExpressionList
|
||||
|
||||
@@ -359,7 +359,7 @@ class Converter private constructor(
|
||||
}
|
||||
else if (propertyInfo.modifiers.contains(Modifier.OVERRIDE) && !(propertyInfo.superInfo?.isAbstract() ?: false)) {
|
||||
val superExpression = SuperExpression(Identifier.Empty).assignNoPrototype()
|
||||
val superAccess = QualifiedExpression(superExpression, propertyInfo.identifier).assignNoPrototype()
|
||||
val superAccess = QualifiedExpression(superExpression, propertyInfo.identifier, null).assignNoPrototype()
|
||||
val returnStatement = ReturnStatement(superAccess).assignNoPrototype()
|
||||
val body = Block.of(returnStatement).assignNoPrototype()
|
||||
val parameterList = ParameterList.withNoPrototype(emptyList())
|
||||
@@ -396,7 +396,7 @@ class Converter private constructor(
|
||||
}
|
||||
else if (propertyInfo.modifiers.contains(Modifier.OVERRIDE) && !(propertyInfo.superInfo?.isAbstract() ?: false)) {
|
||||
val superExpression = SuperExpression(Identifier.Empty).assignNoPrototype()
|
||||
val superAccess = QualifiedExpression(superExpression, propertyInfo.identifier).assignNoPrototype()
|
||||
val superAccess = QualifiedExpression(superExpression, propertyInfo.identifier, null).assignNoPrototype()
|
||||
val valueIdentifier = Identifier.withNoPrototype("value", isNullable = false)
|
||||
val assignment = AssignmentExpression(superAccess, valueIdentifier, Operator.EQ).assignNoPrototype()
|
||||
val body = Block.of(assignment).assignNoPrototype()
|
||||
|
||||
@@ -242,7 +242,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
|
||||
}
|
||||
else {
|
||||
val type = converter.convertTypeElement(operand, Nullability.NotNull)
|
||||
result = QualifiedExpression(ClassLiteralExpression(type).assignNoPrototype(), Identifier.withNoPrototype("java"))
|
||||
result = QualifiedExpression(ClassLiteralExpression(type).assignNoPrototype(), Identifier.withNoPrototype("java"), null)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -253,7 +253,8 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
|
||||
else
|
||||
wrapperTypeName.shortName().asString()
|
||||
result = QualifiedExpression(Identifier(classNameToUse, false).assignPrototype(operand),
|
||||
Identifier.withNoPrototype("TYPE", isNullable = false))
|
||||
Identifier.withNoPrototype("TYPE", isNullable = false),
|
||||
null)
|
||||
}
|
||||
|
||||
override fun visitConditionalExpression(expression: PsiConditionalExpression) {
|
||||
@@ -322,6 +323,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
|
||||
override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {
|
||||
val methodExpr = expression.methodExpression
|
||||
val arguments = expression.argumentList.expressions
|
||||
val qualifier = methodExpr.qualifierExpression
|
||||
val target = methodExpr.resolve()
|
||||
val isNullable = if (target is PsiMethod) typeConverter.methodNullability(target).isNullable(codeConverter.settings) else false
|
||||
val typeArguments = convertTypeArguments(expression)
|
||||
@@ -340,12 +342,15 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
|
||||
val isExtension = property.isExtensionDeclaration()
|
||||
val propertyAccess = if (isTopLevel) {
|
||||
if (isExtension)
|
||||
QualifiedExpression(codeConverter.convertExpression(arguments.firstOrNull(), true), propertyName).assignNoPrototype()
|
||||
QualifiedExpression(codeConverter.convertExpression(arguments.firstOrNull(), true), propertyName, null).assignNoPrototype()
|
||||
else
|
||||
propertyName
|
||||
}
|
||||
else if (qualifier != null) {
|
||||
QualifiedExpression(codeConverter.convertExpression(qualifier), propertyName, methodExpr.dot()).assignNoPrototype()
|
||||
}
|
||||
else {
|
||||
QualifiedExpression(codeConverter.convertExpression(methodExpr.qualifierExpression), propertyName).assignNoPrototype()
|
||||
propertyName
|
||||
}
|
||||
|
||||
when(if (isExtension) parameterCount - 1 else parameterCount) {
|
||||
@@ -408,7 +413,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
|
||||
if (target is PsiMethod) {
|
||||
val specialMethod = SpecialMethod.match(target, arguments.size, converter.services)
|
||||
if (specialMethod != null) {
|
||||
val converted = specialMethod.convertCall(methodExpr.qualifierExpression, arguments, typeArguments, codeConverter)
|
||||
val converted = specialMethod.convertCall(qualifier, arguments, typeArguments, codeConverter)
|
||||
if (converted != null) {
|
||||
result = converted
|
||||
return
|
||||
@@ -542,7 +547,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
|
||||
|
||||
expression.getContainingClass()?.getParentOfType<PsiVariable>(false)?.let {
|
||||
if (it == expression.qualifierExpression?.reference?.resolve()) {
|
||||
result = QualifiedExpression(ThisExpression(Identifier.Empty).assignNoPrototype(), identifier)
|
||||
result = QualifiedExpression(ThisExpression(Identifier.Empty).assignNoPrototype(), identifier, null)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -583,7 +588,10 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
|
||||
}
|
||||
}
|
||||
|
||||
result = if (qualifier != null) QualifiedExpression(codeConverter.convertExpression(qualifier), identifier) else identifier
|
||||
result = if (qualifier != null)
|
||||
QualifiedExpression(codeConverter.convertExpression(qualifier), identifier, expression.dot())
|
||||
else
|
||||
identifier
|
||||
}
|
||||
|
||||
private fun isNullable(target: PsiVariable): Boolean {
|
||||
|
||||
@@ -240,7 +240,7 @@ class ForConverter(
|
||||
val collectionType = PsiElementFactory.SERVICE.getInstance(project).createTypeByFQClassName(CommonClassNames.JAVA_UTIL_COLLECTION)
|
||||
val qualifierType = qualifier.type
|
||||
if (qualifierType != null && collectionType.isAssignableFrom(qualifierType)) {
|
||||
indices = QualifiedExpression(codeConverter.convertExpression(qualifier), Identifier.withNoPrototype("indices", isNullable = false))
|
||||
indices = QualifiedExpression(codeConverter.convertExpression(qualifier), Identifier.withNoPrototype("indices", isNullable = false), null)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -250,7 +250,7 @@ class ForConverter(
|
||||
&& collectionSize.referenceName == "length") {
|
||||
val qualifier = collectionSize.qualifierExpression
|
||||
if (qualifier is PsiReferenceExpression && qualifier.type is PsiArrayType) {
|
||||
indices = QualifiedExpression(codeConverter.convertExpression(qualifier), Identifier.withNoPrototype("indices", isNullable = false))
|
||||
indices = QualifiedExpression(codeConverter.convertExpression(qualifier), Identifier.withNoPrototype("indices", isNullable = false), null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -197,7 +197,10 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
|
||||
OBJECT_GET_CLASS(JAVA_LANG_OBJECT, "getClass", 0) {
|
||||
override fun convertCall(qualifier: PsiExpression?, arguments: Array<PsiExpression>, typeArgumentsConverted: List<Type>, codeConverter: CodeConverter): Expression {
|
||||
val identifier = Identifier.withNoPrototype("javaClass", isNullable = false)
|
||||
return if (qualifier != null) QualifiedExpression(codeConverter.convertExpression(qualifier), identifier) else identifier
|
||||
return if (qualifier != null)
|
||||
QualifiedExpression(codeConverter.convertExpression(qualifier), identifier, null)
|
||||
else
|
||||
identifier
|
||||
}
|
||||
},
|
||||
|
||||
@@ -436,7 +439,10 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String
|
||||
|
||||
protected fun convertMethodCallToPropertyUse(codeConverter: CodeConverter, qualifier: PsiExpression?, propertyName: String = methodName): Expression {
|
||||
val identifier = Identifier.withNoPrototype(propertyName, isNullable = false)
|
||||
return if (qualifier != null) QualifiedExpression(codeConverter.convertExpression(qualifier), identifier) else identifier
|
||||
return if (qualifier != null)
|
||||
QualifiedExpression(codeConverter.convertExpression(qualifier), identifier, null)
|
||||
else
|
||||
identifier
|
||||
}
|
||||
|
||||
protected fun Array<PsiExpression>.notNull() = map { it to Nullability.NotNull }
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.psi.util.PsiMethodUtil
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.j2k.ast.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.allChildren
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
|
||||
fun quoteKeywords(packageName: String): String = packageName.split('.').map { Identifier.toKotlin(it) }.joinToString(".")
|
||||
@@ -110,6 +111,8 @@ fun PsiModifierListOwner.accessModifier(): String = when {
|
||||
|
||||
fun PsiMethod.isMainMethod(): Boolean = PsiMethodUtil.isMainMethod(this)
|
||||
|
||||
fun PsiReferenceExpression.dot(): PsiElement? = allChildren.firstOrNull { it.node.elementType == JavaTokenType.DOT }
|
||||
|
||||
fun PsiMember.isImported(file: PsiJavaFile): Boolean {
|
||||
if (this is PsiClass) {
|
||||
val fqName = qualifiedName
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.j2k.ast
|
||||
|
||||
import com.intellij.psi.JavaTokenType
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import org.jetbrains.kotlin.j2k.CodeBuilder
|
||||
import org.jetbrains.kotlin.j2k.append
|
||||
@@ -111,17 +112,26 @@ class SuperExpression(val identifier: Identifier) : Expression() {
|
||||
}
|
||||
}
|
||||
|
||||
class QualifiedExpression(val qualifier: Expression, val identifier: Expression) : Expression() {
|
||||
class QualifiedExpression(val qualifier: Expression, val identifier: Expression, dotPrototype: PsiElement?) : Expression() {
|
||||
private val dot = Dot().assignPrototype(dotPrototype, CommentsAndSpacesInheritance.LINE_BREAKS)
|
||||
|
||||
override val isNullable: Boolean
|
||||
get() = identifier.isNullable
|
||||
|
||||
override fun generateCode(builder: CodeBuilder) {
|
||||
if (!qualifier.isEmpty) {
|
||||
builder.appendOperand(this, qualifier).append(if (qualifier.isNullable) "!!." else ".")
|
||||
builder.appendOperand(this, qualifier).append(if (qualifier.isNullable) "!!" else "")
|
||||
builder.append(dot)
|
||||
}
|
||||
|
||||
builder.append(identifier)
|
||||
}
|
||||
|
||||
private class Dot : Element() {
|
||||
override fun generateCode(builder: CodeBuilder) {
|
||||
builder.append(".")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PolyadicExpression(val expressions: List<Expression>, val operators: List<Operator>) : Expression() {
|
||||
|
||||
@@ -54,7 +54,7 @@ class MethodCallExpression(
|
||||
isNullable: Boolean
|
||||
): MethodCallExpression {
|
||||
val identifier = Identifier.withNoPrototype(methodName, isNullable = false)
|
||||
return MethodCallExpression(if (receiver != null) QualifiedExpression(receiver, identifier).assignNoPrototype() else identifier,
|
||||
return MethodCallExpression(if (receiver != null) QualifiedExpression(receiver, identifier, null).assignNoPrototype() else identifier,
|
||||
argumentList,
|
||||
typeArguments,
|
||||
isNullable)
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.j2k.AccessorKind
|
||||
import org.jetbrains.kotlin.j2k.CodeConverter
|
||||
import org.jetbrains.kotlin.j2k.ast.*
|
||||
import org.jetbrains.kotlin.j2k.dot
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
|
||||
@@ -34,7 +35,11 @@ class AccessorToPropertyProcessing(val accessorMethod: PsiMethod, val accessorKi
|
||||
val arguments = methodCall.argumentList.expressions
|
||||
|
||||
val propertyName = Identifier.withNoPrototype(propertyName, isNullable)
|
||||
val propertyAccess = QualifiedExpression(codeConverter.convertExpression(methodExpr.qualifierExpression), propertyName).assignNoPrototype()
|
||||
val qualifier = methodExpr.qualifierExpression
|
||||
val propertyAccess = if (qualifier != null)
|
||||
QualifiedExpression(codeConverter.convertExpression(qualifier), propertyName, methodExpr.dot()).assignNoPrototype()
|
||||
else
|
||||
propertyName
|
||||
|
||||
if (accessorKind == AccessorKind.GETTER) {
|
||||
if (arguments.size != 0) return null // incorrect call
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.util.IncorrectOperationException
|
||||
import org.jetbrains.kotlin.j2k.AccessorKind
|
||||
import org.jetbrains.kotlin.j2k.CodeConverter
|
||||
import org.jetbrains.kotlin.j2k.ast.*
|
||||
import org.jetbrains.kotlin.j2k.dot
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
|
||||
class FieldToPropertyProcessing(
|
||||
@@ -60,7 +61,7 @@ class FieldToPropertyProcessing(
|
||||
|
||||
val qualifier = expression.qualifierExpression
|
||||
if (qualifier != null && !useFieldReference) {
|
||||
return QualifiedExpression(codeConverter.convertExpression(qualifier), identifier)
|
||||
return QualifiedExpression(codeConverter.convertExpression(qualifier), identifier, expression.dot())
|
||||
}
|
||||
else {
|
||||
// check if field name is shadowed
|
||||
@@ -74,7 +75,7 @@ class FieldToPropertyProcessing(
|
||||
return if (refExpr.resolve() == null)
|
||||
identifier
|
||||
else
|
||||
QualifiedExpression(ThisExpression(Identifier.Empty).assignNoPrototype(), identifier) //TODO: this is not correct in case of nested/anonymous classes
|
||||
QualifiedExpression(ThisExpression(Identifier.Empty).assignNoPrototype(), identifier, null) //TODO: this is not correct in case of nested/anonymous classes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,11 @@ object Test {
|
||||
@JvmStatic fun main(args: Array<String>) {
|
||||
println()// Comment
|
||||
|
||||
Test.foo()// Comment1
|
||||
.indexOf("s")// Comment2
|
||||
Test
|
||||
// Comment1
|
||||
.foo()
|
||||
// Comment2
|
||||
.indexOf("s")
|
||||
}
|
||||
|
||||
fun foo(): String {
|
||||
|
||||
@@ -35,7 +35,10 @@ internal class CustomerBuilder {
|
||||
|
||||
object User {
|
||||
fun main() {
|
||||
val customer = CustomerBuilder().WithFirstName("Homer").WithLastName("Simpson").Build()
|
||||
val customer = CustomerBuilder()
|
||||
.WithFirstName("Homer")
|
||||
.WithLastName("Simpson")
|
||||
.Build()
|
||||
println(customer.firstName)
|
||||
println(customer.lastName)
|
||||
}
|
||||
|
||||
8
j2k/testData/fileOrElement/formatting/chainedCall.java
vendored
Normal file
8
j2k/testData/fileOrElement/formatting/chainedCall.java
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
public class C {
|
||||
void foo() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(1)
|
||||
.append(2).append(3)
|
||||
.append(4);
|
||||
}
|
||||
}
|
||||
8
j2k/testData/fileOrElement/formatting/chainedCall.kt
vendored
Normal file
8
j2k/testData/fileOrElement/formatting/chainedCall.kt
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
class C {
|
||||
internal fun foo() {
|
||||
val builder = StringBuilder()
|
||||
builder.append(1)
|
||||
.append(2).append(3)
|
||||
.append(4)
|
||||
}
|
||||
}
|
||||
@@ -2317,6 +2317,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/formatting"), Pattern.compile("^(.+)\\.java$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("chainedCall.java")
|
||||
public void testChainedCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/formatting/chainedCall.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lineBreaksBetweenArguments.java")
|
||||
public void testLineBreaksBetweenArguments() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/formatting/lineBreaksBetweenArguments.java");
|
||||
|
||||
@@ -2317,6 +2317,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/formatting"), Pattern.compile("^(.+)\\.java$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("chainedCall.java")
|
||||
public void testChainedCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/formatting/chainedCall.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lineBreaksBetweenArguments.java")
|
||||
public void testLineBreaksBetweenArguments() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/formatting/lineBreaksBetweenArguments.java");
|
||||
|
||||
Reference in New Issue
Block a user