Skip to content

Commit

Permalink
Add rule deprecation mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
VitalyVPinchuk committed Sep 18, 2022
1 parent 15c19aa commit 3f08963
Show file tree
Hide file tree
Showing 16 changed files with 66 additions and 16 deletions.
2 changes: 0 additions & 2 deletions config/detekt/detekt.yml
Expand Up @@ -124,8 +124,6 @@ potential-bugs:
active: true
DoubleMutabilityForCollection:
active: false
ElseCaseInsteadOfExhaustiveWhen:
active: true
ExitOutsideMain:
active: false
HasPlatformType:
Expand Down
9 changes: 0 additions & 9 deletions detekt-core/src/main/resources/default-detekt-config.yml
Expand Up @@ -419,10 +419,6 @@ potential-bugs:
- 'java.util.HashSet'
- 'java.util.LinkedHashMap'
- 'java.util.HashMap'
DuplicateCaseInWhenExpression:
active: true
ElseCaseInsteadOfExhaustiveWhen:
active: false
EqualsAlwaysReturnsTrueOrFalse:
active: true
EqualsWithHashCodeExist:
Expand Down Expand Up @@ -466,15 +462,10 @@ potential-bugs:
MissingPackageDeclaration:
active: false
excludes: ['**/*.kts']
MissingWhenCase:
active: true
allowElseExpression: true
NullCheckOnMutableProperty:
active: false
NullableToStringCall:
active: false
RedundantElseInWhen:
active: true
UnconditionalJumpStatementInLoop:
active: false
UnnecessaryNotNullOperator:
Expand Down
4 changes: 4 additions & 0 deletions detekt-core/src/main/resources/deprecation.properties
@@ -1,7 +1,11 @@
complexity>LongParameterList>threshold=Use `functionThreshold` and `constructorThreshold` instead
empty-blocks>EmptyFunctionBlock>ignoreOverriddenFunctions=Use `ignoreOverridden` instead
potential-bugs>DuplicateCaseInWhenExpression=Compiler performs this check by default
potential-bugs>ElseCaseInsteadOfExhaustiveWhen=Compiler performs this check by default
potential-bugs>IgnoredReturnValue>restrictToAnnotatedMethods=Use `restrictToConfig` instead
potential-bugs>LateinitUsage>excludeAnnotatedProperties=Use `ignoreAnnotated` instead
potential-bugs>MissingWhenCase=Compiler performs this check by default
potential-bugs>RedundantElseInWhen=Compiler performs this check by default
naming>FunctionParameterNaming>ignoreOverriddenFunctions=Use `ignoreOverridden` instead
naming>MemberNameEqualsClassName>ignoreOverriddenFunction=Use `ignoreOverridden` instead
style>FunctionOnlyReturningConstant>excludeAnnotatedFunction=Use `ignoreAnnotated` instead
Expand Down
Expand Up @@ -13,5 +13,8 @@ data class Rule(
val configuration: List<Configuration> = emptyList(),
val autoCorrect: Boolean = false,
var inMultiRule: String? = null,
val requiresTypeResolution: Boolean = false
)
val requiresTypeResolution: Boolean = false,
val deprecated: String? = null
) {
fun isDeprecated() = deprecated != null
}
Expand Up @@ -35,6 +35,7 @@ internal class RuleVisitor : DetektVisitor() {
private var parent = ""
private val configurationCollector = ConfigurationCollector()
private val classesMap = mutableMapOf<String, Boolean>()
private var deprecationMessage: String? = null

fun getRule(): Rule {
if (documentationCollector.description.isEmpty()) {
Expand All @@ -55,6 +56,7 @@ internal class RuleVisitor : DetektVisitor() {
parent = parent,
configuration = configurationByAnnotation,
autoCorrect = autoCorrect,
deprecated = deprecationMessage,
requiresTypeResolution = requiresTypeResolution
)
}
Expand Down Expand Up @@ -105,6 +107,7 @@ internal class RuleVisitor : DetektVisitor() {

autoCorrect = classOrObject.isAnnotatedWith(AutoCorrectable::class)
requiresTypeResolution = classOrObject.isAnnotatedWith(RequiresTypeResolution::class)
deprecationMessage = classOrObject.firstAnnotationParameterOrNull(Deprecated::class)

documentationCollector.setClass(classOrObject)
}
Expand Down
Expand Up @@ -10,6 +10,9 @@ object DeprecatedPrinter : DocumentationPrinter<List<RuleSetPage>> {
val builder = StringBuilder()
item.forEach { ruleSet ->
ruleSet.rules.forEach { rule ->
if (rule.isDeprecated()) {
builder.appendLine(writeRuleProperty(ruleSet, rule))
}
rule.configuration.forEach { configuration ->
if (configuration.isDeprecated()) {
builder.appendLine(writeProperty(ruleSet, rule, configuration))
Expand All @@ -25,3 +28,8 @@ private fun writeProperty(ruleSet: RuleSetPage, rule: Rule, configuration: Confi
@Suppress("UnsafeCallOnNullableType")
return "${ruleSet.ruleSet.name}>${rule.name}>${configuration.name}=${configuration.deprecated!!}"
}

private fun writeRuleProperty(ruleSet: RuleSetPage, rule: Rule): String {
@Suppress("UnsafeCallOnNullableType")
return "${ruleSet.ruleSet.name}>${rule.name}=${rule.deprecated!!}"
}
Expand Up @@ -30,6 +30,8 @@ internal fun YamlNode.printRuleSet(ruleSet: RuleSetProvider, rules: List<Rule>)
}

internal fun YamlNode.printRule(rule: Rule) {
if (rule.isDeprecated()) return

node(rule.name) {
keyValue { Config.ACTIVE_KEY to "${rule.defaultActivationStatus.active}" }
if (rule.autoCorrect) {
Expand Down
Expand Up @@ -77,6 +77,9 @@ class ConfigAssert(
private fun getRuleClassesInPackage(): List<Class<out Rule>> {
return Reflections(packageName)
.getSubTypesOf(Rule::class.java)
.filter { !Modifier.isAbstract(it.modifiers) }
.filter { rule ->
!Modifier.isAbstract(rule.modifiers) &&
rule.annotations.none { it.annotationClass == Deprecated::class }
}
}
}
Expand Up @@ -12,7 +12,8 @@ class DeprecatedPrinterSpec {
val expectedMarkdownString = """
style>MagicNumber>conf2=use conf1 instead
style>MagicNumber>conf4=use conf3 instead
style>DuplicateCaseInWhenExpression=is deprecated
""".trimIndent()
assertThat(markdownString).isEqualTo(expectedMarkdownString)
}
Expand Down
Expand Up @@ -18,6 +18,7 @@ internal class RulePrinterTest {
debt = "10min",
aliases = "alias1, alias2",
parent = "",
deprecated = "deprecated",
)

@Test
Expand Down
Expand Up @@ -102,5 +102,17 @@ internal fun createRules(): List<Rule> {
autoCorrect = true,
requiresTypeResolution = true
)
return listOf(rule1, rule2, rule3)
val rule4 = Rule(
name = "DuplicateCaseInWhenExpression",
description = "Duplicated `case` statements in a `when` expression detected.",
nonCompliantCodeExample = "fun stuff(): Unit {}",
compliantCodeExample = "fun stuff() {}",
defaultActivationStatus = Active(since = "1.16.0"),
severity = "",
debt = "5m",
aliases = null,
parent = "",
deprecated = "is deprecated"
)
return listOf(rule1, rule2, rule3, rule4)
}
20 changes: 20 additions & 0 deletions detekt-generator/src/test/resources/RuleSet.md
Expand Up @@ -75,3 +75,23 @@ fun stuff(): Unit {}
```kotlin
fun stuff() {}
```

### DuplicateCaseInWhenExpression

Duplicated `case` statements in a `when` expression detected.

**Active by default**: Yes - Since v1.16.0

**Debt**: 5m

#### Noncompliant Code:

```kotlin
fun stuff(): Unit {}
```

#### Compliant Code:

```kotlin
fun stuff() {}
```
Expand Up @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.psi.KtWhenExpression
* </compliant>
*/
@ActiveByDefault(since = "1.0.0")
@Deprecated("Compiler performs this check by default")
class DuplicateCaseInWhenExpression(config: Config) : Rule(config) {

override val issue = Issue(
Expand Down
Expand Up @@ -50,6 +50,7 @@ import org.jetbrains.kotlin.types.typeUtil.isBooleanOrNullableBoolean
* </compliant>
*/
@RequiresTypeResolution
@Deprecated("Compiler performs this check by default")
class ElseCaseInsteadOfExhaustiveWhen(config: Config = Config.empty) : Rule(config) {

override val issue: Issue = Issue(
Expand Down
Expand Up @@ -68,6 +68,7 @@ import org.jetbrains.kotlin.resolve.calls.util.getType
*/
@ActiveByDefault(since = "1.2.0")
@RequiresTypeResolution
@Deprecated("Compiler performs this check by default")
class MissingWhenCase(config: Config = Config.empty) : Rule(config) {

override val issue: Issue = Issue(
Expand Down
Expand Up @@ -59,6 +59,7 @@ import org.jetbrains.kotlin.psi.KtWhenExpression
*/
@RequiresTypeResolution
@ActiveByDefault(since = "1.2.0")
@Deprecated("Compiler performs this check by default")
class RedundantElseInWhen(config: Config = Config.empty) : Rule(config) {

override val issue: Issue = Issue(
Expand Down

0 comments on commit 3f08963

Please sign in to comment.