diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/UnnecessaryParenthesesBeforeTrailingLambdaRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/UnnecessaryParenthesesBeforeTrailingLambdaRule.kt index 0948c3ae7f..5b8943b6b6 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/UnnecessaryParenthesesBeforeTrailingLambdaRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/UnnecessaryParenthesesBeforeTrailingLambdaRule.kt @@ -2,7 +2,9 @@ package com.pinterest.ktlint.ruleset.standard.rules import com.pinterest.ktlint.rule.engine.core.api.AutocorrectDecision import com.pinterest.ktlint.rule.engine.core.api.ElementType.CALL_EXPRESSION +import com.pinterest.ktlint.rule.engine.core.api.ElementType.FUNCTION_LITERAL import com.pinterest.ktlint.rule.engine.core.api.ElementType.LAMBDA_ARGUMENT +import com.pinterest.ktlint.rule.engine.core.api.ElementType.LAMBDA_EXPRESSION import com.pinterest.ktlint.rule.engine.core.api.ElementType.LPAR import com.pinterest.ktlint.rule.engine.core.api.ElementType.RPAR import com.pinterest.ktlint.rule.engine.core.api.ElementType.VALUE_ARGUMENT_LIST @@ -14,6 +16,7 @@ import com.pinterest.ktlint.rule.engine.core.api.children import com.pinterest.ktlint.rule.engine.core.api.ifAutocorrectAllowed import com.pinterest.ktlint.rule.engine.core.api.isPartOf import com.pinterest.ktlint.rule.engine.core.api.nextCodeSibling +import com.pinterest.ktlint.rule.engine.core.api.prevCodeSibling import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -27,8 +30,9 @@ public class UnnecessaryParenthesesBeforeTrailingLambdaRule : StandardRule("unne node: ASTNode, emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> AutocorrectDecision, ) { - if (node.isPartOf(CALL_EXPRESSION) && - node.isEmptyArgumentList() && + if (node.isEmptyArgumentList() && + node.isPartOf(CALL_EXPRESSION) && + node.isNotPrecededByCallExpressionEndingWithLambdaArgument() && node.nextCodeSibling()?.elementType == LAMBDA_ARGUMENT ) { emit( @@ -46,6 +50,17 @@ public class UnnecessaryParenthesesBeforeTrailingLambdaRule : StandardRule("unne children() .filterNot { it.elementType == LPAR || it.elementType == RPAR } .none() + + private fun ASTNode.isNotPrecededByCallExpressionEndingWithLambdaArgument() = + prevCodeSibling() + ?.takeIf { it.elementType == CALL_EXPRESSION } + ?.lastChildNode + ?.takeIf { it.elementType == LAMBDA_ARGUMENT } + ?.lastChildNode + ?.takeIf { it.elementType == LAMBDA_EXPRESSION } + ?.lastChildNode + ?.let { it.elementType != FUNCTION_LITERAL } + ?: true } public val UNNECESSARY_PARENTHESES_BEFORE_TRAILING_LAMBDA_RULE_ID: RuleId = UnnecessaryParenthesesBeforeTrailingLambdaRule().ruleId diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/UnnecessaryParenthesesBeforeTrailingLambdaRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/UnnecessaryParenthesesBeforeTrailingLambdaRuleTest.kt index e389a78524..b349ab249b 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/UnnecessaryParenthesesBeforeTrailingLambdaRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/UnnecessaryParenthesesBeforeTrailingLambdaRuleTest.kt @@ -23,4 +23,15 @@ class UnnecessaryParenthesesBeforeTrailingLambdaRuleTest { .hasLintViolation(2, 24, "Empty parentheses in function call followed by lambda are unnecessary") .isFormattedAs(formattedCode) } + + @Test + fun `Issue 2884 - Given some a call expression ending with a lambda argument, followed by an empty argument list followed by another lambda argument then do not remove empty parameter list`() { + val code = + """ + fun fooBar(foo: () -> String): (() -> String) -> String = { bar -> foo().plus(" ").plus(bar()) } + + val foobar = fooBar { "Hello" }() { "world" } + """.trimIndent() + unnecessaryParenthesesBeforeTrailingLambdaRuleAssertThat(code).hasNoLintViolations() + } }