Skip to content

Commit e8dbfb0

Browse files
Fix the race condition introduced with 3470888 (#1555)
### What's done: - Original issue: #1548. - Original PR: #1553. - This change reverts 3470888. - Enhances the KDoc of `DiktatRule`. - Fixes #1548.
1 parent 0cb47bb commit e8dbfb0

File tree

3 files changed

+28
-28
lines changed

3 files changed

+28
-28
lines changed

diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/rules/RulesConfigReader.kt

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import java.io.File
1818
import java.util.Locale
1919
import java.util.concurrent.atomic.AtomicInteger
2020

21-
import kotlinx.serialization.ExperimentalSerializationApi
2221
import kotlinx.serialization.Serializable
2322
import kotlinx.serialization.decodeFromString
2423

@@ -84,7 +83,6 @@ open class RulesConfigReader(override val classLoader: ClassLoader) : JsonResour
8483
* @param fileStream a [BufferedReader] representing loaded rules config file
8584
* @return list of [RulesConfig]
8685
*/
87-
@OptIn(ExperimentalSerializationApi::class)
8886
override fun parseResource(fileStream: BufferedReader): List<RulesConfig> = fileStream.use { stream ->
8987
yamlSerializer.decodeFromString<List<RulesConfig>>(stream.readLines().joinToString(separator = "\n")).reversed().distinctBy { it.name }
9088
}
@@ -99,19 +97,16 @@ open class RulesConfigReader(override val classLoader: ClassLoader) : JsonResour
9997
override fun getConfigFile(resourceFileName: String): BufferedReader? {
10098
val resourceFile = File(resourceFileName)
10199
return if (resourceFile.exists()) {
102-
log.debug("Using diktat-analysis.yml file from the following path: ${resourceFile.absolutePath}")
100+
log.debug("Using $DIKTAT_ANALYSIS_CONF file from the following path: ${resourceFile.absolutePath}")
103101
File(resourceFileName).bufferedReader()
104102
} else {
105-
log.debug("Using the default diktat-analysis.yml file from the class path")
103+
log.debug("Using the default $DIKTAT_ANALYSIS_CONF file from the class path")
106104
classLoader.getResourceAsStream(resourceFileName)?.bufferedReader()
107105
}
108106
}
109107

110108
companion object {
111-
/**
112-
* A [Logger] that can be used
113-
*/
114-
val log: KLogger = KotlinLogging.loggerWithKtlintConfig(RulesConfigReader::class)
109+
internal val log: KLogger = KotlinLogging.loggerWithKtlintConfig(RulesConfigReader::class)
115110
}
116111
}
117112

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode
1414
private typealias DiktatConfigRule = org.cqfn.diktat.common.config.rules.Rule
1515

1616
/**
17-
* This is a wrapper around Ktlint Rule
17+
* This is a wrapper around _KtLint_ `Rule`.
1818
*
1919
* @param id id of the rule
2020
* @property configRules all rules from configuration
@@ -33,7 +33,17 @@ abstract class DiktatRule(
3333
var isFixMode: Boolean = false
3434

3535
/**
36-
* Will be initialized in visit
36+
* The **file-specific** error emitter, initialized in
37+
* [beforeVisitChildNodes] and used in [logic] implementations.
38+
*
39+
* Since the file is indirectly a part of the state of a `Rule`, the same
40+
* `Rule` instance should **never be re-used** to check more than a single
41+
* file, or confusing effects (incl. race conditions) will occur.
42+
* See the documentation of the [Rule] class for more details.
43+
*
44+
* @see Rule
45+
* @see beforeVisitChildNodes
46+
* @see logic
3747
*/
3848
lateinit var emitWarn: EmitType
3949

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

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -108,16 +108,7 @@ class DiktatRuleSetProvider(private var diktatConfigFile: String = DIKTAT_ANALYS
108108
yield(resolveConfigFileFromJarLocation())
109109
yield(resolveConfigFileFromSystemProperty())
110110
}
111-
112-
/**
113-
* As of _KtLint_ **0.47**, each rule is expected to have a state and is executed
114-
* twice per file, and a new `Rule` instance is created per each file checked.
115-
*
116-
* Diktat rules have no mutable state yet and use the deprecated _KtLint_
117-
* API, so we initialize them only _once_ for performance reasons and also
118-
* to avoid redundant logging.
119-
*/
120-
private val ruleSet: RuleSet by lazy {
111+
private val configRules: List<RulesConfig> by lazy {
121112
log.debug("Will run $DIKTAT_RULE_SET_ID with $diktatConfigFile" +
122113
" (it can be placed to the run directory or the default file from resources will be used)")
123114
val configPath = possibleConfigs
@@ -137,10 +128,20 @@ class DiktatRuleSetProvider(private var diktatConfigFile: String = DIKTAT_ANALYS
137128
diktatConfigFile
138129
}
139130

140-
val configRules = RulesConfigReader(javaClass.classLoader)
131+
RulesConfigReader(javaClass.classLoader)
141132
.readResource(diktatConfigFile)
142133
?.onEach(::validate)
143134
?: emptyList()
135+
}
136+
137+
@Suppress(
138+
"LongMethod",
139+
"TOO_LONG_FUNCTION",
140+
)
141+
@Deprecated(
142+
"Marked for removal in KtLint 0.48. See changelog or KDoc for more information.",
143+
)
144+
override fun get(): RuleSet {
144145
// Note: the order of rules is important in autocorrect mode. For example, all rules that add new code should be invoked before rules that fix formatting.
145146
// We don't have a way to enforce a specific order, so we should just be careful when adding new rules to this list and, when possible,
146147
// cover new rules in smoke test as well. If a rule needs to be at a specific position in a list, please add comment explaining it (like for NewlinesRule).
@@ -229,18 +230,12 @@ class DiktatRuleSetProvider(private var diktatConfigFile: String = DIKTAT_ANALYS
229230
.map {
230231
it.invoke(configRules)
231232
}
232-
RuleSet(
233+
return RuleSet(
233234
DIKTAT_RULE_SET_ID,
234235
rules = rules.toTypedArray()
235236
).ordered()
236237
}
237238

238-
@Deprecated(
239-
"Marked for removal in KtLint 0.48. See changelog or KDoc for more information.",
240-
)
241-
override fun get(): RuleSet =
242-
ruleSet
243-
244239
private fun validate(config: RulesConfig) =
245240
require(config.name == DIKTAT_COMMON || config.name in Warnings.names) {
246241
val closestMatch = Warnings.names.minByOrNull { Levenshtein.distance(it, config.name) }

0 commit comments

Comments
 (0)