Skip to content

Commit 64dfcba

Browse files
Prevent conflict between multiline-expression-wrapping and function-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
1 parent b898462 commit 64dfcba

File tree

3 files changed

+26
-0
lines changed

3 files changed

+26
-0
lines changed

documentation/snapshot/docs/rules/standard.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4454,6 +4454,8 @@ Suppress or disable rule (1)
44544454

44554455
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.
44564456

4457+
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.
4458+
44574459
=== "[:material-heart:](#) Ktlint"
44584460

44594461
```kotlin

ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrappingRule.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ import com.pinterest.ktlint.rule.engine.core.api.prevCodeSibling
5050
import com.pinterest.ktlint.rule.engine.core.api.prevLeaf
5151
import com.pinterest.ktlint.rule.engine.core.api.upsertWhitespaceBeforeMe
5252
import com.pinterest.ktlint.ruleset.standard.StandardRule
53+
import com.pinterest.ktlint.ruleset.standard.rules.FunctionSignatureRule.Companion.FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY
54+
import com.pinterest.ktlint.ruleset.standard.rules.FunctionSignatureRule.FunctionBodyExpressionWrapping.default
5355
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
5456

5557
/**
@@ -64,17 +66,20 @@ public class MultilineExpressionWrappingRule :
6466
setOf(
6567
INDENT_SIZE_PROPERTY,
6668
INDENT_STYLE_PROPERTY,
69+
FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY,
6770
),
6871
),
6972
Rule.OfficialCodeStyle {
7073
private var indentConfig = DEFAULT_INDENT_CONFIG
74+
private lateinit var functionBodyExpressionWrapping: FunctionSignatureRule.FunctionBodyExpressionWrapping
7175

7276
override fun beforeFirstNode(editorConfig: EditorConfig) {
7377
indentConfig =
7478
IndentConfig(
7579
indentStyle = editorConfig[INDENT_STYLE_PROPERTY],
7680
tabWidth = editorConfig[INDENT_SIZE_PROPERTY],
7781
)
82+
functionBodyExpressionWrapping = editorConfig[FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY]
7883
}
7984

8085
override fun beforeVisitChildNodes(
@@ -172,6 +177,7 @@ public class MultilineExpressionWrappingRule :
172177
null !=
173178
prevCodeSibling()
174179
?.takeIf { it.elementType == EQ || it.elementType == OPERATION_REFERENCE }
180+
?.takeUnless { functionBodyExpressionWrapping == default && it.treeParent.elementType == FUN }
175181
?.takeUnless { it.isElvisOperator() }
176182
?.takeUnless {
177183
it

ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrappingRuleTest.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package com.pinterest.ktlint.ruleset.standard.rules
22

33
import com.pinterest.ktlint.rule.engine.core.api.editorconfig.CODE_STYLE_PROPERTY
44
import com.pinterest.ktlint.rule.engine.core.api.editorconfig.CodeStyleValue
5+
import com.pinterest.ktlint.ruleset.standard.rules.FunctionSignatureRule.Companion.FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY
6+
import com.pinterest.ktlint.ruleset.standard.rules.FunctionSignatureRule.FunctionBodyExpressionWrapping.default
57
import com.pinterest.ktlint.test.KtLintAssertThat
68
import com.pinterest.ktlint.test.LintViolation
79
import com.pinterest.ktlint.test.MULTILINE_STRING_QUOTE
@@ -360,6 +362,22 @@ class MultilineExpressionWrappingRuleTest {
360362
.isFormattedAs(formattedCode)
361363
}
362364

365+
@Test
366+
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)`() {
367+
val code =
368+
"""
369+
fun foo() = bar(
370+
"bar"
371+
)
372+
""".trimIndent()
373+
multilineExpressionWrappingRuleAssertThat(code)
374+
.addAdditionalRuleProvider { IndentationRule() }
375+
.addAdditionalRuleProvider { FunctionSignatureRule() }
376+
.withEditorConfigOverride(CODE_STYLE_PROPERTY to CodeStyleValue.ktlint_official)
377+
.withEditorConfigOverride(FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY to default)
378+
.hasNoLintViolations()
379+
}
380+
363381
@Test
364382
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`() {
365383
val code =

0 commit comments

Comments
 (0)