Skip to content

Commit d4ad6b6

Browse files
authored
Extract new rule no-blank-lines-in-chained-method-calls from no-consecutive-blank-lines (#1469, #1248)
The 'no-consecutive-blank-lines' rule no longer disallows a single blank line in a chained method call. Multiple consecutive blank lines are still prohibited. The new rule 'no-blank-lines-in-chained-method-calls' also prohibits single blank lines in chained method call. Closes #1248
1 parent c083a97 commit d4ad6b6

File tree

7 files changed

+102
-17
lines changed

7 files changed

+102
-17
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ An AssertJ style API for testing KtLint rules ([#1444](https://github.com/pinter
2323
- Add experimental rule for rewriting the function signature (`function-signature`) ([#1341](https://github.com/pinterest/ktlint/issues/1341))
2424

2525
### Fixed
26+
- Move disallowing blank lines in chained method calls from `no-consecutive-blank-lines` to new rule (`no-blank-lines-in-chained-method-calls`) ([#1248](https://github.com/pinterest/ktlint/issues/1248))
2627
- Fix check of spacing in the receiver type of an anonymous function ([#1440](https://github.com/pinterest/ktlint/issues/1440))
2728
- Allow comment on same line as super class in class declaration `wrapping` ([#1457](https://github.com/pinterest/ktlint/pull/1457))
2829
- Fix formatting of a property delegate with a dot-qualified-expression `indent` ([#1340](https://github.com/pinterest/ktlint/ssues/1340))

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ It's also [easy to create your own](#creating-a-reporter).
4040
- `max-line-length`: Ensures that lines do not exceed the given length of `.editorconfig` property `max_line_length` (see [EditorConfig](#editorconfig) section for more). This rule does not apply in a number of situations. For example, in the case a line exceeds the maximum line length due to and comment that disables ktlint rules than that comment is being ignored when validating the length of the line. The `.editorconfig` property `ktlint_ignore_back_ticked_identifier` can be set to ignore identifiers which are enclosed in backticks, which for example is very useful when you want to allow longer names for unit tests.
4141
- `modifier-order`: Consistent order of modifiers
4242
- `no-blank-line-before-rbrace`: No blank lines before `}`
43+
- `no-blank-lines-in-chained-method-calls`: No blank lines in chained method expressions
4344
- `no-consecutive-blank-lines`: No consecutive blank lines
4445
- `no-empty-class-body`: No empty (`{}`) class bodies
4546
- `no-line-break-after-else`: Disallows line breaks after the else keyword if that could lead to confusion, for example:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.pinterest.ktlint.ruleset.standard
2+
3+
import com.pinterest.ktlint.core.Rule
4+
import com.pinterest.ktlint.core.ast.ElementType.DOT_QUALIFIED_EXPRESSION
5+
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
6+
import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace
7+
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
8+
9+
public class NoBlankLinesInChainedMethodCallsRule : Rule("no-blank-lines-in-chained-method-calls") {
10+
override fun visit(
11+
node: ASTNode,
12+
autoCorrect: Boolean,
13+
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit
14+
) {
15+
val isBlankLine = node is PsiWhiteSpace && node.getText().contains("\n\n")
16+
if (isBlankLine && node.treeParent.elementType == DOT_QUALIFIED_EXPRESSION) {
17+
emit(node.startOffset + 1, "Needless blank line(s)", true)
18+
19+
if (autoCorrect) {
20+
(node as LeafPsiElement).rawReplaceWithText("\n" + node.getText().split("\n\n")[1])
21+
}
22+
}
23+
}
24+
}

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package com.pinterest.ktlint.ruleset.standard
22

33
import com.pinterest.ktlint.core.Rule
44
import com.pinterest.ktlint.core.ast.ElementType.CLASS
5-
import com.pinterest.ktlint.core.ast.ElementType.DOT_QUALIFIED_EXPRESSION
65
import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER
76
import com.pinterest.ktlint.core.ast.ElementType.PRIMARY_CONSTRUCTOR
87
import com.pinterest.ktlint.core.ast.nextLeaf
@@ -25,20 +24,21 @@ public class NoConsecutiveBlankLinesRule : Rule("no-consecutive-blank-lines") {
2524
if (lfcount < 2) {
2625
return
2726
}
27+
2828
val eof = node.nextLeaf() == null
2929
val prevNode = node.treePrev
3030
val betweenClassAndPrimaryConstructor = prevNode.elementType == IDENTIFIER &&
3131
prevNode.treeParent.elementType == CLASS &&
3232
node.treeNext.elementType == PRIMARY_CONSTRUCTOR
33-
val inDotQualifiedExpression = node.treeParent.elementType == DOT_QUALIFIED_EXPRESSION && lfcount > 1
34-
if (lfcount > 2 || eof || betweenClassAndPrimaryConstructor || inDotQualifiedExpression) {
33+
34+
if (lfcount > 2 || eof || betweenClassAndPrimaryConstructor) {
3535
val split = text.split("\n")
3636
emit(node.startOffset + split[0].length + split[1].length + 2, "Needless blank line(s)", true)
3737
if (autoCorrect) {
3838
val newText = buildString {
3939
append(split.first())
4040
append("\n")
41-
if (!eof && !betweenClassAndPrimaryConstructor && !inDotQualifiedExpression) append("\n")
41+
if (!eof && !betweenClassAndPrimaryConstructor) append("\n")
4242
append(split.last())
4343
}
4444
(node as LeafPsiElement).rawReplaceWithText(newText)

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

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class StandardRuleSetProvider : RuleSetProvider {
1818
ModifierOrderRule(),
1919
NoBlankLineBeforeRbraceRule(),
2020
NoConsecutiveBlankLinesRule(),
21+
NoBlankLinesInChainedMethodCallsRule(),
2122
NoEmptyClassBodyRule(),
2223
NoLineBreakAfterElseRule(),
2324
NoLineBreakBeforeAssignmentRule(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.pinterest.ktlint.ruleset.standard
2+
3+
import com.pinterest.ktlint.test.KtLintAssertThat.Companion.assertThat
4+
import org.junit.jupiter.api.Test
5+
6+
class NoBlankLinesInChainedMethodCallsRuleTest {
7+
private val noBlankLinesInChainedMethodCallsRuleAssertThat = NoBlankLinesInChainedMethodCallsRule().assertThat()
8+
9+
@Test
10+
fun `single blank line in dot qualified expression returns lint error`() {
11+
val code =
12+
"""
13+
fun foo(inputText: String) {
14+
inputText
15+
16+
.toLowerCase()
17+
}
18+
""".trimIndent()
19+
val formattedCode =
20+
"""
21+
fun foo(inputText: String) {
22+
inputText
23+
.toLowerCase()
24+
}
25+
""".trimIndent()
26+
noBlankLinesInChainedMethodCallsRuleAssertThat(code)
27+
.hasLintViolation(3, 1, "Needless blank line(s)")
28+
.isFormattedAs(formattedCode)
29+
}
30+
31+
@Test
32+
fun `single blank line between statements does not return lint error`() {
33+
val code =
34+
"""
35+
fun foo(inputText: String) {
36+
bar()
37+
38+
bar()
39+
}
40+
""".trimIndent()
41+
noBlankLinesInChainedMethodCallsRuleAssertThat(code).hasNoLintViolations()
42+
}
43+
}

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

+28-13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.pinterest.ktlint.ruleset.standard
33
import com.pinterest.ktlint.test.KtLintAssertThat.Companion.assertThat
44
import com.pinterest.ktlint.test.LintViolation
55
import com.pinterest.ktlint.test.MULTILINE_STRING_QUOTE
6-
import com.pinterest.ktlint.test.format
76
import com.pinterest.ktlint.test.lint
87
import org.assertj.core.api.Assertions.assertThat
98
import org.junit.jupiter.api.Nested
@@ -176,25 +175,41 @@ class NoConsecutiveBlankLinesRuleTest {
176175
}
177176

178177
@Test
179-
fun `should remove line in dot qualified expression`() {
180-
assertThat(
181-
NoConsecutiveBlankLinesRule().format(
182-
"""
183-
fun foo(inputText: String) {
184-
inputText
178+
fun `Given single blank line in dot qualified expression should not return lint errors`() {
179+
val code =
180+
"""
181+
fun foo(inputText: String) {
182+
inputText
185183
184+
.toLowerCase()
185+
}
186+
""".trimIndent()
186187

187-
.toLowerCase()
188-
}
189-
""".trimIndent()
190-
)
191-
).isEqualTo(
188+
noConsecutiveBlankLinesRuleAssertThat(code).hasNoLintViolations()
189+
}
190+
191+
@Test
192+
fun `Given multiple blank line in dot qualified expression should return lint error`() {
193+
val code =
192194
"""
193195
fun foo(inputText: String) {
194196
inputText
197+
198+
195199
.toLowerCase()
196200
}
197201
""".trimIndent()
198-
)
202+
203+
noConsecutiveBlankLinesRuleAssertThat(code)
204+
.hasLintViolations(LintViolation(4, 1, "Needless blank line(s)"))
205+
.isFormattedAs(
206+
"""
207+
fun foo(inputText: String) {
208+
inputText
209+
210+
.toLowerCase()
211+
}
212+
""".trimIndent()
213+
)
199214
}
200215
}

0 commit comments

Comments
 (0)