-
Notifications
You must be signed in to change notification settings - Fork 506
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add rule to check spacing around square brackets 'square-brackets-spa…
- Loading branch information
1 parent
8eb0a58
commit 114a776
Showing
5 changed files
with
269 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
...ain/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundSquareBracketsRule.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package com.pinterest.ktlint.ruleset.standard.rules | ||
|
||
import com.pinterest.ktlint.rule.engine.core.api.ElementType.COLLECTION_LITERAL_EXPRESSION | ||
import com.pinterest.ktlint.rule.engine.core.api.ElementType.KDOC_MARKDOWN_LINK | ||
import com.pinterest.ktlint.rule.engine.core.api.ElementType.LBRACKET | ||
import com.pinterest.ktlint.rule.engine.core.api.ElementType.RBRACKET | ||
import com.pinterest.ktlint.rule.engine.core.api.RuleId | ||
import com.pinterest.ktlint.rule.engine.core.api.SinceKtlint | ||
import com.pinterest.ktlint.rule.engine.core.api.SinceKtlint.Status.EXPERIMENTAL | ||
import com.pinterest.ktlint.rule.engine.core.api.isWhiteSpaceWithoutNewline | ||
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 | ||
|
||
/** | ||
* Ensures there are no extra spaces around square brackets. | ||
* | ||
* See https://kotlinlang.org/docs/reference/coding-conventions.html#horizontal-whitespace | ||
*/ | ||
@SinceKtlint("1.2", EXPERIMENTAL) | ||
public class SpacingAroundSquareBracketsRule : StandardRule("square-brackets-spacing") { | ||
override fun beforeVisitChildNodes( | ||
node: ASTNode, | ||
autoCorrect: Boolean, | ||
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit, | ||
) { | ||
if (node.elementType == LBRACKET || node.elementType == RBRACKET) { | ||
val prevLeaf = node.prevLeaf() | ||
val nextLeaf = node.nextLeaf() | ||
val spacingBefore = | ||
when (node.treeParent.elementType) { | ||
KDOC_MARKDOWN_LINK -> { | ||
// Allow: | ||
// /** | ||
// * @see [Foo] for more information, | ||
// */ | ||
// fun foo() {} | ||
false | ||
} | ||
COLLECTION_LITERAL_EXPRESSION -> { | ||
// Allow: | ||
// @Foo( | ||
// fooBar = ["foo", "bar"], | ||
// fooBaz = [ | ||
// "foo" | ||
// ] | ||
// Disallow: | ||
// @Foo(fooBar = ["foo", "bar" ]) | ||
node.elementType == RBRACKET && prevLeaf.isWhiteSpaceWithoutNewline() | ||
} | ||
else -> { | ||
prevLeaf.isWhiteSpaceWithoutNewline() | ||
} | ||
} | ||
val spacingAfter = | ||
// Allow: | ||
// val foo = bar[ | ||
// 1, | ||
// baz | ||
// ] | ||
// and | ||
// @Foo( | ||
// fooBar = ["foo", "bar"], | ||
// fooBaz = [ | ||
// "foo" | ||
// ] | ||
// Disallow: | ||
// @Foo(fooBar = [ "foo", "bar"]) | ||
node.elementType == LBRACKET && nextLeaf.isWhiteSpaceWithoutNewline() | ||
when { | ||
spacingBefore && spacingAfter -> { | ||
emit(node.startOffset, "Unexpected spacing around '${node.text}'", true) | ||
if (autoCorrect) { | ||
prevLeaf!!.treeParent.removeChild(prevLeaf) | ||
nextLeaf!!.treeParent.removeChild(nextLeaf) | ||
} | ||
} | ||
spacingBefore -> { | ||
emit(prevLeaf!!.startOffset, "Unexpected spacing before '${node.text}'", true) | ||
if (autoCorrect) { | ||
prevLeaf.treeParent.removeChild(prevLeaf) | ||
} | ||
} | ||
spacingAfter -> { | ||
emit(node.startOffset + 1, "Unexpected spacing after '${node.text}'", true) | ||
if (autoCorrect) { | ||
nextLeaf!!.treeParent.removeChild(nextLeaf) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
public val SPACING_AROUND_SQUARE_BRACKETS_RULE_ID: RuleId = SpacingAroundSquareBracketsRule().ruleId |
128 changes: 128 additions & 0 deletions
128
...kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundSquareBracketsRuleTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package com.pinterest.ktlint.ruleset.standard.rules | ||
|
||
import com.pinterest.ktlint.test.KtLintAssertThat.Companion.assertThatRule | ||
import org.junit.jupiter.api.Test | ||
|
||
class SpacingAroundSquareBracketsRuleTest { | ||
private val spacingAroundSquareBracketsRuleAssertThat = assertThatRule { SpacingAroundSquareBracketsRule() } | ||
|
||
@Test | ||
fun `Given array access expression`() { | ||
val code = | ||
""" | ||
val foo = bar[1] | ||
""".trimIndent() | ||
spacingAroundSquareBracketsRuleAssertThat(code).hasNoLintViolations() | ||
} | ||
|
||
@Test | ||
fun `Given array access expression with unexpected spacing before LBRACKET`() { | ||
val code = | ||
""" | ||
val foo = bar [1] | ||
""".trimIndent() | ||
val formattedCode = | ||
""" | ||
val foo = bar[1] | ||
""".trimIndent() | ||
spacingAroundSquareBracketsRuleAssertThat(code) | ||
.hasLintViolation(1, 14, "Unexpected spacing before '['") | ||
.isFormattedAs(formattedCode) | ||
} | ||
|
||
@Test | ||
fun `Given a KDoc with white space before LBRACKET then do not emit`() { | ||
val code = | ||
""" | ||
/** | ||
* @See [Foo] for more information. | ||
*/ | ||
fun foo() {} | ||
""".trimIndent() | ||
spacingAroundSquareBracketsRuleAssertThat(code).hasNoLintViolations() | ||
} | ||
|
||
@Test | ||
fun `Given array access expression with unexpected spacing after LBRACKET`() { | ||
val code = | ||
""" | ||
val foo = bar[ 1] | ||
""".trimIndent() | ||
val formattedCode = | ||
""" | ||
val foo = bar[1] | ||
""".trimIndent() | ||
spacingAroundSquareBracketsRuleAssertThat(code) | ||
.hasLintViolation(1, 15, "Unexpected spacing after '['") | ||
.isFormattedAs(formattedCode) | ||
} | ||
|
||
@Test | ||
fun `Given array access expression with unexpected spacing around LBRACKET`() { | ||
val code = | ||
""" | ||
val foo = bar [ 1] | ||
""".trimIndent() | ||
val formattedCode = | ||
""" | ||
val foo = bar[1] | ||
""".trimIndent() | ||
spacingAroundSquareBracketsRuleAssertThat(code) | ||
.hasLintViolation(1, 15, "Unexpected spacing around '['") | ||
.isFormattedAs(formattedCode) | ||
} | ||
|
||
@Test | ||
fun `Given array access expression with unexpected spacing before RBRACKET`() { | ||
val code = | ||
""" | ||
val foo = bar[1 ] | ||
""".trimIndent() | ||
val formattedCode = | ||
""" | ||
val foo = bar[1] | ||
""".trimIndent() | ||
spacingAroundSquareBracketsRuleAssertThat(code) | ||
.hasLintViolation(1, 16, "Unexpected spacing before ']'") | ||
.isFormattedAs(formattedCode) | ||
} | ||
|
||
@Test | ||
fun `Given a multiline array access expression then do not emit`() { | ||
val code = | ||
""" | ||
val foo = bar[ | ||
1, | ||
baz | ||
] | ||
""".trimIndent() | ||
spacingAroundSquareBracketsRuleAssertThat(code).hasNoLintViolations() | ||
} | ||
|
||
@Test | ||
fun `Given array access expression with whitespace after RBRACKET then do not emit`() { | ||
val code = | ||
""" | ||
val foo1 = bar[1] | ||
val foo2 = bar[1] + bar[2] | ||
val foo3 = bar[1].count() | ||
""".trimIndent() | ||
spacingAroundSquareBracketsRuleAssertThat(code).hasNoLintViolations() | ||
} | ||
|
||
@Test | ||
fun `Given an annotation with a collection literal expression with whitespaces before around LBRACKET and RBRACKET then do not emit`() { | ||
val code = | ||
""" | ||
@Foo( | ||
fooBar = ["foo", "bar"], | ||
fooBaz = [ | ||
"foo", | ||
"baz", | ||
], | ||
) | ||
fun foo() {} | ||
""".trimIndent() | ||
spacingAroundSquareBracketsRuleAssertThat(code).hasNoLintViolations() | ||
} | ||
} |