diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cbd71949a..de4f960e9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ An AssertJ style API for testing KtLint rules ([#1444](https://github.com/pinter - Add experimental rule for consistent spacing before the start of the function body (`function-start-of-body-spacing`) ([#1341](https://github.com/pinterest/ktlint/issues/1341)) ### Fixed +- Fix check of spacing in the receiver type of an anonymous function ([#1440](https://github.com/pinterest/ktlint/issues/1440)) ### Changed * Set Kotlin development version to `1.6.21` and Kotlin version to `1.6.21`. diff --git a/ktlint-ruleset-experimental/src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/FunctionTypeReferenceSpacingRule.kt b/ktlint-ruleset-experimental/src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/FunctionTypeReferenceSpacingRule.kt index 4955b11fa8..ce7bacb00b 100644 --- a/ktlint-ruleset-experimental/src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/FunctionTypeReferenceSpacingRule.kt +++ b/ktlint-ruleset-experimental/src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/FunctionTypeReferenceSpacingRule.kt @@ -2,9 +2,9 @@ package com.pinterest.ktlint.ruleset.experimental import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.ast.ElementType.FUN -import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER import com.pinterest.ktlint.core.ast.ElementType.NULLABLE_TYPE import com.pinterest.ktlint.core.ast.ElementType.TYPE_REFERENCE +import com.pinterest.ktlint.core.ast.ElementType.VALUE_PARAMETER_LIST import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE import com.pinterest.ktlint.core.ast.nextSibling import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -17,26 +17,26 @@ public class FunctionTypeReferenceSpacingRule : Rule("function-type-reference-sp ) { if (node.elementType == FUN) { node - .findTypeReferenceBeforeFunctionIdentifier() + .findFunctionReceiverTypeReference() ?.let { typeReference -> typeReference .firstChildNode .takeIf { it.elementType == NULLABLE_TYPE } ?.let { nullableTypeElement -> - visitNodesUntilIdentifier(nullableTypeElement.firstChildNode, emit, autoCorrect) + visitNodesUntilStartOfValueParameterList(nullableTypeElement.firstChildNode, emit, autoCorrect) } if (typeReference.elementType != NULLABLE_TYPE) { - visitNodesUntilIdentifier(typeReference, emit, autoCorrect) + visitNodesUntilStartOfValueParameterList(typeReference, emit, autoCorrect) } } } } - private fun ASTNode.findTypeReferenceBeforeFunctionIdentifier(): ASTNode? { + private fun ASTNode.findFunctionReceiverTypeReference(): ASTNode? { require(elementType == FUN) var currentNode: ASTNode? = firstChildNode - while (currentNode != null && currentNode.elementType != IDENTIFIER) { + while (currentNode != null && currentNode.elementType != VALUE_PARAMETER_LIST) { if (currentNode.elementType == TYPE_REFERENCE) { return currentNode } @@ -45,13 +45,13 @@ public class FunctionTypeReferenceSpacingRule : Rule("function-type-reference-sp return null } - private fun visitNodesUntilIdentifier( + private fun visitNodesUntilStartOfValueParameterList( node: ASTNode, emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit, autoCorrect: Boolean ) { var currentNode: ASTNode? = node - while (currentNode != null && currentNode.elementType != IDENTIFIER) { + while (currentNode != null && currentNode.elementType != VALUE_PARAMETER_LIST) { val nextNode = currentNode.nextSibling { true } removeIfNonEmptyWhiteSpace(currentNode, emit, autoCorrect) currentNode = nextNode diff --git a/ktlint-ruleset-experimental/src/test/kotlin/com/pinterest/ktlint/ruleset/experimental/FunctionTypeReferenceSpacingRuleTest.kt b/ktlint-ruleset-experimental/src/test/kotlin/com/pinterest/ktlint/ruleset/experimental/FunctionTypeReferenceSpacingRuleTest.kt index fbcbe0e93d..bbc360827f 100644 --- a/ktlint-ruleset-experimental/src/test/kotlin/com/pinterest/ktlint/ruleset/experimental/FunctionTypeReferenceSpacingRuleTest.kt +++ b/ktlint-ruleset-experimental/src/test/kotlin/com/pinterest/ktlint/ruleset/experimental/FunctionTypeReferenceSpacingRuleTest.kt @@ -75,4 +75,40 @@ class FunctionTypeReferenceSpacingRuleTest { """.trimIndent() functionTypeReferenceSpacingRuleAssertThat(code).hasNoLintViolations() } + + @Test + fun `Issue 1440 - Given an anonymous function without receiver type then do not reformat`() { + val code = + """ + val anonymousFunction = fun(foo: Boolean): String? = if (foo) "Test string" else null + """.trimIndent() + functionTypeReferenceSpacingRuleAssertThat(code).hasNoLintViolations() + } + + @Test + fun `Given an anonymous function with receiver type then do not reformat`() { + val code = + """ + val anonymousFunction = fun Boolean.(): String? = if (this) "Test string" else null + """.trimIndent() + functionTypeReferenceSpacingRuleAssertThat(code).hasNoLintViolations() + } + + @Test + fun `Given an anonymous function with receiver type followed by an unexpected space then do reformat`() { + val code = + """ + val anonymousFunction = fun Boolean ? . (): String? = this?.let { "Test string" } + """.trimIndent() + val formattedCode = + """ + val anonymousFunction = fun Boolean?.(): String? = this?.let { "Test string" } + """.trimIndent() + functionTypeReferenceSpacingRuleAssertThat(code) + .hasLintViolations( + LintViolation(1, 36, "Unexpected whitespace"), + LintViolation(1, 38, "Unexpected whitespace"), + LintViolation(1, 40, "Unexpected whitespace") + ).isFormattedAs(formattedCode) + } }