From b344c62b20ff2b650a4e9bdf75d3aebe4e9e74de Mon Sep 17 00:00:00 2001 From: paul-dingemans Date: Tue, 14 Mar 2023 08:16:20 +0100 Subject: [PATCH] Enforce spacing around rangeUntil operator `..<` similar to the range operator `..` in `range-spacing` Closes #1858 --- CHANGELOG.md | 1 + .../rule/engine/core/api/ElementType.kt | 1 + .../rules/SpacingAroundRangeOperatorRule.kt | 15 +++++--- .../SpacingAroundRangeOperatorRuleTest.kt | 34 +++++++++++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 674682ba0d..ea067273fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -253,6 +253,7 @@ Previously the default value for `.editorconfig` property `max_line_length` was * Fix false positive when multiple KDOCs exists between a declaration and another annotated declaration `spacing-between-declarations-with-annotations` ([#1802](https://github.com/pinterest/ktlint/issues/1802)) * Fix false positive when a single line statement containing a block having exactly the maximum line length is preceded by a blank line `wrapping` ([#1808](https://github.com/pinterest/ktlint/issues/1808)) * Fix false positive when a single line contains multiple dot qualified expressions and/or safe expressions `indent` ([#1830](https://github.com/pinterest/ktlint/issues/1830)) +* Enforce spacing around rangeUntil operator `..<` similar to the range operator `..` in `range-spacing` ([#1858](https://github.com/pinterest/ktlint/issues/1858)) ### Changed * Wrap the parameters of a function literal containing a multiline parameter list (only in `ktlint_official` code style) `parameter-list-wrapping` ([#1681](https://github.com/pinterest/ktlint/issues/1681)). diff --git a/ktlint-rule-engine-core/src/main/kotlin/com/pinterest/ktlint/rule/engine/core/api/ElementType.kt b/ktlint-rule-engine-core/src/main/kotlin/com/pinterest/ktlint/rule/engine/core/api/ElementType.kt index 1158353d67..ee3d0ce7a6 100644 --- a/ktlint-rule-engine-core/src/main/kotlin/com/pinterest/ktlint/rule/engine/core/api/ElementType.kt +++ b/ktlint-rule-engine-core/src/main/kotlin/com/pinterest/ktlint/rule/engine/core/api/ElementType.kt @@ -213,6 +213,7 @@ public object ElementType { public val SEMICOLON: IElementType = KtTokens.SEMICOLON public val DOUBLE_SEMICOLON: IElementType = KtTokens.DOUBLE_SEMICOLON public val RANGE: IElementType = KtTokens.RANGE + public val RANGE_UNTIL: IElementType = KtTokens.RANGE_UNTIL public val EQ: IElementType = KtTokens.EQ public val MULTEQ: IElementType = KtTokens.MULTEQ public val DIVEQ: IElementType = KtTokens.DIVEQ diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundRangeOperatorRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundRangeOperatorRule.kt index 0518037205..a6d7518755 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundRangeOperatorRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundRangeOperatorRule.kt @@ -1,12 +1,17 @@ package com.pinterest.ktlint.ruleset.standard.rules import com.pinterest.ktlint.rule.engine.core.api.ElementType.RANGE +import com.pinterest.ktlint.rule.engine.core.api.ElementType.RANGE_UNTIL import com.pinterest.ktlint.rule.engine.core.api.RuleId import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.prevLeaf import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace +import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin +import org.jetbrains.kotlin.lexer.KtSingleValueToken +import org.jetbrains.kotlin.lexer.KtToken +import org.jetbrains.kotlin.lexer.KtTokens public class SpacingAroundRangeOperatorRule : StandardRule("range-spacing") { override fun beforeVisitChildNodes( @@ -14,25 +19,25 @@ public class SpacingAroundRangeOperatorRule : StandardRule("range-spacing") { autoCorrect: Boolean, emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit, ) { - if (node.elementType == RANGE) { + if (node.elementType == RANGE || node.elementType == RANGE_UNTIL) { val prevLeaf = node.prevLeaf() val nextLeaf = node.nextLeaf() when { prevLeaf is PsiWhiteSpace && nextLeaf is PsiWhiteSpace -> { - emit(node.startOffset, "Unexpected spacing around \"..\"", true) + emit(node.startOffset, "Unexpected spacing around \"${node.elementTypeDescription()}\"", true) if (autoCorrect) { prevLeaf.node.treeParent.removeChild(prevLeaf.node) nextLeaf.node.treeParent.removeChild(nextLeaf.node) } } prevLeaf is PsiWhiteSpace -> { - emit(prevLeaf.node.startOffset, "Unexpected spacing before \"..\"", true) + emit(prevLeaf.node.startOffset, "Unexpected spacing before \"${node.elementTypeDescription()}\"", true) if (autoCorrect) { prevLeaf.node.treeParent.removeChild(prevLeaf.node) } } nextLeaf is PsiWhiteSpace -> { - emit(nextLeaf.node.startOffset, "Unexpected spacing after \"..\"", true) + emit(nextLeaf.node.startOffset, "Unexpected spacing after \"${node.elementTypeDescription()}\"", true) if (autoCorrect) { nextLeaf.node.treeParent.removeChild(nextLeaf.node) } @@ -40,6 +45,8 @@ public class SpacingAroundRangeOperatorRule : StandardRule("range-spacing") { } } } + + private fun ASTNode.elementTypeDescription() = (elementType as? KtSingleValueToken)?.value ?: elementType } public val SPACING_AROUND_RANGE_OPERATOR_RULE_ID: RuleId = SpacingAroundRangeOperatorRule().ruleId diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundRangeOperatorRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundRangeOperatorRuleTest.kt index 8c13a21ffb..1b7255848f 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundRangeOperatorRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundRangeOperatorRuleTest.kt @@ -64,4 +64,38 @@ class SpacingAroundRangeOperatorRuleTest { LintViolation(5, 16, "Unexpected spacing before \"..\""), ).isFormattedAs(formattedCode) } + + @Test + fun `Given a rangeUntil operator`() { + val code = + """ + @OptIn(ExperimentalStdlibApi::class) + fun foo(int: Int): String = + when (int) { + in 10..<20 -> "A" + in 20..< 30 -> "B" + in 30 ..< 40 -> "C" + in 40 ..<50 -> "D" + else -> "unknown" + } + """.trimIndent() + val formattedCode = + """ + @OptIn(ExperimentalStdlibApi::class) + fun foo(int: Int): String = + when (int) { + in 10..<20 -> "A" + in 20..<30 -> "B" + in 30..<40 -> "C" + in 40..<50 -> "D" + else -> "unknown" + } + """.trimIndent() + spacingAroundRangeOperatorRuleAssertThat(code) + .hasLintViolations( + LintViolation(5, 17, "Unexpected spacing after \"..<\""), + LintViolation(6, 15, "Unexpected spacing around \"..<\""), + LintViolation(7, 14, "Unexpected spacing before \"..<\""), + ).isFormattedAs(formattedCode) + } }