From 2653e53f16da93cca9595e4a31395f35d3a6a22b Mon Sep 17 00:00:00 2001 From: Paul Dingemans Date: Wed, 22 Dec 2021 21:41:27 +0100 Subject: [PATCH] Fix indent of "by" keyword Original fix for #1210 solved the runtime exception during formatting but also reformatted some delegate by constructs which are conflicting with the default IntelliJ formatting. --- .../ruleset/standard/IndentationRule.kt | 18 ++++++- .../ruleset/standard/IndentationRuleTest.kt | 52 +------------------ 2 files changed, 19 insertions(+), 51 deletions(-) diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRule.kt index fc7d3d6374..ab2910a8d1 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRule.kt @@ -26,6 +26,7 @@ import com.pinterest.ktlint.core.ast.ElementType.EQ import com.pinterest.ktlint.core.ast.ElementType.FUN import com.pinterest.ktlint.core.ast.ElementType.FUNCTION_LITERAL import com.pinterest.ktlint.core.ast.ElementType.GT +import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER import com.pinterest.ktlint.core.ast.ElementType.KDOC import com.pinterest.ktlint.core.ast.ElementType.KDOC_END import com.pinterest.ktlint.core.ast.ElementType.KDOC_LEADING_ASTERISK @@ -163,6 +164,11 @@ class IndentationRule : Rule("indent"), Rule.Modifier.RestrictToRootLast { Companion.debug { "phase: indentation" } // step 2: correct indentation indent(node, autoCorrect, emit, editorConfig) + + // The expectedIndent should never be negative. If so, it is very likely that ktlint crashes at runtime when + // autocorrecting is executed while no error occurs with linting only. Such errors often are not found in unit + // tests, as the examples are way more simple than realistic code. + assert(expectedIndent >= 0) } private fun rearrange( @@ -742,7 +748,13 @@ class IndentationRule : Rule("indent"), Rule.Modifier.RestrictToRootLast { val byKeywordLeaf = n .findChildByType(DELEGATED_SUPER_TYPE_ENTRY) ?.findChildByType(BY_KEYWORD) - if (n.prevLeaf()?.textContains('\n') == true && byKeywordLeaf?.prevLeaf().isWhiteSpaceWithNewline()) { + if (n.prevLeaf()?.textContains('\n') == true && + byKeywordLeaf?.prevLeaf().isWhiteSpaceWithNewline() + ) { + Unit + } else if (byKeywordLeaf?.prevLeaf()?.textContains('\n') == true && + byKeywordLeaf.prevLeaf()?.treeParent?.nextLeaf()?.elementType == IDENTIFIER + ) { Unit } else { expectedIndent-- @@ -1014,6 +1026,10 @@ class IndentationRule : Rule("indent"), Rule.Modifier.RestrictToRootLast { node.treeParent.prevLeaf()?.textContains('\n') == true ) { 0 + } else if (node.isPartOf(DELEGATED_SUPER_TYPE_ENTRY) && + node.treeParent.nextLeaf()?.elementType == IDENTIFIER + ) { + 0 } else { expectedIndent++ debug { "++whitespace followed by BY keyword -> $expectedIndent" } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRuleTest.kt index f1ce955463..20d0c69843 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRuleTest.kt @@ -955,10 +955,6 @@ internal class IndentationRuleTest { fun `lint and format delegation 2`() { val code = """ - interface Foo - - class Bar(a: Int, b: Int, c: Int) : Foo - class Test2 : Foo by Bar( a = 1, @@ -966,28 +962,8 @@ internal class IndentationRuleTest { c = 3 ) """.trimIndent() - val formattedCode = - """ - interface Foo - - class Bar(a: Int, b: Int, c: Int) : Foo - - class Test2 : Foo - by Bar( - a = 1, - b = 2, - c = 3 - ) - """.trimIndent() - - assertThat(IndentationRule().lint(code)).containsExactly( - LintError(6, 1, "indent", "Unexpected indentation (0) (should be 4)"), - LintError(7, 1, "indent", "Unexpected indentation (4) (should be 8)"), - LintError(8, 1, "indent", "Unexpected indentation (4) (should be 8)"), - LintError(9, 1, "indent", "Unexpected indentation (4) (should be 8)"), - LintError(10, 1, "indent", "Unexpected indentation (0) (should be 4)"), - ) - assertThat(IndentationRule().format(code)).isEqualTo(formattedCode) + assertThat(IndentationRule().format(code)).isEqualTo(code) + assertThat(IndentationRule().lint(code)).isEmpty() } @Test @@ -1582,30 +1558,6 @@ internal class IndentationRuleTest { object ApplicationComponentFactory : ApplicationComponent.Factory by DaggerApplicationComponent.factory() """.trimIndent() - val formattedCode = - """ - object ApplicationComponentFactory : ApplicationComponent.Factory - by DaggerApplicationComponent.factory() - """.trimIndent() - assertThat(IndentationRule().lint(code)).containsExactly( - LintError(2, 1, "indent", "Unexpected indentation (0) (should be 4)") - ) - assertThat(IndentationRule().format(code)).isEqualTo(formattedCode) - } - - @Test - fun `Issue 1210 - format of statements after supertype delegated entry 1`() { - val code = - """ - object Issue1210 : ApplicationComponent.Factory - by DaggerApplicationComponent.factory() - - // The next line ensures that the fix regarding the expectedIndex due to alignment of "by" keyword in - // class above, is still in place. Without this fix, the expectedIndex would hold a negative value, - // resulting in the formatting to crash on the next line. - val bar = 1 - """.trimIndent() - assertThat(IndentationRule().lint(code)).isEmpty() assertThat(IndentationRule().format(code)).isEqualTo(code) }