Skip to content

Commit

Permalink
Do not merge an annotated expression body with the function signature…
Browse files Browse the repository at this point in the history
… even if it fits on a single line (#2049)

Closes #2043
  • Loading branch information
paul-dingemans committed May 21, 2023
1 parent 55bab3d commit 9d4a168
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
### Fixed

* Do not flag a (potential) mutable extension property in case the getter is annotated or prefixed with a modifier `property-naming` ([#2024](https://github.com/pinterest/ktlint/issues/2024))
* Do not merge an annotated expression body with the function signature even if it fits on a single line ([#2043](https://github.com/pinterest/ktlint/issues/2043))

### Changed

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.pinterest.ktlint.ruleset.standard.rules

import com.pinterest.ktlint.rule.engine.core.api.ElementType.ANNOTATED_EXPRESSION
import com.pinterest.ktlint.rule.engine.core.api.ElementType.ANNOTATION
import com.pinterest.ktlint.rule.engine.core.api.ElementType.ANNOTATION_ENTRY
import com.pinterest.ktlint.rule.engine.core.api.ElementType.BLOCK
Expand Down Expand Up @@ -540,6 +541,13 @@ public class FunctionSignatureRule :
.firstOrNull()
?.also { firstLineOfBodyExpression ->
if (whiteSpaceBeforeFunctionBodyExpression.isWhiteSpaceWithNewline()) {
lastNodeOfFunctionSignatureWithBodyExpression
.nextCodeSibling()
.takeIf { it?.elementType == ANNOTATED_EXPRESSION }
?.let {
// Never merge an annotated expression body with function signature as this conflicts with the Annotation rule
return
}
val mergeWithFunctionSignature =
if (firstLineOfBodyExpression.length < maxLengthRemainingForFirstLineOfBodyExpression) {
functionBodyExpressionWrapping == default ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import com.pinterest.ktlint.rule.engine.core.api.editorconfig.CodeStyleValue.ktl
import com.pinterest.ktlint.rule.engine.core.api.editorconfig.ec4j.toPropertyWithValue
import com.pinterest.ktlint.ruleset.standard.rules.FunctionSignatureRule.Companion.FORCE_MULTILINE_WHEN_PARAMETER_COUNT_GREATER_OR_EQUAL_THAN_PROPERTY
import com.pinterest.ktlint.ruleset.standard.rules.FunctionSignatureRule.Companion.FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY
import com.pinterest.ktlint.ruleset.standard.rules.FunctionSignatureRule.FunctionBodyExpressionWrapping
import com.pinterest.ktlint.ruleset.standard.rules.FunctionSignatureRule.FunctionBodyExpressionWrapping.default
import com.pinterest.ktlint.test.KtLintAssertThat.Companion.EOL_CHAR
import com.pinterest.ktlint.test.KtLintAssertThat.Companion.MAX_LINE_LENGTH_MARKER
import com.pinterest.ktlint.test.KtLintAssertThat.Companion.assertThatRule
Expand Down Expand Up @@ -671,11 +673,11 @@ class FunctionSignatureRuleTest {
inner class BodyExpressionOnSameLine {
@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.FunctionBodyExpressionWrapping::class,
value = FunctionBodyExpressionWrapping::class,
names = ["default", "multiline"],
)
fun `Given that the function signature and a single line body expression body fit on the same line then do not reformat function signature or body expression`(
bodyExpressionWrapping: FunctionSignatureRule.FunctionBodyExpressionWrapping,
bodyExpressionWrapping: FunctionBodyExpressionWrapping,
) {
val code =
"""
Expand All @@ -690,11 +692,11 @@ class FunctionSignatureRuleTest {

@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.FunctionBodyExpressionWrapping::class,
value = FunctionBodyExpressionWrapping::class,
names = ["always"],
)
fun `Given that the function signature and a single line body expression body fit on the same line then do not reformat function signature but move the body expression to a separate line`(
bodyExpressionWrapping: FunctionSignatureRule.FunctionBodyExpressionWrapping,
bodyExpressionWrapping: FunctionBodyExpressionWrapping,
) {
val code =
"""
Expand All @@ -717,11 +719,11 @@ class FunctionSignatureRuleTest {

@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.FunctionBodyExpressionWrapping::class,
value = FunctionBodyExpressionWrapping::class,
names = ["multiline", "always"],
)
fun `Given that the function signature and first line of a multiline body expression body fit on the same line then do not reformat the function signature, move the body expression to a separate line`(
bodyExpressionWrapping: FunctionSignatureRule.FunctionBodyExpressionWrapping,
bodyExpressionWrapping: FunctionBodyExpressionWrapping,
) {
val code =
"""
Expand Down Expand Up @@ -750,11 +752,11 @@ class FunctionSignatureRuleTest {
inner class BodyExpressionOnSeparateLine {
@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.FunctionBodyExpressionWrapping::class,
value = FunctionBodyExpressionWrapping::class,
names = ["default", "multiline"],
)
fun `Given that the function signature and a single line body expression body fit on the same line then do reformat as single line signature`(
bodyExpressionWrapping: FunctionSignatureRule.FunctionBodyExpressionWrapping,
bodyExpressionWrapping: FunctionBodyExpressionWrapping,
) {
val code =
"""
Expand Down Expand Up @@ -784,11 +786,11 @@ class FunctionSignatureRuleTest {

@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.FunctionBodyExpressionWrapping::class,
value = FunctionBodyExpressionWrapping::class,
names = ["default", "multiline", "always"],
)
fun `Given that the function signature and first line of a multi line body expression body do not fit on the same line then do reformat`(
bodyExpressionWrapping: FunctionSignatureRule.FunctionBodyExpressionWrapping,
bodyExpressionWrapping: FunctionBodyExpressionWrapping,
) {
val code =
"""
Expand Down Expand Up @@ -818,11 +820,11 @@ class FunctionSignatureRuleTest {

@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.FunctionBodyExpressionWrapping::class,
value = FunctionBodyExpressionWrapping::class,
names = ["multiline", "always"],
)
fun `Given that the function signature and the first line of a multi line body expression body fit on the same line then reformat to single line signature but keep body expression on separate line`(
bodyExpressionWrapping: FunctionSignatureRule.FunctionBodyExpressionWrapping,
bodyExpressionWrapping: FunctionBodyExpressionWrapping,
) {
val code =
"""
Expand Down Expand Up @@ -854,11 +856,11 @@ class FunctionSignatureRuleTest {

@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.FunctionBodyExpressionWrapping::class,
value = FunctionBodyExpressionWrapping::class,
names = ["default"],
)
fun `Given that the function signature and first line of a multiline body expression body fit on the same line then do reformat as single line signature`(
bodyExpressionWrapping: FunctionSignatureRule.FunctionBodyExpressionWrapping,
bodyExpressionWrapping: FunctionBodyExpressionWrapping,
) {
val code =
"""
Expand Down Expand Up @@ -890,11 +892,11 @@ class FunctionSignatureRuleTest {

@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.FunctionBodyExpressionWrapping::class,
value = FunctionBodyExpressionWrapping::class,
names = ["always"],
)
fun `Given that the function signature and first line of a multiline body expression body fit on the same line then do reformat as single line signature, keep the body expression on a separate line`(
bodyExpressionWrapping: FunctionSignatureRule.FunctionBodyExpressionWrapping,
bodyExpressionWrapping: FunctionBodyExpressionWrapping,
) {
val code =
"""
Expand Down Expand Up @@ -927,10 +929,10 @@ class FunctionSignatureRuleTest {

@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.FunctionBodyExpressionWrapping::class,
value = FunctionBodyExpressionWrapping::class,
)
fun `Given a multiline function signature without explicit return type and start of body expression on next line then keep first line of body expression body on the same line as the last line of the function signature`(
bodyExpressionWrapping: FunctionSignatureRule.FunctionBodyExpressionWrapping,
bodyExpressionWrapping: FunctionBodyExpressionWrapping,
) {
val code =
"""
Expand Down Expand Up @@ -961,10 +963,10 @@ class FunctionSignatureRuleTest {

@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.FunctionBodyExpressionWrapping::class,
value = FunctionBodyExpressionWrapping::class,
)
fun `Given a multiline function signature without explicit return type and start of body expression on same line as last line of function signature then do not reformat`(
bodyExpressionWrapping: FunctionSignatureRule.FunctionBodyExpressionWrapping,
bodyExpressionWrapping: FunctionBodyExpressionWrapping,
) {
val code =
"""
Expand Down Expand Up @@ -1244,6 +1246,23 @@ class FunctionSignatureRuleTest {
.hasNoLintViolations()
}

@Test
fun `Issue 2043 - Given a function signature with an expression body that is an annotated expression then do not reformat to single line function signature`() {
val code =
"""
// $MAX_LINE_LENGTH_MARKER $EOL_CHAR
fun foo1(bar: String): String =
@Bar
bar
fun foo2(bar: String): String =
@Bar bar
""".trimIndent()
functionSignatureWrappingRuleAssertThat(code)
.setMaxLineLength()
.withEditorConfigOverride(FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY to default)
.hasNoLintViolations()
}

private companion object {
const val UNEXPECTED_SPACES = " "
const val NO_SPACE = ""
Expand Down

0 comments on commit 9d4a168

Please sign in to comment.