From b14eaef3cb7a550990d30a806c0097e0387dfc61 Mon Sep 17 00:00:00 2001 From: Paul Dingemans Date: Tue, 15 Aug 2023 18:11:34 +0200 Subject: [PATCH] Fix wrapping of multiline postfix expression (#2184) * Fix wrapping of multiline postfix expression Closes #2183 --- CHANGELOG.md | 1 + .../ruleset/standard/rules/IndentationRule.kt | 9 +++--- .../rules/MultilineExpressionWrappingRule.kt | 2 ++ .../ruleset/standard/rules/WrappingRule.kt | 29 ++++++++++--------- .../MultilineExpressionWrappingRuleTest.kt | 19 ++++++++++++ 5 files changed, 42 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c03ef38983..3aa574d616 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Fix null pointer exception for if-else statement with empty THEN block `if-else-bracing` [#2135](https://github.com/pinterest/ktlint/issues/2135) * Do not wrap a single line enum class `statement-wrapping` [#2177](https://github.com/pinterest/ktlint/issues/2177) * Fix alignment of type constraints after `where` keyword in function signature `indent` [#2175](https://github.com/pinterest/ktlint/issues/2175) +* Fix wrapping of multiline postfix expression `multiline-expression-wrapping` [#2183](https://github.com/pinterest/ktlint/issues/2183) ### Changed diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/IndentationRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/IndentationRule.kt index 6f170f325c..23ce722a38 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/IndentationRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/IndentationRule.kt @@ -581,10 +581,11 @@ public class IndentationRule : node.prevSibling { it.isWhiteSpaceWithNewline() } == null && node == node.treeParent.findChildByType(VALUE_PARAMETER) ) { - nextToAstNode = startIndentContext( - fromAstNode = fromAstNode, - toAstNode = nextToAstNode, - ).fromASTNode.prevLeaf { !it.isWhiteSpace() }!! + nextToAstNode = + startIndentContext( + fromAstNode = fromAstNode, + toAstNode = nextToAstNode, + ).fromASTNode.prevLeaf { !it.isWhiteSpace() }!! } else { startIndentContext( fromAstNode = node, diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrappingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrappingRule.kt index 795bfc5ac9..7a9815814c 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrappingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrappingRule.kt @@ -15,6 +15,7 @@ import com.pinterest.ktlint.rule.engine.core.api.ElementType.IF import com.pinterest.ktlint.rule.engine.core.api.ElementType.IS_EXPRESSION import com.pinterest.ktlint.rule.engine.core.api.ElementType.OBJECT_LITERAL import com.pinterest.ktlint.rule.engine.core.api.ElementType.OPERATION_REFERENCE +import com.pinterest.ktlint.rule.engine.core.api.ElementType.POSTFIX_EXPRESSION import com.pinterest.ktlint.rule.engine.core.api.ElementType.PREFIX_EXPRESSION import com.pinterest.ktlint.rule.engine.core.api.ElementType.REFERENCE_EXPRESSION import com.pinterest.ktlint.rule.engine.core.api.ElementType.RPAR @@ -181,6 +182,7 @@ public class MultilineExpressionWrappingRule : IS_EXPRESSION, OBJECT_LITERAL, PREFIX_EXPRESSION, + POSTFIX_EXPRESSION, REFERENCE_EXPRESSION, SAFE_ACCESS_EXPRESSION, TRY, diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/WrappingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/WrappingRule.kt index b3aae80af2..1d4fdaa190 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/WrappingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/WrappingRule.kt @@ -210,23 +210,24 @@ public class WrappingRule : autoCorrect: Boolean, emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit, ) { - val rElementType = MATCHING_RTOKEN_MAP[node.elementType] + val closingElementType = MATCHING_RTOKEN_MAP[node.elementType] var newlineInBetween = false var parameterListInBetween = false var numberOfArgs = 0 var firstArg: ASTNode? = null // matching ), ] or } - val r = node.nextSibling { - val isValueArgument = it.elementType == VALUE_ARGUMENT - val hasLineBreak = if (isValueArgument) it.hasLineBreak(LAMBDA_EXPRESSION, FUN) else it.hasLineBreak() - newlineInBetween = newlineInBetween || hasLineBreak - parameterListInBetween = parameterListInBetween || it.elementType == VALUE_PARAMETER_LIST - if (isValueArgument) { - numberOfArgs++ - firstArg = it - } - it.elementType == rElementType - }!! + val closingElement = + node.nextSibling { + val isValueArgument = it.elementType == VALUE_ARGUMENT + val hasLineBreak = if (isValueArgument) it.hasLineBreak(LAMBDA_EXPRESSION, FUN) else it.hasLineBreak() + newlineInBetween = newlineInBetween || hasLineBreak + parameterListInBetween = parameterListInBetween || it.elementType == VALUE_PARAMETER_LIST + if (isValueArgument) { + numberOfArgs++ + firstArg = it + } + it.elementType == closingElementType + }!! if ( !newlineInBetween || // keep { p -> @@ -283,8 +284,8 @@ public class WrappingRule : ) { requireNewlineAfterLeaf(node, autoCorrect, emit) } - if (!r.prevLeaf().isWhiteSpaceWithNewline()) { - requireNewlineBeforeLeaf(r, autoCorrect, emit, indentConfig.parentIndentOf(node)) + if (!closingElement.prevLeaf().isWhiteSpaceWithNewline()) { + requireNewlineBeforeLeaf(closingElement, autoCorrect, emit, indentConfig.parentIndentOf(node)) } } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrappingRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrappingRuleTest.kt index c5e6930146..e55d8ec642 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrappingRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrappingRuleTest.kt @@ -784,4 +784,23 @@ class MultilineExpressionWrappingRuleTest { .addAdditionalRuleProvider { IndentationRule() } .hasNoLintViolations() } + + @Test + fun `Issue 2183 - Given a multiline postfix expression then reformat`() { + val code = + """ + val foobar = foo!! + .bar() + """.trimIndent() + val formattedCode = + """ + val foobar = + foo!! + .bar() + """.trimIndent() + multilineExpressionWrappingRuleAssertThat(code) + .addAdditionalRuleProvider { IndentationRule() } + .hasLintViolation(1, 14, "A multiline expression should start on a new line") + .isFormattedAs(formattedCode) + } }