首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用Detekt自定义规则检查lambda中“it”参数的用法?

如何使用Detekt自定义规则检查lambda中“it”参数的用法?
EN

Stack Overflow用户
提问于 2022-03-20 10:56:39
回答 1查看 76关注 0票数 0

我想写一个Detekt规则,它不允许在多行lambda中使用隐式"it“变量。我已经编写了重写fun visitLambdaExpression(lambdaExpression: KtLambdaExpression)的方法,但我不知道如何实现

  1. 检查lambda是否包含“it”变量。lambdaExpression.valueParameters在这种情况下不包含任何内容。
  2. 检查是否在lambda.

中使用“it”。

我也没找到任何文件。

EN

回答 1

Stack Overflow用户

发布于 2022-07-20 14:50:46

尝尝这个

代码语言:javascript
复制
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
    }
}

而测试:

代码语言:javascript
复制
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)
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71546120

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档