Skip to content

Commit

Permalink
Prevent conflict between multiline-expression-wrapping and `functio…
Browse files Browse the repository at this point in the history
…n-signature` (#2775)

When `function-signature` rule is configured with `ktlint_function_signature_body_expression_wrapping` set to `default` then the first line of a multiline expression body should be kept on the same line as the end of function signature, as long as max line length is not exceeded. In this case the `multiline-expression-wrapping` rule has to ignore the multiline function expression body.

Closes #2650
  • Loading branch information
paul-dingemans authored Aug 28, 2024
1 parent b898462 commit 64dfcba
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 0 deletions.
2 changes: 2 additions & 0 deletions documentation/snapshot/docs/rules/standard.md
Original file line number Diff line number Diff line change
Expand Up @@ -4454,6 +4454,8 @@ Suppress or disable rule (1)

Multiline expression on the right hand side of an expression are forced to start on a separate line. Expressions in return statement are excluded as that would result in a compilation error.

Setting `ktlint_function_signature_body_expression_wrapping` of the `function-signature` rule takes precedence when set to `default`. This setting keeps the first line of a multiline expression body on the same line as the end of function signature as long as the max line length is not exceeded. In that case, this rule does not wrap the multiline expression.

=== "[:material-heart:](#) Ktlint"

```kotlin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ import com.pinterest.ktlint.rule.engine.core.api.prevCodeSibling
import com.pinterest.ktlint.rule.engine.core.api.prevLeaf
import com.pinterest.ktlint.rule.engine.core.api.upsertWhitespaceBeforeMe
import com.pinterest.ktlint.ruleset.standard.StandardRule
import com.pinterest.ktlint.ruleset.standard.rules.FunctionSignatureRule.Companion.FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY
import com.pinterest.ktlint.ruleset.standard.rules.FunctionSignatureRule.FunctionBodyExpressionWrapping.default
import org.jetbrains.kotlin.com.intellij.lang.ASTNode

/**
Expand All @@ -64,17 +66,20 @@ public class MultilineExpressionWrappingRule :
setOf(
INDENT_SIZE_PROPERTY,
INDENT_STYLE_PROPERTY,
FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY,
),
),
Rule.OfficialCodeStyle {
private var indentConfig = DEFAULT_INDENT_CONFIG
private lateinit var functionBodyExpressionWrapping: FunctionSignatureRule.FunctionBodyExpressionWrapping

override fun beforeFirstNode(editorConfig: EditorConfig) {
indentConfig =
IndentConfig(
indentStyle = editorConfig[INDENT_STYLE_PROPERTY],
tabWidth = editorConfig[INDENT_SIZE_PROPERTY],
)
functionBodyExpressionWrapping = editorConfig[FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY]
}

override fun beforeVisitChildNodes(
Expand Down Expand Up @@ -172,6 +177,7 @@ public class MultilineExpressionWrappingRule :
null !=
prevCodeSibling()
?.takeIf { it.elementType == EQ || it.elementType == OPERATION_REFERENCE }
?.takeUnless { functionBodyExpressionWrapping == default && it.treeParent.elementType == FUN }
?.takeUnless { it.isElvisOperator() }
?.takeUnless {
it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.pinterest.ktlint.ruleset.standard.rules

import com.pinterest.ktlint.rule.engine.core.api.editorconfig.CODE_STYLE_PROPERTY
import com.pinterest.ktlint.rule.engine.core.api.editorconfig.CodeStyleValue
import com.pinterest.ktlint.ruleset.standard.rules.FunctionSignatureRule.Companion.FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY
import com.pinterest.ktlint.ruleset.standard.rules.FunctionSignatureRule.FunctionBodyExpressionWrapping.default
import com.pinterest.ktlint.test.KtLintAssertThat
import com.pinterest.ktlint.test.LintViolation
import com.pinterest.ktlint.test.MULTILINE_STRING_QUOTE
Expand Down Expand Up @@ -360,6 +362,22 @@ class MultilineExpressionWrappingRuleTest {
.isFormattedAs(formattedCode)
}

@Test
fun `Given a function with a multiline body expression, and the function signature body expression wrapping is set to 'default' (eg keep first line of expression on same line)`() {
val code =
"""
fun foo() = bar(
"bar"
)
""".trimIndent()
multilineExpressionWrappingRuleAssertThat(code)
.addAdditionalRuleProvider { IndentationRule() }
.addAdditionalRuleProvider { FunctionSignatureRule() }
.withEditorConfigOverride(CODE_STYLE_PROPERTY to CodeStyleValue.ktlint_official)
.withEditorConfigOverride(FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY to default)
.hasNoLintViolations()
}

@Test
fun `Given a function with a multiline signature without a return type but with a multiline expression body starting on same line as closing parenthesis of function`() {
val code =
Expand Down

0 comments on commit 64dfcba

Please sign in to comment.