Skip to content

Commit

Permalink
Fix incorrect formatting of nested function literal (#2107)
Browse files Browse the repository at this point in the history
* Fix incorrect formatting of nested function literal

Closes #2106
Closes #2103
  • Loading branch information
paul-dingemans authored Jul 9, 2023
1 parent b0b93f0 commit 306325b
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).

### Fixed

* Fix wrapping of nested function literals `wrapping` ([#2106](https://github.com/pinterest/ktlint/issues/2106))
* Do not indent class body for classes having a long super type list in code style `ktlint_official` as it is inconsistent compared to other class bodies `indent` [#2115](https://github.com/pinterest/ktlint/issues/2115)

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ public class WrappingRule :
?: return
if (lbrace.followedByNewline() ||
lbrace.followedByEolComment() ||
lbrace.followedByFunctionLiteralParameterList() ||
lbrace.isPartOf(LONG_STRING_TEMPLATE_ENTRY)
) {
// String template inside raw string literal may exceed the maximum line length
Expand Down Expand Up @@ -198,6 +199,12 @@ public class WrappingRule :
.takeWhile { it.isWhiteSpaceWithoutNewline() || it.elementType == EOL_COMMENT }
.firstOrNull { it.elementType == EOL_COMMENT }

private fun ASTNode.followedByFunctionLiteralParameterList() =
VALUE_PARAMETER_LIST ==
takeIf { treeParent.elementType == FUNCTION_LITERAL }
?.nextCodeSibling()
?.elementType

private fun rearrangeBlock(
node: ASTNode,
autoCorrect: Boolean,
Expand Down Expand Up @@ -425,8 +432,6 @@ public class WrappingRule :
}
}
}

Unit
}
}

Expand Down Expand Up @@ -676,6 +681,7 @@ public class WrappingRule :
?: return
node
.getEndOfBlock()
?.takeIf { it.elementType == RBRACE }
?.takeUnless { it.isPrecededByNewline() }
?.let { rbrace ->
if (hasNewLineInClosedRange(lbrace, rbrace)) {
Expand All @@ -695,28 +701,36 @@ public class WrappingRule :
private fun ASTNode.isPrecededByNewline() = prevLeaf().isWhiteSpaceWithNewline()

private fun ASTNode.getStartOfBlock() =
firstChildLeafOrSelf()
.let { node ->
if (node.elementType == LBRACE) {
// WHEN-entry block have LBRACE and RBRACE as first and last elements
node
} else {
// Other blocks have LBRACE and RBRACE as siblings of the block
node.prevLeaf { !it.isPartOfComment() && !it.isWhiteSpace() }
if (treeParent.elementType == FUNCTION_LITERAL) {
treeParent.findChildByType(LBRACE)
} else {
firstChildLeafOrSelf()
.let { node ->
if (node.elementType == LBRACE) {
// WHEN-entry block have LBRACE and RBRACE as first and last elements
node
} else {
// Other blocks have LBRACE and RBRACE as siblings of the block
node.prevSibling { !it.isPartOfComment() && !it.isWhiteSpace() }
}
}
}
}

private fun ASTNode.getEndOfBlock() =
lastChildLeafOrSelf()
.let { node ->
if (node.elementType == RBRACE && treeParent.elementType != FUNCTION_LITERAL) {
// WHEN-entry block have LBRACE and RBRACE as first and last elements
node
} else {
// Other blocks have LBRACE and RBRACE as siblings of the block
node.nextLeaf { !it.isPartOfComment() && !it.isWhiteSpace() }
if (treeParent.elementType == FUNCTION_LITERAL) {
treeParent.findChildByType(RBRACE)
} else {
lastChildLeafOrSelf()
.let { node ->
if (node.elementType == RBRACE) {
// WHEN-entry block have LBRACE and RBRACE as first and last elements
node
} else {
// Other blocks have LBRACE and RBRACE as siblings of the block
node.nextSibling { !it.isPartOfComment() && !it.isWhiteSpace() }
}
}
}
}

private companion object {
private val LTOKEN_SET = TokenSet.create(LPAR, LBRACE, LBRACKET, LT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2629,6 +2629,18 @@ internal class WrappingRuleTest {
""".trimIndent()
wrappingRuleAssertThat(code).hasNoLintViolations()
}

@Test
fun `Given a nested function literal`() {
val code =
"""
val foo =
bar {
{ Foobar() }
}
""".trimIndent()
wrappingRuleAssertThat(code).hasNoLintViolations()
}
}

// Replace the "$." placeholder with an actual "$" so that string "$.{expression}" is transformed to a String template
Expand Down

0 comments on commit 306325b

Please sign in to comment.