Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix wrapping of multiline postfix expression #2184

Merged
merged 2 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -180,6 +181,7 @@ public class MultilineExpressionWrappingRule :
IS_EXPRESSION,
OBJECT_LITERAL,
PREFIX_EXPRESSION,
POSTFIX_EXPRESSION,
REFERENCE_EXPRESSION,
SAFE_ACCESS_EXPRESSION,
TRY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 ->
Expand Down Expand Up @@ -279,8 +280,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))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -793,4 +793,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)
}
}