Skip to content

Commit

Permalink
Merge first line of body expression with function signature only when…
Browse files Browse the repository at this point in the history
… it fits on the same line

Closes pinterest#1527
  • Loading branch information
paul-dingemans committed Aug 2, 2022
1 parent e0693a0 commit b9fd617
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -126,6 +126,7 @@ The callback function provided as parameter to the format function is now called
* When a glob is specified then ensure that it matches files in the current directory and not only in subdirectories of the current directory ([#1533](https://github.com/pinterest/ktlint/issue/1533)).
* Execute `ktlint` cli on default kotlin extensions only when an (existing) path to a directory is given. ([#917](https://github.com/pinterest/ktlint/issue/917)).
* Invoke callback on `format` function for all errors including errors that are autocorrected ([#1491](https://github.com/pinterest/ktlint/issues/1491))
* Merge first line of body expression with function signature only when it fits on the same line `function-signature` ([#1527](https://github.com/pinterest/ktlint/issues/1527))


### Changed
Expand Down
Expand Up @@ -522,8 +522,11 @@ public class FunctionSignatureRule :
.firstOrNull()
?.also { firstLineOfBodyExpression ->
if (whiteSpaceBeforeFunctionBodyExpression.isWhiteSpaceWithNewline()) {
if (functionBodyExpressionWrapping == default ||
(functionBodyExpressionWrapping == multiline && functionBodyExpressionLines.size == 1) ||
val mergeWithFunctionSignature =
functionBodyExpressionWrapping.keepFirstLineOfBodyExpressionTogetherWithFunctionSignature(
firstLineOfBodyExpression.length < maxLengthRemainingForFirstLineOfBodyExpression
)
if (mergeWithFunctionSignature ||
node.isMultilineFunctionSignatureWithoutExplicitReturnType(lastNodeOfFunctionSignatureWithBodyExpression)
) {
emit(
Expand Down Expand Up @@ -754,5 +757,12 @@ public class FunctionSignatureRule :
* Always force the body expression to start on a separate line.
*/
always;

internal fun keepFirstLineOfBodyExpressionTogetherWithFunctionSignature(fitOnSameLine: Boolean) =
if (this == default || this == multiline) {
fitOnSameLine
} else {
false
}
}
}
Expand Up @@ -786,12 +786,46 @@ class FunctionSignatureRuleTest {
).isFormattedAs(formattedCode)
}

@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.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
) {
val code =
"""
// $MAX_LINE_LENGTH_MARKER $EOL_CHAR
fun f(
a: Any,
b: Any
): String = "some-result"
""".trimIndent()
val formattedCode =
"""
// $MAX_LINE_LENGTH_MARKER $EOL_CHAR
fun f(a: Any, b: Any): String =
"some-result"
""".trimIndent()
functionSignatureWrappingRuleAssertThat(code)
.setMaxLineLength()
.withEditorConfigOverride(functionBodyExpressionWrappingProperty to bodyExpressionWrapping)
.addAdditionalRuleProvider { IndentationRule() }
.hasLintViolations(
LintViolation(3, 5, "No whitespace expected between opening parenthesis and first parameter name"),
LintViolation(4, 5, "Single whitespace expected before parameter"),
LintViolation(4, 11, "No whitespace expected between last parameter and closing parenthesis"),
LintViolation(5, 13, "Newline expected before expression body")
).isFormattedAs(formattedCode)
}

@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.FunctionBodyExpressionWrapping::class,
names = ["always"]
)
fun `Given that the function signature and a single line body expression body fit on the same line then reformat to single line signature but keep body expression on a separate line`(
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
) {
val code =
Expand All @@ -802,12 +836,14 @@ class FunctionSignatureRuleTest {
b: Any
): String =
"some-result"
.trim()
""".trimIndent()
val formattedCode =
"""
// $MAX_LINE_LENGTH_MARKER $EOL_CHAR
fun f(a: Any, b: Any): String =
"some-result"
.trim()
""".trimIndent()
functionSignatureWrappingRuleAssertThat(code)
.setMaxLineLength()
Expand All @@ -823,7 +859,7 @@ class FunctionSignatureRuleTest {
@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.FunctionBodyExpressionWrapping::class,
names = ["default"]
names = ["default", "multiline"]
)
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
Expand Down Expand Up @@ -859,7 +895,7 @@ class FunctionSignatureRuleTest {
@ParameterizedTest(name = "bodyExpressionWrapping: {0}")
@EnumSource(
value = FunctionSignatureRule.FunctionBodyExpressionWrapping::class,
names = ["multiline", "always"]
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
Expand Down Expand Up @@ -897,7 +933,7 @@ class FunctionSignatureRuleTest {
@EnumSource(
value = FunctionSignatureRule.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 og the function signature`(
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
) {
val code =
Expand Down Expand Up @@ -996,6 +1032,19 @@ class FunctionSignatureRuleTest {
).isFormattedAs(formattedCode)
}

@Test
fun `Issue 1527 - Given a function signature with an expression body which does not fit on the same line as the signature then do not reformat`() {
val code =
"""
// $MAX_LINE_LENGTH_MARKER $EOL_CHAR
fun foo(bar: String) =
"some-result"
""".trimIndent()
functionSignatureWrappingRuleAssertThat(code)
.setMaxLineLength()
.hasNoLintViolations()
}

private companion object {
const val EOL_CHAR = '#'
const val UNEXPECTED_SPACES = " "
Expand Down

0 comments on commit b9fd617

Please sign in to comment.