diff --git a/ktlint-ruleset-experimental/src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/MultiLineIfElseRule.kt b/ktlint-ruleset-experimental/src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/MultiLineIfElseRule.kt index 3042c98d13..f90db68d8d 100644 --- a/ktlint-ruleset-experimental/src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/MultiLineIfElseRule.kt +++ b/ktlint-ruleset-experimental/src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/MultiLineIfElseRule.kt @@ -1,16 +1,24 @@ package com.pinterest.ktlint.ruleset.experimental +import com.pinterest.ktlint.core.KtLint +import com.pinterest.ktlint.core.LintError import com.pinterest.ktlint.core.Rule +import com.pinterest.ktlint.core.RuleSet +import com.pinterest.ktlint.core.ast.ElementType +import com.pinterest.ktlint.core.ast.ElementType.BLOCK import com.pinterest.ktlint.core.ast.ElementType.ELSE import com.pinterest.ktlint.core.ast.ElementType.ELSE_KEYWORD +import com.pinterest.ktlint.core.ast.ElementType.IF import com.pinterest.ktlint.core.ast.ElementType.LBRACE import com.pinterest.ktlint.core.ast.ElementType.RBRACE import com.pinterest.ktlint.core.ast.ElementType.THEN +import com.pinterest.ktlint.core.ast.parent import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl import org.jetbrains.kotlin.psi.KtBlockExpression +import org.jetbrains.kotlin.psi.psiUtil.parents /** * https://kotlinlang.org/docs/reference/coding-conventions.html#formatting-control-flow-statements @@ -40,7 +48,12 @@ class MultiLineIfElseRule : Rule("multiline-if-else") { private fun autocorrect(node: ASTNode) { val bodyIndent = node.treePrev.text - val rightBraceIndent = (node.treeParent.treePrev as? PsiWhiteSpace)?.text ?: "\n" + val rightBraceIndent = when { + // in case of else if, get the indentation from the first if + node.treeParent.treeParent.elementType == ELSE -> node.parent({ it.elementType == IF && it.treeParent.elementType == BLOCK})!!.treePrev.text + node.treeParent.treePrev is PsiWhiteSpace -> node.treeParent.treePrev.text + else -> "\n" + } (node.treePrev as LeafPsiElement).rawReplaceWithText(" ") KtBlockExpression(null).apply { val previousChild = node.firstChildNode diff --git a/ktlint-ruleset-experimental/src/test/kotlin/com/pinterest/ktlint/ruleset/experimental/MultiLineIfElseRuleTest.kt b/ktlint-ruleset-experimental/src/test/kotlin/com/pinterest/ktlint/ruleset/experimental/MultiLineIfElseRuleTest.kt index ed1d0324da..07e4329a0a 100644 --- a/ktlint-ruleset-experimental/src/test/kotlin/com/pinterest/ktlint/ruleset/experimental/MultiLineIfElseRuleTest.kt +++ b/ktlint-ruleset-experimental/src/test/kotlin/com/pinterest/ktlint/ruleset/experimental/MultiLineIfElseRuleTest.kt @@ -3,7 +3,6 @@ package com.pinterest.ktlint.ruleset.experimental import com.pinterest.ktlint.core.LintError import com.pinterest.ktlint.test.format import com.pinterest.ktlint.test.lint -import org.assertj.core.api.Assertions import org.assertj.core.api.Assertions.assertThat import org.junit.Test @@ -124,9 +123,137 @@ class MultiLineIfElseRuleTest { ) } + @Test + fun testMultiLineIfElseIfElseWithoutCurlyBraces() { + val ifElseWithoutCurlyBrace = + """ + fun main() { + if (true) + return 0 + else if (false) + return 1 + else + return -1 + } + """.trimIndent() + + assertThat(lint(ifElseWithoutCurlyBrace)).isEqualTo( + listOf( + LintError(3, 9, "multiline-if-else", "Missing { ... }"), + LintError(5, 9, "multiline-if-else", "Missing { ... }"), + LintError(7, 9, "multiline-if-else", "Missing { ... }") + ) + ) + assertThat(format(ifElseWithoutCurlyBrace)).isEqualTo( + """ + fun main() { + if (true) { + return 0 + } else if (false) { + return 1 + } else { + return -1 + } + } + """.trimIndent() + ) + } + + @Test + fun testNestedMultiLineIfElse() { + val ifElseWithoutCurlyBrace = + """ + fun main() { + if (outerCondition1) + if (innerCondition1) + if (innerCondition11) + return 0 + else if (innerCondition12) + return 12 + else if (innerCondition13) + return 13 + else + return 14 + else if (innerCondition44) + return 1 + else { + return 16 + } + else if (outerCondition2) + if (innerCondition2) + return 2 + else if (innerCondition3) + return 3 + else + return 4 + else + if (innerCondition4) + return 5 + else + return -1 + } + """.trimIndent() + + assertThat(lint(ifElseWithoutCurlyBrace)).isEqualTo( + listOf( + LintError(3, 9, "multiline-if-else", "Missing { ... }"), + LintError(4, 13, "multiline-if-else", "Missing { ... }"), + LintError(5, 17, "multiline-if-else", "Missing { ... }"), + LintError(7, 17, "multiline-if-else", "Missing { ... }"), + LintError(9, 17, "multiline-if-else", "Missing { ... }"), + LintError(11, 17, "multiline-if-else", "Missing { ... }"), + LintError(13, 13, "multiline-if-else", "Missing { ... }"), + LintError(18, 9, "multiline-if-else", "Missing { ... }"), + LintError(19, 13, "multiline-if-else", "Missing { ... }"), + LintError(21, 13, "multiline-if-else", "Missing { ... }"), + LintError(23, 13, "multiline-if-else", "Missing { ... }"), + LintError(25, 9, "multiline-if-else", "Missing { ... }"), + LintError(26, 13, "multiline-if-else", "Missing { ... }"), + LintError(28, 13, "multiline-if-else", "Missing { ... }") + ) + ) + assertThat(format(ifElseWithoutCurlyBrace)).isEqualTo( + """ + fun main() { + if (outerCondition1) { + if (innerCondition1) { + if (innerCondition11) { + return 0 + } else if (innerCondition12) { + return 12 + } else if (innerCondition13) { + return 13 + } else { + return 14 + } + } else if (innerCondition44) { + return 1 + } else { + return 16 + } + } else if (outerCondition2) { + if (innerCondition2) { + return 2 + } else if (innerCondition3) { + return 3 + } else { + return 4 + } + } else { + if (innerCondition4) { + return 5 + } else { + return -1 + } + } + } + """.trimIndent() + ) + } + private fun assertOK(kotlinScript: String) { - Assertions.assertThat(format(kotlinScript)).isEqualTo(kotlinScript) - Assertions.assertThat(lint(kotlinScript)).isEqualTo(emptyList()) + assertThat(format(kotlinScript)).isEqualTo(kotlinScript) + assertThat(lint(kotlinScript)).isEqualTo(emptyList()) } private fun format(kotlinScript: String): String {