diff --git a/CHANGELOG.md b/CHANGELOG.md index f1620cee6b..18caaa55d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -279,6 +279,7 @@ Previously the default value for `.editorconfig` property `max_line_length` was * Remove trailing comma if last two enum entries are on the same line and trailing commas are not allowed. `trailing-comma-on-declaration-site` ([#1905](https://github.com/pinterest/ktlint/issues/1905)) * Wrap annotated function parameters to a separate line in code style `ktlint_official` only. `function-signature`, `parameter-list-wrapping` ([#1908](https://github.com/pinterest/ktlint/issues/1908)) * Wrap annotated projection types in type argument lists to a separate line `annotation` ([#1909](https://github.com/pinterest/ktlint/issues/1909)) +* Add newline after adding trailing comma in parameter list of a function literal `trailing-comma-on-declaration-site` ([#1911](https://github.com/pinterest/ktlint/issues/1911)) ### Changed * Wrap the parameters of a function literal containing a multiline parameter list (only in `ktlint_official` code style) `parameter-list-wrapping` ([#1681](https://github.com/pinterest/ktlint/issues/1681)). diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ParameterListSpacingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ParameterListSpacingRule.kt index 68dfe8bab6..23b114c87b 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ParameterListSpacingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ParameterListSpacingRule.kt @@ -89,13 +89,10 @@ public class ParameterListSpacingRule : } COMMA -> { // Comma must be followed by whitespace - val nextSibling = - el - .nextSibling() - ?.elementType - if (nextSibling != WHITE_SPACE) { - addMissingWhiteSpaceAfterMe(el, emit, autoCorrect) - } + el + .nextLeaf() + ?.takeIf { it.elementType != WHITE_SPACE } + ?.let { addMissingWhiteSpaceAfterMe(el, emit, autoCorrect) } } VALUE_PARAMETER -> { valueParameterCount += 1 diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TrailingCommaOnDeclarationSiteRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TrailingCommaOnDeclarationSiteRule.kt index b7054a27bf..8da16f1086 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TrailingCommaOnDeclarationSiteRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TrailingCommaOnDeclarationSiteRule.kt @@ -295,9 +295,13 @@ public class TrailingCommaOnDeclarationSiteRule : } TrailingCommaState.MISSING -> if (isTrailingCommaAllowed) { - val addNewLineBeforeArrowInWhenEntry = addNewLineBeforeArrowInWhen() + val leafBeforeArrowOrNull = leafBeforeArrowOrNull() + val addNewLine = + leafBeforeArrowOrNull + ?.let { !(leafBeforeArrowOrNull is PsiWhiteSpace && leafBeforeArrowOrNull.textContains('\n')) } + ?: false val prevNode = inspectNode.prevCodeLeaf()!! - if (addNewLineBeforeArrowInWhenEntry) { + if (addNewLine) { emit( prevNode.startOffset + prevNode.textLength, "Missing trailing comma and newline before \"${inspectNode.text}\"", @@ -311,16 +315,15 @@ public class TrailingCommaOnDeclarationSiteRule : ) } if (autoCorrect) { - if (addNewLineBeforeArrowInWhenEntry) { + if (addNewLine) { val newLine = KtPsiFactory(prevNode.psi).createWhiteSpace( prevNode .treeParent .indent(), ) - val leafBeforeArrow = (psi as KtWhenEntry).arrow?.prevLeaf() - if (leafBeforeArrow != null && leafBeforeArrow is PsiWhiteSpace) { - leafBeforeArrow.replace(newLine) + if (leafBeforeArrowOrNull != null && leafBeforeArrowOrNull is PsiWhiteSpace) { + leafBeforeArrowOrNull.replace(newLine) } else { prevNode.psi.parent.addAfter(newLine, prevNode.psi) } @@ -392,12 +395,19 @@ public class TrailingCommaOnDeclarationSiteRule : } } - private fun ASTNode.addNewLineBeforeArrowInWhen() = - if (psi is KtWhenEntry) { - val leafBeforeArrow = (psi as KtWhenEntry).arrow?.prevLeaf() - !(leafBeforeArrow is PsiWhiteSpace && leafBeforeArrow.textContains('\n')) - } else { - false + private fun ASTNode.leafBeforeArrowOrNull() = + when (psi) { + is KtWhenEntry -> + (psi as KtWhenEntry) + .arrow + ?.prevLeaf() + + is KtFunctionLiteral -> + (psi as KtFunctionLiteral) + .arrow + ?.prevLeaf() + + else -> null } private fun ASTNode.findPreviousTrailingCommaNodeOrNull(): ASTNode? { diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ParameterListSpacingRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ParameterListSpacingRuleTest.kt index 00231c5754..e813f919cb 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ParameterListSpacingRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ParameterListSpacingRuleTest.kt @@ -447,6 +447,21 @@ class ParameterListSpacingRuleTest { .hasNoLintViolations() } + @Test + fun `Given a function literal with a trailing comma in the parameter list and arrow on the next line then do not report a violation`() { + val code = + """ + val foo = { + string: String, + int: Int, + -> + // do something + } + """.trimIndent() + parameterListSpacingRuleAssertThat(code) + .hasNoLintViolations() + } + private companion object { const val TOO_MANY_SPACES = " " } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TrailingCommaOnDeclarationSiteRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TrailingCommaOnDeclarationSiteRuleTest.kt index a0f6cceb28..8120e48179 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TrailingCommaOnDeclarationSiteRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TrailingCommaOnDeclarationSiteRuleTest.kt @@ -1056,4 +1056,29 @@ class TrailingCommaOnDeclarationSiteRuleTest { .withEditorConfigOverride(TRAILING_COMMA_ON_DECLARATION_SITE_PROPERTY to true) .hasNoLintViolations() } + + @Test + fun `Given a function literal with a trailing comma in the parameter list and arrow on the next line then do not report a violation`() { + val code = + """ + val foo = { + string: String, + int: Int -> + // do something + } + """.trimIndent() + val formattedCode = + """ + val foo = { + string: String, + int: Int, + -> + // do something + } + """.trimIndent() + trailingCommaOnDeclarationSiteRuleAssertThat(code) + .withEditorConfigOverride(TRAILING_COMMA_ON_DECLARATION_SITE_PROPERTY to true) + .hasLintViolation(3, 17, "Missing trailing comma and newline before \"->\"") + .isFormattedAs(formattedCode) + } }