Skip to content

Commit f7c9c8a

Browse files
authored
Reused c.p.k.c.Rule.VisitorModifier.RunAfterRule (#1310)
### What's done: * added a wrapper for rule with c.p.k.c.Rule.VisitorModifier.RunAfterRule is pointed to prev rule * added test for OrderedRule
1 parent b895181 commit f7c9c8a

File tree

3 files changed

+123
-4
lines changed

3 files changed

+123
-4
lines changed

.git-hooks/commit-msg.sh

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
commit_pattern="(Merge (remote-tracking )?branch|### What's done:)"
44
error_msg="Your commit message doesn't match the pattern $commit_pattern. Please fix it."
5+
commit_count="$(git rev-list --count master..HEAD 2> /dev/null)"
56

6-
if [[ ! $( cat "$1" ) =~ $commit_pattern ]]
7+
if [[ $commit_count = "0" && ! $( cat "$1" ) =~ $commit_pattern ]]
78
then
89
echo "$error_msg"
910
exit 1

diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt

+43-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package org.cqfn.diktat.ruleset.rules
33
import org.cqfn.diktat.common.config.rules.DIKTAT_COMMON
44
import org.cqfn.diktat.common.config.rules.RulesConfig
55
import org.cqfn.diktat.common.config.rules.RulesConfigReader
6+
import org.cqfn.diktat.ruleset.constants.EmitType
67
import org.cqfn.diktat.ruleset.constants.Warnings
78
import org.cqfn.diktat.ruleset.dummy.DummyWarning
89
import org.cqfn.diktat.ruleset.rules.chapter1.FileNaming
@@ -79,8 +80,10 @@ import org.cqfn.diktat.ruleset.rules.chapter6.classes.SingleConstructorRule
7980
import org.cqfn.diktat.ruleset.rules.chapter6.classes.SingleInitRule
8081
import org.cqfn.diktat.ruleset.rules.chapter6.classes.StatelessClassesRule
8182

83+
import com.pinterest.ktlint.core.Rule
8284
import com.pinterest.ktlint.core.RuleSet
8385
import com.pinterest.ktlint.core.RuleSetProvider
86+
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
8487
import org.jetbrains.kotlin.org.jline.utils.Levenshtein
8588
import org.slf4j.LoggerFactory
8689

@@ -226,10 +229,12 @@ class DiktatRuleSetProvider(private var diktatConfigFile: String = DIKTAT_ANALYS
226229
.map {
227230
it.invoke(configRules)
228231
}
229-
.toTypedArray()
232+
val orderedRules = rules.mapIndexed { index, rule ->
233+
if (index != 0) OrderedRule(rule, rules[index - 1]) else rule
234+
}
230235
return RuleSet(
231236
DIKTAT_RULE_SET_ID,
232-
*rules
237+
rules = orderedRules.toTypedArray()
233238
)
234239
}
235240

@@ -262,7 +267,43 @@ class DiktatRuleSetProvider(private var diktatConfigFile: String = DIKTAT_ANALYS
262267

263268
private fun resolveConfigFileFromSystemProperty(): String? = System.getProperty(DIKTAT_CONF_PROPERTY)
264269

270+
/**
271+
* This is a wrapper around Ktlint Rule which adjusts visitorModifiers to keep order with prevRule
272+
* Added as a workaround after introducing a new logic for sorting KtLint Rules: https://github.com/pinterest/ktlint/issues/1478
273+
*
274+
* @property rule KtLink Rule which this class wraps
275+
*
276+
* @param prevRule previous KtLink Rule, the wrapped rule is called after prevRule
277+
*/
278+
internal class OrderedRule(val rule: Rule, prevRule: Rule) : Rule(rule.id, adjustVisitorModifiers(rule, prevRule)) {
279+
/**
280+
* Delegating a call of this method
281+
*/
282+
override fun visit(
283+
node: ASTNode,
284+
autoCorrect: Boolean,
285+
emit: EmitType
286+
) {
287+
rule.visit(node, autoCorrect, emit)
288+
}
289+
}
290+
265291
companion object {
266292
private val log = LoggerFactory.getLogger(DiktatRuleSetProvider::class.java)
293+
294+
private fun adjustVisitorModifiers(rule: Rule, prevRule: Rule): Set<Rule.VisitorModifier> {
295+
val visitorModifiers: Set<Rule.VisitorModifier> = rule.visitorModifiers
296+
require(visitorModifiers.none { it is Rule.VisitorModifier.RunAfterRule }) {
297+
"Rule ${rule.id} already contains VisitorModifier.RunAfterRule"
298+
}
299+
require(rule.id != prevRule.id) {
300+
"PrevRule has same ID as rule: ${rule.id}"
301+
}
302+
return visitorModifiers + Rule.VisitorModifier.RunAfterRule(
303+
ruleId = prevRule.id,
304+
loadOnlyWhenOtherRuleIsLoaded = false,
305+
runOnlyWhenOtherRuleIsEnabled = false
306+
)
307+
}
267308
}
268309
}

diktat-rules/src/test/kotlin/org/cqfn/diktat/util/DiktatRuleSetProvider4Test.kt

+78-1
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ package org.cqfn.diktat.util
66

77
import org.cqfn.diktat.common.config.rules.RulesConfig
88
import org.cqfn.diktat.common.config.rules.RulesConfigReader
9+
import org.cqfn.diktat.ruleset.constants.EmitType
910
import org.cqfn.diktat.ruleset.rules.DIKTAT_RULE_SET_ID
1011
import org.cqfn.diktat.ruleset.rules.DiktatRuleSetProvider
1112

1213
import com.pinterest.ktlint.core.Rule
1314
import com.pinterest.ktlint.core.RuleSet
1415
import com.pinterest.ktlint.core.RuleSetProvider
16+
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
1517
import org.junit.jupiter.api.Assertions
1618
import org.junit.jupiter.api.Test
1719

@@ -40,10 +42,85 @@ class DiktatRuleSetProviderTest {
4042
.filter { it.isFile }
4143
.map { it.nameWithoutExtension }
4244
.filterNot { it in ignoreFile }
43-
val rulesName = DiktatRuleSetProvider().get().map { it::class.simpleName!! }.filter { it != "DummyWarning" }
45+
val rulesName = DiktatRuleSetProvider().get()
46+
.onEachIndexed { index, rule ->
47+
if (index != 0) {
48+
Assertions.assertTrue(
49+
rule.visitorModifiers.any { it is Rule.VisitorModifier.RunAfterRule },
50+
"Rule ${rule.id} doesn't contain Rule.VisitorModifier.RunAfterRule"
51+
)
52+
}
53+
}
54+
.map { (it as? DiktatRuleSetProvider.OrderedRule)?.rule ?: it }
55+
.map { it::class.simpleName!! }
56+
.filter { it != "DummyWarning" }
4457
Assertions.assertEquals(filesName.sorted().toList(), rulesName.sorted())
4558
}
4659

60+
@Test
61+
fun `check OrderedRule with VisitorModifier RunAfterRule`() {
62+
val rule = object : Rule("rule") {
63+
override fun visit(
64+
node: ASTNode,
65+
autoCorrect: Boolean,
66+
emit: EmitType
67+
) {
68+
// do nothing
69+
}
70+
}
71+
Assertions.assertThrows(IllegalArgumentException::class.java) {
72+
DiktatRuleSetProvider.OrderedRule(rule, rule)
73+
}
74+
75+
val ruleWithRunAfterRule = object : Rule("invalid-rule", setOf(VisitorModifier.RunAfterRule("another-rule"))) {
76+
override fun visit(
77+
node: ASTNode,
78+
autoCorrect: Boolean,
79+
emit: EmitType
80+
) {
81+
// do nothing
82+
}
83+
}
84+
Assertions.assertThrows(IllegalArgumentException::class.java) {
85+
DiktatRuleSetProvider.OrderedRule(ruleWithRunAfterRule, rule)
86+
}
87+
}
88+
89+
@Test
90+
fun `check OrderedRule`() {
91+
val rule1 = object : Rule("rule-first") {
92+
override fun visit(
93+
node: ASTNode,
94+
autoCorrect: Boolean,
95+
emit: EmitType
96+
) {
97+
// do nothing
98+
}
99+
}
100+
val rule2 = object : Rule("rule-second") {
101+
override fun visit(
102+
node: ASTNode,
103+
autoCorrect: Boolean,
104+
emit: EmitType
105+
) {
106+
// do nothing
107+
}
108+
}
109+
110+
val orderedRule = DiktatRuleSetProvider.OrderedRule(rule2, rule1)
111+
orderedRule.visitorModifiers
112+
.filterIsInstance<Rule.VisitorModifier.RunAfterRule>()
113+
.also {
114+
Assertions.assertEquals(1, it.size,
115+
"Found invalid count of Rule.VisitorModifier.RunAfterRule")
116+
}
117+
.first()
118+
.let {
119+
Assertions.assertEquals(rule1.id, it.ruleId,
120+
"Invalid ruleId in Rule.VisitorModifier.RunAfterRule")
121+
}
122+
}
123+
47124
companion object {
48125
private val ignoreFile = listOf("DiktatRuleSetProvider", "DiktatRule")
49126
}

0 commit comments

Comments
 (0)