Skip to content

Commit

Permalink
Support nested if-elseif-else blocks autoformatting
Browse files Browse the repository at this point in the history
  • Loading branch information
romtsn committed Jun 1, 2020
1 parent 6805807 commit 6463e80
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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<LintError>())
assertThat(format(kotlinScript)).isEqualTo(kotlinScript)
assertThat(lint(kotlinScript)).isEqualTo(emptyList<LintError>())
}

private fun format(kotlinScript: String): String {
Expand Down

0 comments on commit 6463e80

Please sign in to comment.