From 38edb58e60270fce863f131016ac7f95627ec095 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 19 Aug 2016 22:13:58 +0300 Subject: [PATCH] Preserve formatting of parenthesis in calls too --- .../SeveralMethodsSample.expected.kt | 3 +- .../org/jetbrains/kotlin/j2k/CodeConverter.kt | 16 ++- j2k/src/org/jetbrains/kotlin/j2k/Converter.kt | 7 +- .../kotlin/j2k/ExpressionConverter.kt | 38 ++++-- .../org/jetbrains/kotlin/j2k/ForConverter.kt | 5 +- .../org/jetbrains/kotlin/j2k/SpecialMethod.kt | 123 ++++++++++-------- .../kotlin/j2k/StatementConverter.kt | 8 +- j2k/src/org/jetbrains/kotlin/j2k/Utils.kt | 4 +- .../{ExpressionList.kt => ArgumentList.kt} | 17 ++- .../jetbrains/kotlin/j2k/ast/EnumConstant.kt | 10 +- .../jetbrains/kotlin/j2k/ast/Expressions.kt | 2 +- .../kotlin/j2k/ast/MethodCallExpression.kt | 40 +++--- .../kotlin/j2k/ast/NewClassExpression.kt | 5 +- .../lineBreaksBetweenArguments.java | 3 +- .../formatting/lineBreaksBetweenArguments.kt | 3 +- 15 files changed, 173 insertions(+), 111 deletions(-) rename j2k/src/org/jetbrains/kotlin/j2k/ast/{ExpressionList.kt => ArgumentList.kt} (61%) diff --git a/idea/testData/copyPaste/conversion/SeveralMethodsSample.expected.kt b/idea/testData/copyPaste/conversion/SeveralMethodsSample.expected.kt index 125711996f1..fc77c461841 100644 --- a/idea/testData/copyPaste/conversion/SeveralMethodsSample.expected.kt +++ b/idea/testData/copyPaste/conversion/SeveralMethodsSample.expected.kt @@ -14,7 +14,8 @@ class A { return JetBundle.message( "x.in.y", DescriptorRenderer.COMPACT.render(declarationDescriptor), - IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(containingDescriptor)) + IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(containingDescriptor) + ) } } } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/CodeConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/CodeConverter.kt index 5cc96cb28d7..0422aaa20fd 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/CodeConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/CodeConverter.kt @@ -63,6 +63,16 @@ class CodeConverter( fun convertExpressions(expressions: List): List = expressions.map { convertExpression(it) } + fun convertArgumentList(list: PsiExpressionList): ArgumentList { + val lPar = list.node.findChildByType(JavaTokenType.LPARENTH)?.psi + val rPar = list.node.findChildByType(JavaTokenType.RPARENTH)?.psi + return ArgumentList( + convertExpressions(list.expressions), + LPar().assignPrototype(lPar, CommentsAndSpacesInheritance.LINE_BREAKS), + RPar().assignPrototype(rPar, CommentsAndSpacesInheritance.LINE_BREAKS) + ).assignPrototype(list) + } + fun convertExpression(expression: PsiExpression?, shouldParenthesize: Boolean = false): Expression { if (expression == null) return Expression.Empty @@ -127,7 +137,7 @@ class CodeConverter( convertedExpression = LiteralExpression(text) } else if (expectedTypeStr == "char") { - convertedExpression = MethodCallExpression.build(convertedExpression, "toChar", emptyList(), emptyList(), false) + convertedExpression = MethodCallExpression.buildNonNull(convertedExpression, "toChar") } } else if (expression is PsiPrefixExpression && expression.isLiteralWithSign()) { @@ -137,7 +147,7 @@ class CodeConverter( else { val conversion = PRIMITIVE_TYPE_CONVERSIONS[expectedTypeStr] if (conversion != null) { - convertedExpression = MethodCallExpression.buildNotNull(convertedExpression, conversion) + convertedExpression = MethodCallExpression.buildNonNull(convertedExpression, conversion) } } } @@ -146,7 +156,7 @@ class CodeConverter( } fun convertedExpressionType(expression: PsiExpression, expectedType: PsiType): Type { - var convertedExpression = convertExpression(expression) + val convertedExpression = convertExpression(expression) val actualType = expression.type ?: return ErrorType() var resultType = typeConverter.convertType(actualType, if (convertedExpression.isNullable) Nullability.Nullable else Nullability.NotNull) diff --git a/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt b/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt index 3da3e44fb46..530cad6904d 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt @@ -317,8 +317,11 @@ class Converter private constructor( if (field is PsiEnumConstant) { assert(getMethod == null && setMethod == null) val argumentList = field.argumentList - val params = deferredElement { codeConverter -> - ExpressionList(codeConverter.convertExpressions(argumentList?.expressions ?: arrayOf())).assignPrototype(argumentList) + val params = if (argumentList != null && argumentList.expressions.isNotEmpty()) { + deferredElement { codeConverter -> codeConverter.convertArgumentList(argumentList) } + } + else { + null } val body = field.initializingClass?.let { convertAnonymousClassBody(it) } return EnumConstant(name, annotations, modifiers, params, body) diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt index 2d074ebd96e..5c58846f36e 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ExpressionConverter.kt @@ -118,8 +118,8 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { val expectedNullability = if (operationTokenType in NON_NULL_OPERAND_OPS) Nullability.NotNull else null val leftOperandExpectedType = getOperandExpectedType(left, right, operationTokenType) - var leftConverted = codeConverter.convertExpression(left, leftOperandExpectedType, expectedNullability) - var rightConverted = codeConverter.convertExpression( + val leftConverted = codeConverter.convertExpression(left, leftOperandExpectedType, expectedNullability) + val rightConverted = codeConverter.convertExpression( right, if (leftOperandExpectedType == null) getOperandExpectedType(right, left, operationTokenType) @@ -129,7 +129,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { ) if (operationTokenType == JavaTokenType.GTGTGT) { - result = MethodCallExpression.buildNotNull(leftConverted, "ushr", listOf(rightConverted)) + result = MethodCallExpression.buildNonNull(leftConverted, "ushr", ArgumentList.withNoPrototype(rightConverted)) } else { var operator = Operator(operationTokenType) @@ -509,7 +509,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { val operand = codeConverter.convertExpression(expression.operand, expression.operand!!.type) val token = expression.operationTokenType if (token == JavaTokenType.TILDE) { - result = MethodCallExpression.buildNotNull(operand, "inv") + result = MethodCallExpression.buildNonNull(operand, "inv") } else if (token == JavaTokenType.EXCL && operand is BinaryExpression && operand.op.asString() == "==") { // happens when equals is converted to == result = BinaryExpression(operand.left, operand.right, Operator(JavaTokenType.NE).assignPrototype(expression.operand)) @@ -623,7 +623,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { val typeConversion = PRIMITIVE_TYPE_CONVERSIONS[typeText] val operandConverted = codeConverter.convertExpression(operand) if (operandType is PsiPrimitiveType && typeConversion != null) { - result = MethodCallExpression.buildNotNull(operandConverted, typeConversion) + result = MethodCallExpression.buildNonNull(operandConverted, typeConversion) } else { val nullability = if (operandConverted.isNullable && !expression.isQualifier()) @@ -659,8 +659,9 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { result = PolyadicExpression(args, operators).assignPrototype(expression) } - private fun convertArguments(expression: PsiCallExpression, isExtension: Boolean = false): List { - var arguments = expression.argumentList?.expressions?.toList() ?: listOf() + private fun convertArguments(expression: PsiCallExpression, isExtension: Boolean = false): ArgumentList { + val argumentList = expression.argumentList + var arguments = argumentList?.expressions?.toList() ?: listOf() if (isExtension && arguments.isNotEmpty()) { arguments = arguments.drop(1) } @@ -670,7 +671,7 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { val commentsAndSpacesInheritance = CommentsAndSpacesInheritance.LINE_BREAKS - return if (arguments.size == parameters.size) { + val convertedArguments = if (arguments.size == parameters.size) { arguments.mapIndexed { i, argument -> val expectedNullability = typeConverter.variableNullability(parameters[i]) val converted = codeConverter.convertExpression(argument, parameters[i].type, expectedNullability) @@ -685,6 +686,15 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { else { arguments.map { codeConverter.convertExpression(it).assignPrototype(it, commentsAndSpacesInheritance) } } + + val lPar = argumentList?.node?.findChildByType(JavaTokenType.LPARENTH)?.psi + val rPar = argumentList?.node?.findChildByType(JavaTokenType.RPARENTH)?.psi + + return ArgumentList( + convertedArguments, + LPar().assignPrototype(lPar, CommentsAndSpacesInheritance.LINE_BREAKS), + RPar().assignPrototype(rPar, CommentsAndSpacesInheritance.LINE_BREAKS) + ).assignPrototype(argumentList) } override fun visitLambdaExpression(expression: PsiLambdaExpression) { @@ -772,7 +782,8 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { val specialMethod = method?.let { SpecialMethod.match(it, callParams.size, converter.services) } val statement: Statement = if (expression.isConstructor) { - MethodCallExpression.build(null, convertMethodReferenceQualifier(qualifier), callParams.map { it.first }, emptyList(), false) + val argumentList = ArgumentList.withNoPrototype(callParams.map { it.first }) + MethodCallExpression.buildNonNull(null, convertMethodReferenceQualifier(qualifier), argumentList) } else if (specialMethod != null) { val factory = PsiElementFactory.SERVICE.getInstance(converter.project) @@ -800,7 +811,8 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { } else { val referenceName = expression.referenceName!! - MethodCallExpression.build(receiver?.first, referenceName, callParams.map { it.first }, emptyList(), false) + val argumentList = ArgumentList.withNoPrototype(callParams.map { it.first }) + MethodCallExpression.buildNonNull(receiver?.first, referenceName, argumentList) } statement.assignNoPrototype() @@ -822,12 +834,10 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter { } else { val convertedFunctionalType = converter.typeConverter.convertType(functionalType) - result = MethodCallExpression.build( + result = MethodCallExpression.buildNonNull( null, convertedFunctionalType.canonicalCode(), - listOf(lambdaExpression), - emptyList(), - false + ArgumentList.withNoPrototype(lambdaExpression) ) } } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ForConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/ForConverter.kt index 10291c8cdee..8bce87de44f 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ForConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ForConverter.kt @@ -138,7 +138,8 @@ class ForConverter( block.generateCode(builder) } else { - val call = MethodCallExpression.build(null, "run", listOf(LambdaExpression(null, block)), listOf(), false) + val argumentList = ArgumentList.withNoPrototype(LambdaExpression(null, block)) + val call = MethodCallExpression.buildNonNull(null, "run", argumentList) call.generateCode(builder) } } @@ -256,7 +257,7 @@ class ForConverter( if (indices == null) return null return if (reversed) - MethodCallExpression.build(indices.assignNoPrototype(), "reversed", listOf(), listOf(), false) + MethodCallExpression.buildNonNull(indices.assignNoPrototype(), "reversed") else indices } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/SpecialMethod.kt b/j2k/src/org/jetbrains/kotlin/j2k/SpecialMethod.kt index 805c6c907e7..c2c39c9ec5d 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/SpecialMethod.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/SpecialMethod.kt @@ -208,68 +208,80 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String COLLECTIONS_EMPTY_LIST(Collections::class.java.name, "emptyList", 0) { override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter) - = MethodCallExpression.build(null, "emptyList", listOf(), typeArgumentsConverted, false) + = MethodCallExpression.buildNonNull(null, "emptyList", ArgumentList.withNoPrototype(), typeArgumentsConverted) }, COLLECTIONS_EMPTY_SET(Collections::class.java.name, "emptySet", 0) { override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter) - = MethodCallExpression.build(null, "emptySet", listOf(), typeArgumentsConverted, false) + = MethodCallExpression.buildNonNull(null, "emptySet", ArgumentList.withNoPrototype(), typeArgumentsConverted) }, COLLECTIONS_EMPTY_MAP(Collections::class.java.name, "emptyMap", 0) { override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter) - = MethodCallExpression.build(null, "emptyMap", listOf(), typeArgumentsConverted, false) + = MethodCallExpression.buildNonNull(null, "emptyMap", ArgumentList.withNoPrototype(), typeArgumentsConverted) }, COLLECTIONS_SINGLETON_LIST(Collections::class.java.name, "singletonList", 1) { - override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter) - = MethodCallExpression.build(null, "listOf", listOf(codeConverter.convertExpression(arguments.single())), typeArgumentsConverted, false) + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): MethodCallExpression { + val argumentList = ArgumentList.withNoPrototype(codeConverter.convertExpression(arguments.single())) + return MethodCallExpression.buildNonNull(null, "listOf", argumentList, typeArgumentsConverted) + } }, COLLECTIONS_SINGLETON(Collections::class.java.name, "singleton", 1) { - override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter) - = MethodCallExpression.build(null, "setOf", listOf(codeConverter.convertExpression(arguments.single())), typeArgumentsConverted, false) + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): MethodCallExpression { + val argumentList = ArgumentList.withNoPrototype(codeConverter.convertExpression(arguments.single())) + return MethodCallExpression.buildNonNull(null, "setOf", argumentList, typeArgumentsConverted) + } }, STRING_TRIM(JAVA_LANG_STRING, "trim", 0) { override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): Expression? { val comparison = BinaryExpression(Identifier.withNoPrototype("it", isNullable = false), LiteralExpression("' '").assignNoPrototype(), Operator(JavaTokenType.LE).assignNoPrototype()).assignNoPrototype() - return MethodCallExpression.buildNotNull( - codeConverter.convertExpression(qualifier), "trim", - listOf(LambdaExpression(null, Block.of(comparison).assignNoPrototype())), emptyList()) + val argumentList = ArgumentList.withNoPrototype(LambdaExpression(null, Block.of(comparison).assignNoPrototype())) + return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "trim", argumentList) } }, STRING_REPLACE_ALL(JAVA_LANG_STRING, "replaceAll", 2) { - override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter) - = MethodCallExpression.build(codeConverter.convertExpression(qualifier), "replace", - listOf( - codeConverter.convertToRegex(arguments[0]), - codeConverter.convertExpression(arguments[1]) - ), emptyList(), false) + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): MethodCallExpression { + val argumentList = ArgumentList.withNoPrototype( + codeConverter.convertToRegex(arguments[0]), + codeConverter.convertExpression(arguments[1]) + ) + return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "replace", argumentList) + } }, STRING_REPLACE_FIRST(JAVA_LANG_STRING, "replaceFirst", 2) { - override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter) - = MethodCallExpression.build(codeConverter.convertExpression(qualifier), "replaceFirst", - listOf( - codeConverter.convertToRegex(arguments[0]), - codeConverter.convertExpression(arguments[1]) - ), emptyList(), false) + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): MethodCallExpression { + return MethodCallExpression.buildNonNull( + codeConverter.convertExpression(qualifier), "replaceFirst", + ArgumentList.withNoPrototype( + codeConverter.convertToRegex(arguments[0]), + codeConverter.convertExpression(arguments[1]) + ) + ) + } }, STRING_MATCHES(JAVA_LANG_STRING, "matches", 1) { - override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter) - = MethodCallExpression.build(codeConverter.convertExpression(qualifier), "matches", listOf(codeConverter.convertToRegex(arguments.single())), emptyList(), false) + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): MethodCallExpression { + val argumentList = ArgumentList.withNoPrototype(codeConverter.convertToRegex(arguments.single())) + return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "matches", argumentList) + } }, STRING_SPLIT(JAVA_LANG_STRING, "split", 1) { override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): Expression? { - val splitCall = MethodCallExpression.buildNotNull(codeConverter.convertExpression(qualifier), "split", listOf(codeConverter.convertToRegex(arguments.single())), emptyList()).assignNoPrototype() - val isEmptyCall = MethodCallExpression.buildNotNull(Identifier.withNoPrototype("it", isNullable = false), "isEmpty", emptyList(), emptyList()).assignNoPrototype() + val splitCall = MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "split", + ArgumentList.withNoPrototype(codeConverter.convertToRegex(arguments.single())) + ).assignNoPrototype() + val isEmptyCall = MethodCallExpression.buildNonNull(Identifier.withNoPrototype("it", isNullable = false), "isEmpty").assignNoPrototype() val isEmptyCallBlock = Block.of(isEmptyCall).assignNoPrototype() - val dropLastCall = MethodCallExpression.buildNotNull(splitCall, "dropLastWhile", listOf(LambdaExpression(null, isEmptyCallBlock).assignNoPrototype())).assignNoPrototype() - return MethodCallExpression.buildNotNull(dropLastCall, "toTypedArray", emptyList(), emptyList()) + val dropLastCall = MethodCallExpression.buildNonNull(splitCall, "dropLastWhile", + ArgumentList.withNoPrototype(LambdaExpression(null, isEmptyCallBlock).assignNoPrototype())).assignNoPrototype() + return MethodCallExpression.buildNonNull(dropLastCall, "toTypedArray") } }, @@ -281,7 +293,7 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String val limit = evaluator.computeConstantExpression(arguments[1], /* throwExceptionOnOverflow = */ false) as? Int val splitArguments = when { limit == null -> // not a constant - listOf(patternArgument, MethodCallExpression.buildNotNull(limitArgument, "coerceAtLeast", listOf(LiteralExpression("0").assignNoPrototype()), emptyList()).assignNoPrototype()) + listOf(patternArgument, MethodCallExpression.buildNonNull(limitArgument, "coerceAtLeast", ArgumentList.withNoPrototype(LiteralExpression("0").assignNoPrototype())).assignNoPrototype()) limit < 0 -> // negative, same behavior as split(regex) in kotlin listOf(patternArgument) limit == 0 -> // zero, same replacement as for split without limit @@ -290,8 +302,8 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String listOf(patternArgument, limitArgument) } - val splitCall = MethodCallExpression.buildNotNull(codeConverter.convertExpression(qualifier), "split", splitArguments, emptyList()).assignNoPrototype() - return MethodCallExpression.buildNotNull(splitCall, "toTypedArray", emptyList(), emptyList()) + val splitCall = MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "split", ArgumentList.withNoPrototype(splitArguments)).assignNoPrototype() + return MethodCallExpression.buildNonNull(splitCall, "toTypedArray") } }, @@ -299,8 +311,10 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String override fun matches(method: PsiMethod, superMethodsSearcher: SuperMethodsSearcher): Boolean = super.matches(method, superMethodsSearcher) && method.parameterList.parameters.last().type.canonicalText == "java.lang.Iterable" - override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): Expression? - = MethodCallExpression.buildNotNull(codeConverter.convertExpression(arguments[1]), "joinToString", codeConverter.convertExpressions(arguments.take(1)), emptyList()) + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): Expression? { + val argumentList = ArgumentList.withNoPrototype(codeConverter.convertExpressions(arguments.take(1))) + return MethodCallExpression.buildNonNull(codeConverter.convertExpression(arguments[1]), "joinToString", argumentList) + } }, STRING_JOIN_VARARG(JAVA_LANG_STRING, "join", null) { @@ -312,10 +326,10 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String return STRING_JOIN.convertCall(qualifier, arguments, typeArgumentsConverted, codeConverter) } else { - return MethodCallExpression.buildNotNull( - MethodCallExpression.buildNotNull(null, "arrayOf", codeConverter.convertExpressions(arguments.drop(1))).assignNoPrototype(), + return MethodCallExpression.buildNonNull( + MethodCallExpression.buildNonNull(null, "arrayOf", ArgumentList.withNoPrototype(codeConverter.convertExpressions(arguments.drop(1)))).assignNoPrototype(), "joinToString", - codeConverter.convertExpressions(arguments.take(1)) + ArgumentList.withNoPrototype(codeConverter.convertExpressions (arguments.take(1))) ) } } @@ -351,18 +365,20 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String val charsetArg = arguments.lastOrNull()?.check { it.type?.canonicalText == JAVA_LANG_STRING } val convertedArguments = codeConverter.convertExpressions(arguments).map { if (charsetArg != null && it.prototypes?.singleOrNull()?.element == charsetArg) - MethodCallExpression.buildNotNull(null, "charset", listOf(it)).assignNoPrototype() + MethodCallExpression.buildNonNull(null, "charset", ArgumentList.withNoPrototype(it)).assignNoPrototype() else it } - return MethodCallExpression.build(codeConverter.convertExpression(qualifier), "toByteArray", convertedArguments, emptyList(), false) + return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "toByteArray", ArgumentList.withNoPrototype(convertedArguments)) } }, STRING_GET_CHARS(JAVA_LANG_STRING, "getChars", 4) { - override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter) - // reorder parameters: srcBegin(0), srcEnd(1), dst(2), dstOffset(3) -> destination(2), destinationOffset(3), startIndex(0), endIndex(1) - = MethodCallExpression.buildNotNull(codeConverter.convertExpression(qualifier), "toCharArray", codeConverter.convertExpressions(arguments.slice(listOf(2, 3, 0, 1)))) + override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): MethodCallExpression { + // reorder parameters: srcBegin(0), srcEnd(1), dst(2), dstOffset(3) -> destination(2), destinationOffset(3), startIndex(0), endIndex(1) + val argumentList = ArgumentList.withNoPrototype(codeConverter.convertExpressions(arguments.slice(listOf(2, 3, 0, 1)))) + return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), "toCharArray", argumentList) + } }, STRING_VALUE_OF_CHAR_ARRAY(JAVA_LANG_STRING, "valueOf", null) { @@ -373,7 +389,7 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String } override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter) - = MethodCallExpression.build(null, "String", codeConverter.convertExpressions(arguments), emptyList(), false) + = MethodCallExpression.buildNonNull(null, "String", ArgumentList.withNoPrototype(codeConverter.convertExpressions (arguments))) }, STRING_COPY_VALUE_OF_CHAR_ARRAY(JAVA_LANG_STRING, "copyValueOf", null) { @@ -389,7 +405,7 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String STRING_VALUE_OF(JAVA_LANG_STRING, "valueOf", 1) { override fun convertCall(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter) - = MethodCallExpression.build(codeConverter.convertExpression(arguments.single(), true), "toString", emptyList(), emptyList(), false) + = MethodCallExpression.buildNonNull(codeConverter.convertExpression(arguments.single(), true), "toString") }, SYSTEM_OUT_PRINTLN(PrintStream::class.java.name, "println", null) { @@ -425,14 +441,16 @@ enum class SpecialMethod(val qualifiedClassName: String?, val methodName: String protected fun Array.notNull() = map { it to Nullability.NotNull } - protected fun convertWithChangedName(name: String, qualifier: PsiExpression?, arguments: List>, typeArgumentsConverted: List, codeConverter: CodeConverter) - = MethodCallExpression.buildNotNull(codeConverter.convertExpression(qualifier), name, arguments.map { codeConverter.convertExpression(it.first, null, it.second) }, typeArgumentsConverted) + protected fun convertWithChangedName(name: String, qualifier: PsiExpression?, arguments: List>, typeArgumentsConverted: List, codeConverter: CodeConverter): MethodCallExpression { + val argumentList = ArgumentList.withNoPrototype(arguments.map { codeConverter.convertExpression(it.first, null, it.second) }) + return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), name, argumentList, typeArgumentsConverted) + } protected fun convertMethodCallWithReceiverCast(qualifier: PsiExpression?, arguments: Array, typeArgumentsConverted: List, codeConverter: CodeConverter): MethodCallExpression? { val convertedArguments = arguments.map { codeConverter.convertExpression(it) } val qualifierWithCast = castQualifierToType(codeConverter, qualifier!!, qualifiedClassName!!) if (qualifierWithCast != null) { - return MethodCallExpression.build(qualifierWithCast, methodName, convertedArguments, typeArgumentsConverted, false) + return MethodCallExpression.buildNonNull(qualifierWithCast, methodName, ArgumentList.withNoPrototype(convertedArguments), typeArgumentsConverted) } return null } @@ -470,11 +488,12 @@ private fun convertSystemOutMethodCall( if (qqualifier.canonicalText != "java.lang.System") return null if (qualifier.referenceName != "out") return null if (typeArgumentsConverted.isNotEmpty()) return null - return MethodCallExpression.build(null, methodName, arguments.map { codeConverter.convertExpression(it) }, emptyList(), false) + val argumentList = ArgumentList.withNoPrototype(arguments.map { codeConverter.convertExpression(it) }) + return MethodCallExpression.buildNonNull(null, methodName, argumentList) } private fun CodeConverter.convertToRegex(expression: PsiExpression?): Expression - = MethodCallExpression.build(convertExpression(expression, true), "toRegex", emptyList(), emptyList(), false).assignNoPrototype() + = MethodCallExpression.buildNonNull(convertExpression(expression, true), "toRegex").assignNoPrototype() private fun addIgnoreCaseArgument( qualifier: PsiExpression?, @@ -486,8 +505,10 @@ private fun addIgnoreCaseArgument( ): Expression { val ignoreCaseExpression = ignoreCaseArgument?.let { codeConverter.convertExpression(it) } ?: LiteralExpression("true").assignNoPrototype() val ignoreCaseArgumentExpression = AssignmentExpression(Identifier.withNoPrototype("ignoreCase"), ignoreCaseExpression, Operator.EQ).assignNoPrototype() - return MethodCallExpression.build(codeConverter.convertExpression(qualifier), methodName, - arguments.map { codeConverter.convertExpression(it, null, Nullability.NotNull) } + ignoreCaseArgumentExpression, - typeArgumentsConverted, false) + val argumentList = ArgumentList.withNoPrototype(arguments.map { codeConverter.convertExpression(it, null, Nullability.NotNull) } + ignoreCaseArgumentExpression) + return MethodCallExpression.buildNonNull(codeConverter.convertExpression(qualifier), + methodName, + argumentList, + typeArgumentsConverted) } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/StatementConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/StatementConverter.kt index 019ccd0b84c..a9419007dda 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/StatementConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/StatementConverter.kt @@ -54,18 +54,18 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter { val descriptionExpr = statement.assertDescription val condition = codeConverter.convertExpression(statement.assertCondition) if (descriptionExpr == null) { - result = MethodCallExpression.buildNotNull(null, "assert", listOf(condition)) + result = MethodCallExpression.buildNonNull(null, "assert", ArgumentList.withNoPrototype(condition)) } else { val description = codeConverter.convertExpression(descriptionExpr) val lambda = LambdaExpression(null, Block.of(description).assignNoPrototype()) - result = MethodCallExpression.build(null, "assert", listOf(condition, lambda), listOf(), false) + result = MethodCallExpression.buildNonNull(null, "assert", ArgumentList.withNoPrototype(condition, lambda)) } } override fun visitBlockStatement(statement: PsiBlockStatement) { val block = codeConverter.convertBlock(statement.codeBlock) - result = MethodCallExpression.build(null, "run", listOf(LambdaExpression(null, block).assignNoPrototype()), listOf(), false) + result = MethodCallExpression.buildNonNull(null, "run", ArgumentList.withNoPrototype(LambdaExpression(null, block).assignNoPrototype())) } override fun visitBreakStatement(statement: PsiBreakStatement) { @@ -218,7 +218,7 @@ class DefaultStatementConverter : JavaElementVisitor(), StatementConverter { val parameter = LambdaParameter(Identifier.withNoPrototype(variable.name!!), null).assignNoPrototype() val parameterList = ParameterList(listOf(parameter), lPar = null, rPar = null).assignNoPrototype() val lambda = LambdaExpression(parameterList, block) - expression = MethodCallExpression.build(codeConverter.convertExpression(variable.initializer), "use", listOf(lambda), listOf(), false) + expression = MethodCallExpression.buildNonNull(codeConverter.convertExpression(variable.initializer), "use", ArgumentList.withNoPrototype(lambda)) expression.assignNoPrototype() block = Block.of(expression).assignNoPrototype() } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/Utils.kt b/j2k/src/org/jetbrains/kotlin/j2k/Utils.kt index 0979ab7dcd4..0fc959ed3a8 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/Utils.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/Utils.kt @@ -34,8 +34,8 @@ fun getDefaultInitializer(property: Property): Expression? { when (t.name.name) { "Boolean" -> LiteralExpression("false") "Char" -> LiteralExpression("' '") - "Double" -> MethodCallExpression.buildNotNull(LiteralExpression("0").assignNoPrototype(), OperatorConventions.DOUBLE.toString()) - "Float" -> MethodCallExpression.buildNotNull(LiteralExpression("0").assignNoPrototype(), OperatorConventions.FLOAT.toString()) + "Double" -> MethodCallExpression.buildNonNull(LiteralExpression("0").assignNoPrototype(), OperatorConventions.DOUBLE.toString()) + "Float" -> MethodCallExpression.buildNonNull(LiteralExpression("0").assignNoPrototype(), OperatorConventions.FLOAT.toString()) else -> LiteralExpression("0") } } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ast/ExpressionList.kt b/j2k/src/org/jetbrains/kotlin/j2k/ast/ArgumentList.kt similarity index 61% rename from j2k/src/org/jetbrains/kotlin/j2k/ast/ExpressionList.kt rename to j2k/src/org/jetbrains/kotlin/j2k/ast/ArgumentList.kt index d164f4f513e..b736917f003 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ast/ExpressionList.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ast/ArgumentList.kt @@ -19,11 +19,22 @@ package org.jetbrains.kotlin.j2k.ast import org.jetbrains.kotlin.j2k.CodeBuilder import org.jetbrains.kotlin.j2k.append -class ExpressionList(val expressions: List) : Expression() { +class ArgumentList( + val expressions: List, + val lPar: LPar, + val rPar: RPar +) : Expression() { override fun generateCode(builder: CodeBuilder) { + builder.append(lPar) builder.append(expressions, ", ") + builder.append(rPar) } - override val isEmpty: Boolean - get() = expressions.isEmpty() + companion object { + fun withNoPrototype(arguments: List): ArgumentList { + return ArgumentList(arguments, LPar().assignNoPrototype(), RPar().assignNoPrototype()).assignNoPrototype() + } + + fun withNoPrototype(vararg arguments: Expression): ArgumentList = withNoPrototype(arguments.asList()) + } } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ast/EnumConstant.kt b/j2k/src/org/jetbrains/kotlin/j2k/ast/EnumConstant.kt index e9b1c9f0c29..689984dfdcf 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ast/EnumConstant.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ast/EnumConstant.kt @@ -22,19 +22,19 @@ class EnumConstant( val identifier: Identifier, annotations: Annotations, modifiers: Modifiers, - val params: DeferredElement, + val params: DeferredElement?, val body: AnonymousClassBody? ) : Member(annotations, modifiers) { override fun generateCode(builder: CodeBuilder) { - builder append annotations append identifier + builder.append(annotations).append(identifier) - if (!params.isEmpty) { - builder append "(" append params append ")" + if (params != null) { + builder.append(params) } if (body != null) { - builder append body + builder.append(body) } } } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/kotlin/j2k/ast/Expressions.kt index e3acf6f0e2e..7599cae7238 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ast/Expressions.kt @@ -257,5 +257,5 @@ fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List" else "arrayOf" - return MethodCallExpression.buildNotNull(null, createArrayFunction, initializers) + return MethodCallExpression.buildNonNull(null, createArrayFunction, ArgumentList.withNoPrototype(initializers)) } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ast/MethodCallExpression.kt b/j2k/src/org/jetbrains/kotlin/j2k/ast/MethodCallExpression.kt index c1260bff4a8..96ad576b622 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ast/MethodCallExpression.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ast/MethodCallExpression.kt @@ -21,37 +21,41 @@ import org.jetbrains.kotlin.j2k.append class MethodCallExpression( val methodExpression: Expression, - val arguments: List, + val argumentList: ArgumentList, val typeArguments: List, override val isNullable: Boolean ) : Expression() { override fun generateCode(builder: CodeBuilder) { builder.appendOperand(this, methodExpression).append(typeArguments, ", ", "<", ">") - builder.append("(").append(arguments, ", ").append(")") + builder.append(argumentList) } companion object { - fun buildNotNull(receiver: Expression?, - methodName: String, - arguments: List = listOf(), - typeArguments: List = listOf()): MethodCallExpression - = build(receiver, methodName, arguments, typeArguments, false) + fun buildNonNull( + receiver: Expression?, + methodName: String, + argumentList: ArgumentList = ArgumentList.withNoPrototype(), + typeArguments: List = emptyList() + ): MethodCallExpression = build(receiver, methodName, argumentList, typeArguments, false) - fun buildNullable(receiver: Expression?, - methodName: String, - arguments: List = listOf(), - typeArguments: List = listOf()): MethodCallExpression - = build(receiver, methodName, arguments, typeArguments, true) + fun buildNullable( + receiver: Expression?, + methodName: String, + argumentList: ArgumentList = ArgumentList.withNoPrototype(), + typeArguments: List = emptyList() + ): MethodCallExpression = build(receiver, methodName, argumentList, typeArguments, true) - fun build(receiver: Expression?, - methodName: String, - arguments: List, - typeArguments: List, - isNullable: Boolean): MethodCallExpression { + fun build( + receiver: Expression?, + methodName: String, + argumentList: ArgumentList, + typeArguments: List, + isNullable: Boolean + ): MethodCallExpression { val identifier = Identifier.withNoPrototype(methodName, isNullable = false) return MethodCallExpression(if (receiver != null) QualifiedExpression(receiver, identifier).assignNoPrototype() else identifier, - arguments, + argumentList, typeArguments, isNullable) } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ast/NewClassExpression.kt b/j2k/src/org/jetbrains/kotlin/j2k/ast/NewClassExpression.kt index 0e94416241e..0e210433590 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ast/NewClassExpression.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ast/NewClassExpression.kt @@ -17,11 +17,10 @@ package org.jetbrains.kotlin.j2k.ast import org.jetbrains.kotlin.j2k.CodeBuilder -import org.jetbrains.kotlin.j2k.append class NewClassExpression( val name: ReferenceElement?, - val arguments: List, + val argumentList: ArgumentList, val qualifier: Expression = Expression.Empty, val anonymousClass: AnonymousClassBody? = null ) : Expression() { @@ -40,7 +39,7 @@ class NewClassExpression( } if (anonymousClass == null || !anonymousClass.extendsInterface) { - builder.append("(").append(arguments, ", ").append(")") + builder.append(argumentList) } if (anonymousClass != null) { diff --git a/j2k/testData/fileOrElement/formatting/lineBreaksBetweenArguments.java b/j2k/testData/fileOrElement/formatting/lineBreaksBetweenArguments.java index 987e612778f..dda3b58de0c 100644 --- a/j2k/testData/fileOrElement/formatting/lineBreaksBetweenArguments.java +++ b/j2k/testData/fileOrElement/formatting/lineBreaksBetweenArguments.java @@ -5,6 +5,7 @@ class F { void f2(int[] array) { f1(1, 2, 3, 4, - array); + array + ); } } \ No newline at end of file diff --git a/j2k/testData/fileOrElement/formatting/lineBreaksBetweenArguments.kt b/j2k/testData/fileOrElement/formatting/lineBreaksBetweenArguments.kt index 7aa2289d71a..7c1cfdccae8 100644 --- a/j2k/testData/fileOrElement/formatting/lineBreaksBetweenArguments.kt +++ b/j2k/testData/fileOrElement/formatting/lineBreaksBetweenArguments.kt @@ -5,6 +5,7 @@ internal class F { fun f2(array: IntArray) { f1(1, 2, 3, 4, - *array) + *array + ) } }