Skip to content

Commit 52ecb3f

Browse files
Do not wrap a context receiver in a function parameter type reference (#2892)
Closes #2854
1 parent 1bc924c commit 52ecb3f

File tree

4 files changed

+39
-7
lines changed

4 files changed

+39
-7
lines changed

documentation/release-latest/docs/rules/standard.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4343,9 +4343,9 @@ Suppress or disable rule (1)
43434343
ktlint_standard_condition-wrapping = disabled
43444344
```
43454345

4346-
### Content receiver wrapping
4346+
### Context receiver wrapping
43474347

4348-
Wraps the content receiver list to a separate line regardless of maximum line length. If the maximum line length is configured and is exceeded, wrap the context receivers and if needed its projection types to separate lines.
4348+
Wraps the context receiver list to a separate line regardless of maximum line length. If the maximum line length is configured and is exceeded, wrap the context receivers and if needed its projection types to separate lines.
43494349

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

documentation/snapshot/docs/rules/standard.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4343,9 +4343,9 @@ Suppress or disable rule (1)
43434343
ktlint_standard_condition-wrapping = disabled
43444344
```
43454345

4346-
### Content receiver wrapping
4346+
### Context receiver wrapping
43474347

4348-
Wraps the content receiver list to a separate line regardless of maximum line length. If the maximum line length is configured and is exceeded, wrap the context receivers and if needed its projection types to separate lines.
4348+
Wraps the context receiver list of a function to a separate line regardless of maximum line length. If the maximum line length is configured and is exceeded, wrap the context receivers and if needed its projection types to separate lines.
43494349

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

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

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@ package com.pinterest.ktlint.ruleset.standard.rules
33
import com.pinterest.ktlint.rule.engine.core.api.AutocorrectDecision
44
import com.pinterest.ktlint.rule.engine.core.api.ElementType.CONTEXT_RECEIVER
55
import com.pinterest.ktlint.rule.engine.core.api.ElementType.CONTEXT_RECEIVER_LIST
6+
import com.pinterest.ktlint.rule.engine.core.api.ElementType.FUN
7+
import com.pinterest.ktlint.rule.engine.core.api.ElementType.FUNCTION_TYPE
68
import com.pinterest.ktlint.rule.engine.core.api.ElementType.GT
79
import com.pinterest.ktlint.rule.engine.core.api.ElementType.RPAR
810
import com.pinterest.ktlint.rule.engine.core.api.ElementType.TYPE_ARGUMENT_LIST
911
import com.pinterest.ktlint.rule.engine.core.api.ElementType.TYPE_PROJECTION
12+
import com.pinterest.ktlint.rule.engine.core.api.ElementType.TYPE_REFERENCE
13+
import com.pinterest.ktlint.rule.engine.core.api.ElementType.VALUE_PARAMETER
14+
import com.pinterest.ktlint.rule.engine.core.api.ElementType.VALUE_PARAMETER_LIST
1015
import com.pinterest.ktlint.rule.engine.core.api.IndentConfig
1116
import com.pinterest.ktlint.rule.engine.core.api.IndentConfig.Companion.DEFAULT_INDENT_CONFIG
1217
import com.pinterest.ktlint.rule.engine.core.api.RuleId
@@ -80,10 +85,11 @@ public class ContextReceiverWrappingRule :
8085
node: ASTNode,
8186
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> AutocorrectDecision,
8287
) {
83-
// Context receiver must be followed by new line or comment
88+
// Context receiver must be followed by new line or comment unless it is a type reference of a parameter
8489
node
85-
.lastChildLeafOrSelf()
86-
.nextLeaf { !it.isWhiteSpaceWithoutNewline() && !it.isPartOfComment() }
90+
.takeUnless { it.isTypeReferenceParameterInFunction() }
91+
?.lastChildLeafOrSelf()
92+
?.nextLeaf { !it.isWhiteSpaceWithoutNewline() && !it.isPartOfComment() }
8793
?.takeIf { !it.isWhiteSpaceWithNewline() }
8894
?.let { nodeAfterContextReceiver ->
8995
emit(nodeAfterContextReceiver.startOffset, "Expected a newline after the context receiver", true)
@@ -126,6 +132,20 @@ public class ContextReceiverWrappingRule :
126132
}
127133
}
128134

135+
private fun ASTNode.isTypeReferenceParameterInFunction() =
136+
takeIf { it.elementType == CONTEXT_RECEIVER_LIST }
137+
?.treeParent
138+
?.takeIf { it.elementType == FUNCTION_TYPE }
139+
?.treeParent
140+
?.takeIf { it.elementType == TYPE_REFERENCE }
141+
?.treeParent
142+
?.takeIf { it.elementType == VALUE_PARAMETER }
143+
?.treeParent
144+
?.takeIf { it.elementType == VALUE_PARAMETER_LIST }
145+
?.treeParent
146+
?.let { it.elementType == FUN }
147+
?: false
148+
129149
private fun visitContextReceiverTypeArgumentList(
130150
node: ASTNode,
131151
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> AutocorrectDecision,

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,4 +199,16 @@ class ContextReceiverWrappingRuleTest {
199199
LintViolation(2, 36, "Newline expected before closing parenthesis as max line length is violated"),
200200
).isFormattedAs(formattedCode)
201201
}
202+
203+
@Test
204+
fun `Issue 2854 - Given a function parameter with a context receiver then do not wrap after the context receiver`() {
205+
val code =
206+
"""
207+
fun bar1(foo: context(Foo) () -> Unit = { foobar() }) {}
208+
fun bar2(
209+
foo: context(Foo) () -> Unit = { foobar() }
210+
) {}
211+
""".trimIndent()
212+
contextReceiverWrappingRuleAssertThat(code).hasNoLintViolations()
213+
}
202214
}

0 commit comments

Comments
 (0)