Skip to content

Commit

Permalink
Enforce spacing around rangeUntil operator ..< similar to the range…
Browse files Browse the repository at this point in the history
… operator `..` in `range-spacing`

Closes #1858
  • Loading branch information
paul-dingemans committed Mar 14, 2023
1 parent 7f323be commit b344c62
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,52 @@
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(
node: ASTNode,
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)
}
}
}
}
}

private fun ASTNode.elementTypeDescription() = (elementType as? KtSingleValueToken)?.value ?: elementType
}

public val SPACING_AROUND_RANGE_OPERATOR_RULE_ID: RuleId = SpacingAroundRangeOperatorRule().ruleId
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

0 comments on commit b344c62

Please # to comment.