-
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.
Introduce SpacingAroundDoubleColonRule (#722)
- Loading branch information
Roman Zavarnitsyn
authored
Apr 22, 2020
1 parent
b952857
commit ff527eb
Showing
6 changed files
with
212 additions
and
1 deletion.
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
70 changes: 70 additions & 0 deletions
70
...src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/SpacingAroundDoubleColonRule.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,70 @@ | ||
package com.pinterest.ktlint.ruleset.experimental | ||
|
||
import com.pinterest.ktlint.core.Rule | ||
import com.pinterest.ktlint.core.ast.ElementType.CALLABLE_REFERENCE_EXPRESSION | ||
import com.pinterest.ktlint.core.ast.ElementType.CLASS_LITERAL_EXPRESSION | ||
import com.pinterest.ktlint.core.ast.ElementType.COLONCOLON | ||
import com.pinterest.ktlint.core.ast.isPartOf | ||
import com.pinterest.ktlint.core.ast.nextLeaf | ||
import com.pinterest.ktlint.core.ast.prevLeaf | ||
import org.jetbrains.kotlin.com.intellij.lang.ASTNode | ||
import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace | ||
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement | ||
|
||
class SpacingAroundDoubleColonRule : Rule("double-colon-spacing") { | ||
|
||
override fun visit( | ||
node: ASTNode, | ||
autoCorrect: Boolean, | ||
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit | ||
) { | ||
if (node.elementType == COLONCOLON) { | ||
val prevLeaf = node.prevLeaf() | ||
val nextLeaf = node.nextLeaf() | ||
|
||
var removeSingleWhiteSpace = false | ||
val spacingBefore = when { | ||
node.isPartOf(CLASS_LITERAL_EXPRESSION) && prevLeaf is PsiWhiteSpace -> true // Clazz::class | ||
node.isPartOf(CALLABLE_REFERENCE_EXPRESSION) && prevLeaf is PsiWhiteSpace -> // String::length, ::isOdd | ||
if (node.treePrev == null) { // compose(length, ::isOdd), val predicate = ::isOdd | ||
removeSingleWhiteSpace = true | ||
!prevLeaf.textContains('\n') && prevLeaf.psi.textLength > 1 | ||
} else { // String::length, List<String>::isEmpty | ||
!prevLeaf.textContains('\n') | ||
} | ||
else -> false | ||
} | ||
|
||
val spacingAfter = nextLeaf is PsiWhiteSpace | ||
when { | ||
spacingBefore && spacingAfter -> { | ||
emit(node.startOffset, "Unexpected spacing around \"${node.text}\"", true) | ||
if (autoCorrect) { | ||
prevLeaf!!.removeSelf(removeSingleWhiteSpace) | ||
nextLeaf!!.treeParent.removeChild(nextLeaf) | ||
} | ||
} | ||
spacingBefore -> { | ||
emit(prevLeaf!!.startOffset, "Unexpected spacing before \"${node.text}\"", true) | ||
if (autoCorrect) { | ||
prevLeaf.removeSelf(removeSingleWhiteSpace) | ||
} | ||
} | ||
spacingAfter -> { | ||
emit(nextLeaf!!.startOffset, "Unexpected spacing after \"${node.text}\"", true) | ||
if (autoCorrect) { | ||
nextLeaf.treeParent.removeChild(nextLeaf) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
private fun ASTNode.removeSelf(removeSingleWhiteSpace: Boolean) { | ||
if (removeSingleWhiteSpace) { | ||
(this as LeafPsiElement).rawReplaceWithText(text.substring(0, textLength - 1)) | ||
} else { | ||
treeParent.removeChild(this) | ||
} | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
...test/kotlin/com/pinterest/ktlint/ruleset/experimental/SpacingAroundDoubleColonRuleTest.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,26 @@ | ||
package com.pinterest.ktlint.ruleset.experimental | ||
|
||
import com.pinterest.ktlint.test.diffFileFormat | ||
import com.pinterest.ktlint.test.diffFileLint | ||
import org.assertj.core.api.Assertions.assertThat | ||
import org.junit.Test | ||
|
||
class SpacingAroundDoubleColonRuleTest { | ||
|
||
@Test | ||
fun testLint() { | ||
assertThat( | ||
SpacingAroundDoubleColonRule().diffFileLint("spec/spacing-around-double-colon/lint.kt.spec") | ||
).isEmpty() | ||
} | ||
|
||
@Test | ||
fun testFormat() { | ||
assertThat( | ||
SpacingAroundDoubleColonRule().diffFileFormat( | ||
"spec/spacing-around-double-colon/format.kt.spec", | ||
"spec/spacing-around-double-colon/format-expected.kt.spec" | ||
) | ||
).isEmpty() | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
...-experimental/src/test/resources/spec/spacing-around-double-colon/format-expected.kt.spec
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,32 @@ | ||
fun main() { | ||
val a = AClass::class | ||
val b = BClass::class | ||
val c = CClass::class | ||
val d = DClass::class | ||
val e = EClass::class | ||
val f = FClass::class | ||
|
||
fun isOdd(s: String) = s == "brillig" || s == "slithy" || s == "tove" | ||
val predicateA: (String) -> Boolean = ::isOdd | ||
val predicateB: (String) -> Boolean = ::isOdd | ||
val predicateC: (String) -> Boolean = ::isOdd | ||
val predicateD: (String) -> Boolean = ::isOdd | ||
val predicateE: (String) -> Boolean = | ||
::isOdd | ||
val predicateF: (String) -> Boolean = ::isOdd | ||
|
||
if (true == ::isOdd.invoke("")) { | ||
// do stuff | ||
} | ||
|
||
val isEmptyStringList: List<String>.() -> Boolean = List<String>::isEmpty | ||
val isNotEmptyStringList: List<String>.() -> Boolean = List<String>::isNotEmpty | ||
|
||
function(::Foo) | ||
function( | ||
::Foo | ||
) | ||
|
||
items.filter(::isEven) | ||
.map(String::length) | ||
} |
35 changes: 35 additions & 0 deletions
35
...t-ruleset-experimental/src/test/resources/spec/spacing-around-double-colon/format.kt.spec
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,35 @@ | ||
fun main() { | ||
val a = AClass::class | ||
val b = BClass ::class | ||
val c = CClass:: class | ||
val d = DClass :: class | ||
val e = EClass:: | ||
class | ||
val f = FClass :: class | ||
|
||
fun isOdd(s: String) = s == "brillig" || s == "slithy" || s == "tove" | ||
val predicateA: (String) -> Boolean = :: isOdd | ||
val predicateB: (String) -> Boolean = ::isOdd | ||
val predicateC: (String) -> Boolean = :: isOdd | ||
val predicateD: (String) -> Boolean = ::isOdd | ||
val predicateE: (String) -> Boolean = | ||
::isOdd | ||
val predicateF: (String) -> Boolean = :: | ||
isOdd | ||
|
||
if (true == ::isOdd.invoke("")) { | ||
// do stuff | ||
} | ||
|
||
val isEmptyStringList: List<String>.() -> Boolean = List<String> :: isEmpty | ||
val isNotEmptyStringList: List<String>.() -> Boolean = List<String>::isNotEmpty | ||
|
||
function(::Foo) | ||
function( | ||
:: | ||
Foo | ||
) | ||
|
||
items.filter(::isEven) | ||
.map(String ::length) | ||
} |
47 changes: 47 additions & 0 deletions
47
ktlint-ruleset-experimental/src/test/resources/spec/spacing-around-double-colon/lint.kt.spec
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,47 @@ | ||
fun main() { | ||
val a = AClass::class | ||
val b = BClass ::class | ||
val c = CClass:: class | ||
val d = DClass :: class | ||
val e = EClass:: | ||
class | ||
|
||
fun isOdd(s: String) = s == "brillig" || s == "slithy" || s == "tove" | ||
val predicateA: (String) -> Boolean = :: isOdd | ||
val predicateB: (String) -> Boolean = ::isOdd | ||
val predicateC: (String) -> Boolean = :: isOdd | ||
val predicateD: (String) -> Boolean = ::isOdd | ||
val predicateE: (String) -> Boolean = | ||
::isOdd | ||
val predicateF: (String) -> Boolean = :: | ||
isOdd | ||
|
||
if (true == ::isOdd.invoke("")) { | ||
// do stuff | ||
} | ||
|
||
val isEmptyStringList: List<String>.() -> Boolean = List<String> :: isEmpty | ||
val isNotEmptyStringList: List<String>.() -> Boolean = List<String>::isNotEmpty | ||
|
||
function(::Foo) | ||
function( | ||
:: | ||
Foo | ||
) | ||
|
||
items.filter(::isEven) | ||
.map(String ::length) | ||
} | ||
|
||
// expect | ||
// 3:19:Unexpected spacing before "::" | ||
// 4:21:Unexpected spacing after "::" | ||
// 5:20:Unexpected spacing around "::" | ||
// 6:21:Unexpected spacing after "::" | ||
// 10:45:Unexpected spacing after "::" | ||
// 11:42:Unexpected spacing before "::" | ||
// 12:44:Unexpected spacing around "::" | ||
// 16:45:Unexpected spacing after "::" | ||
// 23:70:Unexpected spacing around "::" | ||
// 28:11:Unexpected spacing after "::" | ||
// 33:20:Unexpected spacing before "::" |