/
ForbiddenSuppress.kt
90 lines (82 loc) · 3.18 KB
/
ForbiddenSuppress.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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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.api.config
import io.gitlab.arturbosch.detekt.api.internal.Configuration
import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.KtValueArgumentList
/**
* This rule allows to set a list of rules whose suppression is forbidden. This can be used to discourage abuse of the
* [Suppress] and [SuppressWarnings] annotations. Detekt will report suppression of all forbidden rules. This rule is
* not capable of reporting suppression of itself, as that's a language feature with precedence.
*
* <noncompliant>
* package foo
*
* // When the rule "MaximumLineLength" is forbidden
* @Suppress("MaximumLineLength", "UNCHECKED_CAST")
* class Bar
* </noncompliant>
*
* <compliant>
* package foo
*
* // When the rule "MaximumLineLength" is forbidden
* @Suppress("UNCHECKED_CAST")
* class Bar
* </compliant>
*/
class ForbiddenSuppress(config: Config = Config.empty) : Rule(config) {
override val issue = Issue(
javaClass.simpleName,
Severity.Maintainability,
"",
Debt.TEN_MINS
)
@Configuration("Rules whose suppression is forbidden.")
private val rules: List<String> by config(emptyList())
override fun visitAnnotationEntry(annotationEntry: KtAnnotationEntry) {
val shortName = annotationEntry.shortName!!.asString()
if (shortName == KOTLIN_SUPPRESS || shortName == JAVA_SUPPRESS) {
val nonCompliantRules = annotationEntry.children
.find { it is KtValueArgumentList }
?.children
?.filterIsInstance<KtValueArgument>()
?.findForbiddenRules() ?: emptyList()
if (nonCompliantRules.isNotEmpty()) {
report(
CodeSmell(
issue,
Entity.from(annotationEntry),
message = "Cannot @Suppress ${nonCompliantRules.formatMessage()}.",
)
)
}
}
}
private fun List<String>.formatMessage(): String = if (size > 1) {
"rules "
} else {
"rule "
} + joinToString(", ") { "\"$it\"" }
private fun List<KtValueArgument>.findForbiddenRules(): List<String> = mapNotNull { argument ->
val stringTemplate = argument.children
.find { it is KtStringTemplateExpression }
?.children
?.find { it is KtLiteralStringTemplateEntry }
val text = stringTemplate?.text
if (rules.contains(text)) text else null
}
private companion object {
private const val KOTLIN_SUPPRESS = "Suppress"
private const val JAVA_SUPPRESS = "SuppressWarnings"
}
}