diff --git a/CHANGELOG.md b/CHANGELOG.md index 7139e7ca4d..e591cb82d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Fixed - Fix false positive in rule spacing-between-declarations-with-annotations ([#1281](https://github.com/pinterest/ktlint/issues/1281)) - Fix NoSuchElementException for property accessor (`trailing-comma`) ([#1280](https://github.com/pinterest/ktlint/issues/1280)) +- 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..95b157f3dd 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 += 2 + debug { "++after(COLON IN CONSTRUCTOR) -> $expectedIndent" } + val returnType = n.nextCodeSibling() + ctx.exitAdjBy(returnType!!, -2) + } + 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..8717a392f0 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,66 @@ 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 (8) (should be 12)"), + ) + 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(3, 1, "indent", "Unexpected indentation (8) (should be 12)"), + LintError(4, 1, "indent", "Unexpected indentation (8) (should be 16)"), + LintError(5, 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'}"