Skip to content

Commit

Permalink
Fix indent of "by" keyword
Browse files Browse the repository at this point in the history
Original fix for pinterest#1210 solved the runtime exception during formatting but also
reformatted some delegate by constructs which are conflicting with the default
IntelliJ formatting.
  • Loading branch information
Paul Dingemans committed Dec 22, 2021
1 parent 3866e09 commit 2653e53
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 51 deletions.
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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--
Expand Down Expand Up @@ -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" }
Expand Down
Expand Up @@ -955,39 +955,15 @@ 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,
b = 2,
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
Expand Down Expand Up @@ -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)
}
Expand Down

0 comments on commit 2653e53

Please sign in to comment.