diff --git a/CHANGELOG.md b/CHANGELOG.md index 472119cf52..85f32bc34c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -292,6 +292,7 @@ if (node.isRoot()) { * 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)) * Wrap annotations before class constructor in code style `ktlint_official`. `annotation` ([#1916](https://github.com/pinterest/ktlint/issues/1916)) * Annotations on type projections should be wrapped in same way as other annotations `annotation` ([#1917](https://github.com/pinterest/ktlint/issues/1917)) +* An if-else followed by an elvis operator should not be wrapped in an else-block `multiline-if-else` ([#1904](https://github.com/pinterest/ktlint/issues/1904)) ### 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/MultiLineIfElseRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultiLineIfElseRule.kt index 33f6a6e460..3fe1e6aee9 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultiLineIfElseRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultiLineIfElseRule.kt @@ -1,6 +1,8 @@ package com.pinterest.ktlint.ruleset.standard.rules +import com.pinterest.ktlint.rule.engine.core.api.ElementType.BINARY_EXPRESSION import com.pinterest.ktlint.rule.engine.core.api.ElementType.BLOCK +import com.pinterest.ktlint.rule.engine.core.api.ElementType.DOT_QUALIFIED_EXPRESSION import com.pinterest.ktlint.rule.engine.core.api.ElementType.ELSE import com.pinterest.ktlint.rule.engine.core.api.ElementType.ELSE_KEYWORD import com.pinterest.ktlint.rule.engine.core.api.ElementType.IF @@ -52,29 +54,54 @@ public class MultiLineIfElseRule : autoCorrect: Boolean, emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit, ) { - if (node.elementType == THEN || node.elementType == ELSE) { - if (node.firstChildNode?.elementType == BLOCK) { + if (node.elementType != THEN && node.elementType != ELSE) { + return + } + + // Ignore when already wrapped in a block + if (node.firstChildNode?.elementType == BLOCK) { + return + } + + if (node.elementType == ELSE && node.firstChildNode?.elementType == BINARY_EXPRESSION) { + // Allow + // val foo = if (bar1) { + // "bar1" + // } else { + // null + // } ?: "something-else" + return + } + + if (node.elementType == ELSE && node.firstChildNode?.elementType == DOT_QUALIFIED_EXPRESSION) { + // Allow + // val foo = if (bar1) { + // "bar1" + // } else { + // "bar2" + // }.plus("foo") + return + } + + if (!node.treePrev.textContains('\n')) { + if (node.firstChildNode.elementType == IF) { + // Allow single line for: + // else if (...) return } - - if (!node.treePrev.textContains('\n')) { - if (node.firstChildNode.elementType == IF) { - // Allow single line for: - // else if (...) - return - } - if (!node.treeParent.textContains('\n')) { - // Allow single line if statements as long as they are really simple (e.g. do not contain newlines) - // if (...) // no else statement - // if (...) else - return - } + if (!node.treeParent.textContains('\n')) { + // Allow single line if statements as long as they are really simple (e.g. do not contain newlines) + // if (...) // no else statement + // if (...) else + return } - emit(node.firstChildNode.startOffset, "Missing { ... }", true) - if (autoCorrect) { - autocorrect(node) - } + Unit + } + + emit(node.firstChildNode.startOffset, "Missing { ... }", true) + if (autoCorrect) { + autocorrect(node) } } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultiLineIfElseRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultiLineIfElseRuleTest.kt index a2f553902e..e509735182 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultiLineIfElseRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultiLineIfElseRuleTest.kt @@ -569,4 +569,32 @@ class MultiLineIfElseRuleTest { LintViolation(3, 10, "Missing { ... }"), ).isFormattedAs(formattedCode) } + + @Test + fun `Issue 1904 - Given an nested if else statement followed by an elvis operator`() { + val code = + """ + val foo = if (bar1) { + "bar1" + } else { + null + } ?: "something-else" + """.trimIndent() + multiLineIfElseRuleAssertThat(code).hasNoLintViolations() + } + + @Test + fun `Issue 1904 - Given an nested if else statement and else which is part of a dot qualified expression`() { + val code = + """ + val foo = if (bar1) { + "bar1" + } else if (bar2) { + "bar2" + } else { + "bar3" + }.plus("foo") + """.trimIndent() + multiLineIfElseRuleAssertThat(code).hasNoLintViolations() + } }