Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding experimental rule for detecting first line blank in method block #474

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class ExperimentalRuleSetProvider : RuleSetProvider {
override fun get(): RuleSet = RuleSet(
"experimental",
ImportOrderingRule(),
IndentationRule()
IndentationRule(),
NoFirstLineBlankInMethodBlockRule()
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.pinterest.ktlint.ruleset.experimental

import com.pinterest.ktlint.core.Rule
import com.pinterest.ktlint.core.ast.ElementType
import com.pinterest.ktlint.core.ast.ElementType.FUN
import com.pinterest.ktlint.core.ast.isPartOf
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 NoFirstLineBlankInMethodBlockRule : Rule("no-first-line-blank-in-method-block-rule") {

override fun visit(
node: ASTNode,
autoCorrect: Boolean,
emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit
) {
if (node is PsiWhiteSpace && node.textContains('\n') &&
node.prevLeaf()?.elementType == ElementType.LBRACE && node.isPartOf(FUN)
) {
val split = node.getText().split("\n")
if (split.size > 2) {
emit(
node.startOffset + 1,
"First line in a method block should not be empty", true
)
if (autoCorrect) {
(node as LeafPsiElement).rawReplaceWithText("${split.first()}\n${split.last()}")
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package com.pinterest.ktlint.ruleset.experimental

import com.pinterest.ktlint.core.LintError
import com.pinterest.ktlint.test.format
import com.pinterest.ktlint.test.lint
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test

class NoFirstLineBlankInMethodBlockRuleTest {

@Test
fun testFormatIsCorrect() {
val formattedFunction =
"""
fun bar() {
val a = 2
}
""".trimIndent()

assertThat(NoFirstLineBlankInMethodBlockRule().lint(formattedFunction)).isEmpty()
assertThat(NoFirstLineBlankInMethodBlockRule().format(formattedFunction)).isEqualTo(formattedFunction)
}

@Test
fun testFormatWhenFirstLineIsEmptyInMethod() {
val unformattedFunction =
"""
fun bar() {

val a = 2
}
""".trimIndent()
val formattedFunction =
"""
fun bar() {
val a = 2
}
""".trimIndent()

assertThat(NoFirstLineBlankInMethodBlockRule().lint(unformattedFunction)).isEqualTo(
listOf(
LintError(2, 1, "no-first-line-blank-in-method-block-rule", "First line in a method block should not be empty")
)
)
assertThat(NoFirstLineBlankInMethodBlockRule().format(unformattedFunction)).isEqualTo(formattedFunction)
}

@Test
fun testFormatWhenFirstLineIsEmptyInABlockWithinMethod() {
val unformattedFunction =
"""
fun funA() {

if (conditionA()) {

doSomething()
} else if (conditionB()) {
doAnotherThing()
}
}
""".trimIndent()
val formattedFunction =
"""
fun funA() {
if (conditionA()) {
doSomething()
} else if (conditionB()) {
doAnotherThing()
}
}
""".trimIndent()

assertThat(NoFirstLineBlankInMethodBlockRule().lint(unformattedFunction)).isEqualTo(
listOf(
LintError(2, 1, "no-first-line-blank-in-method-block-rule", "First line in a method block should not be empty"),
LintError(4, 1, "no-first-line-blank-in-method-block-rule", "First line in a method block should not be empty")
)
)
assertThat(NoFirstLineBlankInMethodBlockRule().format(unformattedFunction)).isEqualTo(formattedFunction)
}

@Test
fun testFormatWhenFirstLineIsEmptyOnlyInABlockWithinMethod() {
val unformattedFunction =
"""
fun funA() {
if (conditionA()) {

doSomething()
} else if (conditionB()) {
doAnotherThing()
}
}
""".trimIndent()
val formattedFunction =
"""
fun funA() {
if (conditionA()) {
doSomething()
} else if (conditionB()) {
doAnotherThing()
}
}
""".trimIndent()

assertThat(NoFirstLineBlankInMethodBlockRule().lint(unformattedFunction)).isEqualTo(
listOf(
LintError(3, 1, "no-first-line-blank-in-method-block-rule", "First line in a method block should not be empty")
)
)
assertThat(NoFirstLineBlankInMethodBlockRule().format(unformattedFunction)).isEqualTo(formattedFunction)
}

@Test
fun testFormatWhenFirstLineIsEmptyInFunctionButIgnoreAtClassLevel() {
val unformattedFunction =
"""
class A {

fun bar() {

val a = 2
}
}
""".trimIndent()
val formattedFunction =
"""
class A {

fun bar() {
val a = 2
}
}
""".trimIndent()

assertThat(NoFirstLineBlankInMethodBlockRule().lint(unformattedFunction)).isEqualTo(
listOf(
LintError(4, 1, "no-first-line-blank-in-method-block-rule", "First line in a method block should not be empty")
)
)
assertThat(NoFirstLineBlankInMethodBlockRule().format(unformattedFunction)).isEqualTo(formattedFunction)
}
}
1 change: 0 additions & 1 deletion ktlint/src/main/kotlin/com/pinterest/ktlint/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,6 @@ object Main {
numberOfThreads: Int = Runtime.getRuntime().availableProcessors()
) {
val pill = object : Future<T> {

override fun isDone(): Boolean { throw UnsupportedOperationException() }
override fun get(timeout: Long, unit: TimeUnit): T { throw UnsupportedOperationException() }
override fun get(): T { throw UnsupportedOperationException() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class EditorConfig private constructor (
}

fun cached(): EditorConfigLookup = object : EditorConfigLookup {

// todo: concurrent radix tree can potentially save a lot of memory here
private val cache = ConcurrentHashMap<Path, CompletableFuture<EditorConfig?>>()

Expand Down Expand Up @@ -115,7 +114,6 @@ class EditorConfig private constructor (
private fun load(path: Path) =
linkedMapOf<String, Map<String, String>>().also { map ->
object : Properties() {

private var section: MutableMap<String, String>? = null

override fun put(key: Any, value: Any): Any? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ class MavenDependencyResolver(

fun setTransferEventListener(listener: (event: TransferEvent) -> Unit) {
(session as DefaultRepositorySystemSession).transferListener = object : TransferListener {

override fun transferProgressed(event: TransferEvent) = listener(event)
override fun transferStarted(event: TransferEvent) = listener(event)
override fun transferInitiated(event: TransferEvent) = listener(event)
Expand Down