-
-
Notifications
You must be signed in to change notification settings - Fork 758
/
Rule.kt
104 lines (90 loc) · 3.62 KB
/
Rule.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package io.gitlab.arturbosch.detekt.api
import io.gitlab.arturbosch.detekt.api.Config.Companion.SEVERITY_KEY
import io.gitlab.arturbosch.detekt.api.internal.DefaultContext
import io.gitlab.arturbosch.detekt.api.internal.PathFilters
import io.gitlab.arturbosch.detekt.api.internal.createPathFilters
import io.gitlab.arturbosch.detekt.api.internal.isSuppressedBy
import org.jetbrains.kotlin.psi.KtFile
import java.util.Locale
/**
* A rule defines how one specific code structure should look like. If code is found
* which does not meet this structure, it is considered as harmful regarding maintainability
* or readability.
*
* A rule is implemented using the visitor pattern and should be started using the visit(KtFile)
* function. If calculations must be done before or after the visiting process, here are
* two predefined (preVisit/postVisit) functions which can be overridden to setup/teardown additional data.
*/
abstract class Rule(
override val ruleSetConfig: Config = Config.empty,
ruleContext: Context = DefaultContext()
) : BaseRule(ruleContext), ConfigAware {
/**
* A rule is motivated to point out a specific issue in the code base.
*/
abstract val issue: Issue
/**
* An id this rule is identified with.
* Conventionally the rule id is derived from the issue id as these two classes have a coexistence.
*/
final override val ruleId: RuleId get() = issue.id
/**
* List of rule ids which can optionally be used in suppress annotations to refer to this rule.
*/
val aliases: Set<String> get() = valueOrDefault("aliases", defaultRuleIdAliases)
/**
* The default names which can be used instead of this [ruleId] to refer to this rule in suppression's.
*
* When overriding this property make sure to meet following structure for detekt-generator to pick
* it up and generate documentation for aliases:
*
* override val defaultRuleIdAliases = setOf("Name1", "Name2")
*/
open val defaultRuleIdAliases: Set<String> = emptySet()
internal val ruleSetId: RuleId? get() = ruleSetConfig.parentPath
/**
* Rules are aware of the paths they should run on via configuration properties.
*/
open val filters: PathFilters? by lazy(LazyThreadSafetyMode.NONE) {
createPathFilters()
}
override fun visitCondition(root: KtFile): Boolean =
active && shouldRunOnGivenFile(root) && !root.isSuppressedBy(ruleId, aliases, ruleSetId)
private fun shouldRunOnGivenFile(root: KtFile) =
filters?.isIgnored(root)?.not() ?: true
/**
* Compute severity in the priority order:
* - Severity of the rule
* - Severity of the parent ruleset
* - Default severity: warning
*/
private fun computeSeverity(): SeverityLevel {
val configValue: String = valueOrNull(SEVERITY_KEY)
?: ruleSetConfig.valueOrDefault(SEVERITY_KEY, "warning")
return enumValueOf(configValue.uppercase(Locale.US))
}
/**
* Simplified version of [Context.report] with rule defaults.
*/
fun report(finding: Finding) {
(finding as? CodeSmell)?.internalSeverity = computeSeverity()
report(finding, aliases, ruleSetId)
}
/**
* Simplified version of [Context.report] with rule defaults.
*/
fun report(findings: List<Finding>) {
findings.forEach {
(it as? CodeSmell)?.internalSeverity = computeSeverity()
}
report(
findings,
aliases,
ruleSetId
)
}
}
/**
* The type to use when referring to rule ids giving it more context then a String would.
*/
typealias RuleId = String