forked from detekt/detekt
/
AlsoCouldBeApply.kt
67 lines (62 loc) · 2.18 KB
/
AlsoCouldBeApply.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package io.gitlab.arturbosch.detekt.rules.style
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 io.gitlab.arturbosch.detekt.rules.IT_LITERAL
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
/**
* Detects when an `also` block contains only `it`-started expressions.
*
* By refactoring the `also` block to an `apply` block makes it so that all `it`s can be removed
* thus making the block more concise and easier to read.
*
* <noncompliant>
* Buzz().also {
* it.init()
* it.block()
* }
* </noncompliant>
*
* <compliant>
* Buzz().apply {
* init()
* block()
* }
*
* // Also compliant
* fun foo(a: Int): Int {
* return a.also { println(it) }
* }
* </compliant>
*/
class AlsoCouldBeApply(config: Config = Config.empty) : Rule(config) {
override val issue = Issue(
"AlsoCouldBeApply",
Severity.Style,
"When an `also` block contains only `it`-started expressions, simplify it to the `apply` block.",
Debt.FIVE_MINS
)
override fun visitCallExpression(expression: KtCallExpression) {
if (expression.calleeExpression?.text == "also") {
val lambda = expression.lambdaArguments.singleOrNull() ?: expression.valueArguments.single()
.collectDescendantsOfType<KtLambdaExpression>()
.single()
val dotQualifiedsInLambda = lambda.collectDescendantsOfType<KtDotQualifiedExpression>()
if (
dotQualifiedsInLambda.isNotEmpty() &&
dotQualifiedsInLambda.all { it.receiverExpression.textMatches(IT_LITERAL) }
) {
report(CodeSmell(issue, Entity.from(expression), issue.description))
}
} else {
super.visitCallExpression(expression)
}
}
}