diff --git a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt index 2f7d51e93b3..3bb0174edde 100644 --- a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt +++ b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt @@ -702,7 +702,7 @@ private val INDENT_RULES = arrayOf( private fun getOperationType(node: ASTNode): IElementType? = node.findChildByType(KtNodeTypes.OPERATION_REFERENCE)?.firstChildNode?.elementType -private fun hasErrorElementBefore(node: ASTNode): Boolean { +fun hasErrorElementBefore(node: ASTNode): Boolean { val prevSibling = getPrevWithoutWhitespace(node) ?: return false if (prevSibling.elementType == TokenType.ERROR_ELEMENT) return true val lastChild = TreeUtil.getLastChild(prevSibling) diff --git a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/kotlinSpacingRules.kt b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/kotlinSpacingRules.kt index c27c3246d72..81f4d7f006c 100644 --- a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/kotlinSpacingRules.kt +++ b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/kotlinSpacingRules.kt @@ -28,6 +28,7 @@ import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.codeStyle.CodeStyleSettings import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.TokenSet +import com.intellij.util.text.TextRangeUtil import org.jetbrains.kotlin.KtNodeTypes.* import org.jetbrains.kotlin.idea.formatter.KotlinSpacingBuilder.CustomSpacingBuilder import org.jetbrains.kotlin.lexer.KtTokens @@ -162,7 +163,7 @@ fun createSpacingBuilder(settings: CodeStyleSettings, builderUtil: KotlinSpacing inPosition(parent = VALUE_ARGUMENT_LIST, left = LPAR).customRule { parent, _, _ -> if (kotlinCommonSettings.CALL_PARAMETERS_LPAREN_ON_NEXT_LINE && needWrapArgumentList(parent.node.psi)) { Spacing.createDependentLFSpacing(0, 0, - parent.textRange, + excludeLambdasAndObjects(parent), commonCodeStyleSettings.KEEP_LINE_BREAKS, commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE) } @@ -170,6 +171,20 @@ fun createSpacingBuilder(settings: CodeStyleSettings, builderUtil: KotlinSpacing createSpacing(0) } } + + inPosition(parent = VALUE_ARGUMENT_LIST, right = RPAR).customRule { parent, left, _ -> + if (kotlinCommonSettings.CALL_PARAMETERS_RPAREN_ON_NEXT_LINE) { + Spacing.createDependentLFSpacing(0, 0, + excludeLambdasAndObjects(parent), + commonCodeStyleSettings.KEEP_LINE_BREAKS, + commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE) + } else if (left.node.elementType == KtTokens.COMMA) { + // incomplete call being edited + createSpacing(1) + } else { + createSpacing(0) + } + } } simple { @@ -288,7 +303,6 @@ fun createSpacingBuilder(settings: CodeStyleSettings, builderUtil: KotlinSpacing beforeInside(RPAR, VALUE_PARAMETER_LIST).spaces(0, kotlinCommonSettings.METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE) afterInside(LT, TYPE_PARAMETER_LIST).spaces(0) beforeInside(GT, TYPE_PARAMETER_LIST).spaces(0) - beforeInside(RPAR, VALUE_ARGUMENT_LIST).spaces(0, kotlinCommonSettings.CALL_PARAMETERS_RPAREN_ON_NEXT_LINE) afterInside(LT, TYPE_ARGUMENT_LIST).spaces(0) beforeInside(GT, TYPE_ARGUMENT_LIST).spaces(0) before(TYPE_ARGUMENT_LIST).spaces(0) @@ -550,4 +564,20 @@ fun createSpacingBuilder(settings: CodeStyleSettings, builderUtil: KotlinSpacing after(EOL_COMMENT).lineBreakInCode() } } -} \ No newline at end of file +} + +private fun excludeLambdasAndObjects(parent: ASTBlock): List { + val rangesToExclude = mutableListOf() + parent.node.psi.accept(object : KtTreeVisitorVoid() { + override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) { + super.visitLambdaExpression(lambdaExpression) + rangesToExclude.add(lambdaExpression.textRange) + } + + override fun visitObjectLiteralExpression(expression: KtObjectLiteralExpression) { + super.visitObjectLiteralExpression(expression) + rangesToExclude.add(expression.textRange) + } + }) + return TextRangeUtil.excludeRanges(parent.textRange, rangesToExclude).toList() +} diff --git a/idea/testData/formatter/parameterList/KT19727.after.kt b/idea/testData/formatter/parameterList/KT19727.after.kt new file mode 100644 index 00000000000..117465d83c9 --- /dev/null +++ b/idea/testData/formatter/parameterList/KT19727.after.kt @@ -0,0 +1,20 @@ +fun useCallable(tag: String, callable: Callable<*>) { + +} + +fun main(args: Array) { + useCallable("A", Callable { println("Hello world") }) + + useCallable("B", Callable { + println("Hello world") + }) + + useCallable("C", object : Callable { + override fun call() { + println("Hello world") + } + }) +} + +// SET_TRUE: CALL_PARAMETERS_LPAREN_ON_NEXT_LINE +// SET_TRUE: CALL_PARAMETERS_RPAREN_ON_NEXT_LINE diff --git a/idea/testData/formatter/parameterList/KT19727.kt b/idea/testData/formatter/parameterList/KT19727.kt new file mode 100644 index 00000000000..117465d83c9 --- /dev/null +++ b/idea/testData/formatter/parameterList/KT19727.kt @@ -0,0 +1,20 @@ +fun useCallable(tag: String, callable: Callable<*>) { + +} + +fun main(args: Array) { + useCallable("A", Callable { println("Hello world") }) + + useCallable("B", Callable { + println("Hello world") + }) + + useCallable("C", object : Callable { + override fun call() { + println("Hello world") + } + }) +} + +// SET_TRUE: CALL_PARAMETERS_LPAREN_ON_NEXT_LINE +// SET_TRUE: CALL_PARAMETERS_RPAREN_ON_NEXT_LINE diff --git a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java index 5fdf91c9534..e5bd0a3e77c 100644 --- a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java @@ -1138,6 +1138,12 @@ public class FormatterTestGenerated extends AbstractFormatterTest { doTest(fileName); } + @TestMetadata("KT19727.after.kt") + public void testKT19727() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/parameterList/KT19727.after.kt"); + doTest(fileName); + } + @TestMetadata("ParameterListChopAsNeeded.after.kt") public void testParameterListChopAsNeeded() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/formatter/parameterList/ParameterListChopAsNeeded.after.kt");