我想写一个Detekt规则,它不允许在多行lambda中使用隐式"it“变量。我已经编写了重写fun visitLambdaExpression(lambdaExpression: KtLambdaExpression)的方法,但我不知道如何实现
lambdaExpression.valueParameters在这种情况下不包含任何内容。中使用“it”。
我也没找到任何文件。
发布于 2022-07-20 14:50:46
尝尝这个
import io.gitlab.arturbosch.detekt.api.CodeSmell
import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.api.Debt
import io.gitlab.arturbosch.detekt.api.Entity
import io.gitlab.arturbosch.detekt.api.Issue
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.Severity
import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.psiUtil.allChildren
class NoItInMultilineLambda(config: Config = Config.empty) : Rule(config) {
override val issue = Issue(
id = "NoItInMultilineLambda",
severity = Severity.Style,
description = "Do not use 'it' in multiline lambda. Use an explicit parameter instead",
debt = Debt(mins = 1),
)
override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {
super.visitLambdaExpression(lambdaExpression)
val referenceExpression: KtNameReferenceExpression? = lambdaExpression.run {
when {
isMultiline() -> {
bodyExpression?.statements?.findKtNameReferenceExpression { ktNameReferenceExpression ->
ktNameReferenceExpression.getReferencedName() == "it"
}
}
else -> null
}
}
if (referenceExpression != null) {
report(
CodeSmell(
issue = issue,
entity = Entity.from(referenceExpression),
message = "Usage of 'it' in multiline lambda",
)
)
}
}
private fun KtLambdaExpression.isMultiline(): Boolean {
return children.filterIsInstance<KtFunctionLiteral>().firstOrNull()?.allChildren?.any { psiElement ->
psiElement is PsiWhiteSpace && psiElement.textContains('\n')
} ?: false
}
@Suppress("ReturnCount")
private fun List<KtElement>.findKtNameReferenceExpression(
predicate: (KtNameReferenceExpression) -> Boolean,
): KtNameReferenceExpression? {
forEach { ktElement: KtElement ->
when {
ktElement is KtNameReferenceExpression && predicate(ktElement) -> return ktElement
ktElement is KtLambdaExpression -> return null // Nested lambdas are handled automatically
else -> {
val foundInChidren = ktElement.children.filterIsInstance<KtElement>()
.findKtNameReferenceExpression(predicate)
if (foundInChidren != null) {
return foundInChidren
}
}
}
}
return null
}
}而测试:
import com.google.common.truth.Truth
import io.gitlab.arturbosch.detekt.test.lint
import org.junit.jupiter.api.Test
internal class NoItInMultilineLambdaTest {
@Test
fun noItInMultilineLambdaTest0() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test() {
funWithLambda {
it
}
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(1)
Truth.assertThat(findings[0].message).isEqualTo(
"Usage of 'it' in multiline lambda",
)
}
@Test
fun noItInMultilineLambdaTest1() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test() {
funWithLambda {
// Some good statement
val x = 0
test()
it
it
}
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(1)
Truth.assertThat(findings[0].message).isEqualTo(
"Usage of 'it' in multiline lambda",
)
}
@Test
fun noItInMultilineLambdaTest2() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test() {
funWithLambda {
// Some good statement
val x = 0
test()
it.dec()
// Some good statement
val y = 0
test()
}
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(1)
Truth.assertThat(findings[0].message).isEqualTo(
"Usage of 'it' in multiline lambda",
)
}
@Test
fun noItInMultilineLambdaTest3() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test() {
funWithLambda {
// Some good statement
val x = 0
test()
it += 1
}
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(1)
Truth.assertThat(findings[0].message).isEqualTo(
"Usage of 'it' in multiline lambda",
)
}
@Test
fun noItInMultilineLambdaTest4() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test() {
funWithLambda {
// Some good statement
val x = 0
test()
it.and(1)
}
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(1)
Truth.assertThat(findings[0].message).isEqualTo(
"Usage of 'it' in multiline lambda",
)
}
@Test
fun noItInMultilineLambdaTest6() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test() {
funWithLambda {
// Some good statement
val x = 0
test()
it == 0
}
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(1)
Truth.assertThat(findings[0].message).isEqualTo(
"Usage of 'it' in multiline lambda",
)
}
@Test
fun noItInMultilineLambdaTest5() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test() {
funWithLambda {
funWithLambda {
it == 0
}
}
}
""".trimIndent()
)
Truth.assertThat(findings.map { it.message }).contains(
"Usage of 'it' in multiline lambda",
)
}
@Test
fun noItInMultilineLambdaTest7() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test() {
funWithLambda {
funWithLambda {
// Some good statement
val x = 0
test()
it == 0
// Some good statement
val x = 0
test()
}
}
}
""".trimIndent()
)
Truth.assertThat(findings.map { it.message }).contains(
"Usage of 'it' in multiline lambda",
)
}
@Test
fun noItInMultilineLambdaTest8() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test(i: Int) {
funWithLambda {
test(it)
}
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(1)
Truth.assertThat(findings[0].message).isEqualTo(
"Usage of 'it' in multiline lambda",
)
}
@Test
fun noItInMultilineLambdaTest9() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test(a: Boolean, i: Int, c: Float) {
funWithLambda {
test(false, it, 1.0f)
}
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(1)
Truth.assertThat(findings[0].message).isEqualTo(
"Usage of 'it' in multiline lambda",
)
}
@Test
fun noItInMultilineLambdaTest15() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test() {
var x: Int = 0
funWithLambda {
x = it
}
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(1)
Truth.assertThat(findings[0].message).isEqualTo(
"Usage of 'it' in multiline lambda",
)
}
@Test
fun noItInMultilineLambdaTest10() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test(a: Boolean, i: Int, c: Float) {
funWithLambda { it }
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(0)
}
@Test
fun noItInMultilineLambdaTest11() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test(a: Boolean, i: Int, c: Float) {
funWithLambda { funWithLambda { it } }
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(0)
}
@Test
fun noItInMultilineLambdaTest12() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test(a: Boolean, i: Int, c: Float) {
funWithLambda { funWithLambda { it == 0 } }
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(0)
}
@Test
fun noItInMultilineLambdaTest13() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test(a: Boolean, i: Int, c: Float) {
funWithLambda { funWithLambda { it += 1 } }
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(0)
}
@Test
fun noItInMultilineLambdaTest16() {
val findings = NoItInMultilineLambda().lint(
"""
fun funWithLambda1(lambda: () -> Unit) { }
fun funWithLambda(lambda: (param: Int) -> Unit) { }
fun test() {
funWithLambda1 {
funWithLambda { it += 1 }
}
}
""".trimIndent()
)
Truth.assertThat(findings).hasSize(0)
}
}https://stackoverflow.com/questions/71546120
复制相似问题