From 47b9f34d76bbad110b323654f0c0d63b73cfc188 Mon Sep 17 00:00:00 2001 From: paul-dingemans Date: Tue, 14 Dec 2021 09:50:50 +0100 Subject: [PATCH] Fix indentation of secondary constructor (#1304) * Fix indentation of secondary constructor Closes #1222 * Remove support of continuation index in secondary constructor This aligns the formatting with the default IntelliJ formatting of secondary constructors. Closes #1222 Co-authored-by: Paul Dingemans --- CHANGELOG.md | 1 + .../ruleset/standard/IndentationRule.kt | 26 ++++++--- .../ruleset/standard/IndentationRuleTest.kt | 58 +++++++++++++++++++ 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 417c136a1b..5641c44bb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fix ClassCastException using ktlintFormat on class with KDoc (`no-trailing-spaces`) ([#1270](https://github.com/pinterest/ktlint/issues/1270)) - Do not remove trailing comma in annotation ([#1297](https://github.com/pinterest/ktlint/issues/1297)) - Do not remove import which is used as markdown link in KDoc only (`no-unused-imports`) ([#1282](https://github.com/pinterest/ktlint/issues/1282)) +- Fix indentation of secondary constructor (`indent`) ([#1222](https://github.com/pinterest/ktlint/issues/1222)) ### Changed - Update Kotlin version to `1.6.0` release 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 b50dbf294d..8c184fa7d8 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 @@ -47,6 +47,7 @@ import com.pinterest.ktlint.core.ast.ElementType.RBRACKET import com.pinterest.ktlint.core.ast.ElementType.REGULAR_STRING_PART import com.pinterest.ktlint.core.ast.ElementType.RPAR import com.pinterest.ktlint.core.ast.ElementType.SAFE_ACCESS_EXPRESSION +import com.pinterest.ktlint.core.ast.ElementType.SECONDARY_CONSTRUCTOR import com.pinterest.ktlint.core.ast.ElementType.SHORT_STRING_TEMPLATE_ENTRY import com.pinterest.ktlint.core.ast.ElementType.STRING_TEMPLATE import com.pinterest.ktlint.core.ast.ElementType.SUPER_TYPE_CALL_ENTRY @@ -765,13 +766,24 @@ class IndentationRule : Rule("indent"), Rule.Modifier.RestrictToRootLast { } private fun adjustExpectedIndentAfterColon(n: ASTNode, ctx: IndentContext) { - expectedIndent++ - debug { "++after(COLON) -> $expectedIndent" } - if (n.isPartOf(FUN)) { - val returnType = n.nextCodeSibling() - ctx.exitAdjBy(returnType!!, -1) - } else { - ctx.exitAdjBy(n.treeParent, -1) + when { + n.isPartOf(FUN) -> { + expectedIndent++ + debug { "++after(COLON IN FUN) -> $expectedIndent" } + val returnType = n.nextCodeSibling() + ctx.exitAdjBy(returnType!!, -1) + } + n.treeParent.isPartOf(SECONDARY_CONSTRUCTOR) -> { + expectedIndent++ + debug { "++after(COLON IN CONSTRUCTOR) -> $expectedIndent" } + val nextCodeSibling = n.nextCodeSibling() + ctx.exitAdjBy(nextCodeSibling!!, -1) + } + else -> { + expectedIndent++ + debug { "++after(COLON) -> $expectedIndent" } + ctx.exitAdjBy(n.treeParent, -1) + } } } 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 d42d1036ca..b2e78cb6e0 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 @@ -1343,6 +1343,64 @@ internal class IndentationRuleTest { assertThat(IndentationRule().format(codeTabs, INDENT_STYLE_TABS)).isEqualTo(codeTabs) } + @Test + fun `Issue 1222 - format secondary constructor`() { + val code = + """ + class Issue1222 { + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : + super(context, attrs, defStyleAttr, defStyleRes) { + init(attrs, defStyleAttr, defStyleRes) + } + } + """.trimIndent() + val formattedCode = + """ + class Issue1222 { + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : + super(context, attrs, defStyleAttr, defStyleRes) { + init(attrs, defStyleAttr, defStyleRes) + } + } + """.trimIndent() + assertThat(IndentationRule().lint(code)) + .containsExactly( + LintError(3, 1, "indent", "Unexpected indentation (12) (should be 8)"), + ) + assertThat(IndentationRule().format(code)).isEqualTo(formattedCode) + } + + @Test + fun `Issue 1222 - format class constructor, parameter of super invocations are indented`() { + val code = + """ + class Issue1222 { + constructor(string1: String, string2: String2) : + super( + string1, string2 + ) { + // do something + } + } + """.trimIndent() + val formattedCode = + """ + class Issue1222 { + constructor(string1: String, string2: String2) : + super( + string1, string2 + ) { + // do something + } + } + """.trimIndent() + assertThat(IndentationRule().lint(code)) + .containsExactly( + LintError(4, 1, "indent", "Unexpected indentation (8) (should be 12)"), + ) + assertThat(IndentationRule().format(code)).isEqualTo(formattedCode) + } + private companion object { const val MULTILINE_STRING_QUOTE = "${'"'}${'"'}${'"'}" const val TAB = "${'\t'}"