From 3f089631a652fc6746076bc7ad9075cd5aa953e4 Mon Sep 17 00:00:00 2001 From: "Vitaly V. Pinchuk" Date: Fri, 16 Sep 2022 16:45:27 +0300 Subject: [PATCH] Add rule deprecation mechanism --- config/detekt/detekt.yml | 2 -- .../main/resources/default-detekt-config.yml | 9 --------- .../src/main/resources/deprecation.properties | 4 ++++ .../detekt/generator/collection/Rule.kt | 7 +++++-- .../generator/collection/RuleVisitor.kt | 3 +++ .../generator/printer/DeprecatedPrinter.kt | 8 ++++++++ .../defaultconfig/RuleSetConfigPrinter.kt | 2 ++ .../detekt/generator/config/ConfigAssert.kt | 5 ++++- .../printer/DeprecatedPrinterSpec.kt | 3 ++- .../generator/printer/RulePrinterTest.kt | 1 + .../generator/util/RuleSetPageCreator.kt | 14 ++++++++++++- .../src/test/resources/RuleSet.md | 20 +++++++++++++++++++ .../bugs/DuplicateCaseInWhenExpression.kt | 1 + .../bugs/ElseCaseInsteadOfExhaustiveWhen.kt | 1 + .../detekt/rules/bugs/MissingWhenCase.kt | 1 + .../detekt/rules/bugs/RedundantElseInWhen.kt | 1 + 16 files changed, 66 insertions(+), 16 deletions(-) diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index 5237f6c5f66..5fa036661b3 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -124,8 +124,6 @@ potential-bugs: active: true DoubleMutabilityForCollection: active: false - ElseCaseInsteadOfExhaustiveWhen: - active: true ExitOutsideMain: active: false HasPlatformType: diff --git a/detekt-core/src/main/resources/default-detekt-config.yml b/detekt-core/src/main/resources/default-detekt-config.yml index 764ba811aa5..1a4a3c8e6f4 100644 --- a/detekt-core/src/main/resources/default-detekt-config.yml +++ b/detekt-core/src/main/resources/default-detekt-config.yml @@ -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: @@ -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: diff --git a/detekt-core/src/main/resources/deprecation.properties b/detekt-core/src/main/resources/deprecation.properties index 7d9a994a4b1..cfa8440fa8d 100644 --- a/detekt-core/src/main/resources/deprecation.properties +++ b/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 diff --git a/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/Rule.kt b/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/Rule.kt index 0043eb04d97..89159c3982d 100644 --- a/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/Rule.kt +++ b/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/Rule.kt @@ -13,5 +13,8 @@ data class Rule( val configuration: List = 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 +} diff --git a/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/RuleVisitor.kt b/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/RuleVisitor.kt index 862eb94c0d4..3edbc375b55 100644 --- a/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/RuleVisitor.kt +++ b/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/collection/RuleVisitor.kt @@ -35,6 +35,7 @@ internal class RuleVisitor : DetektVisitor() { private var parent = "" private val configurationCollector = ConfigurationCollector() private val classesMap = mutableMapOf() + private var deprecationMessage: String? = null fun getRule(): Rule { if (documentationCollector.description.isEmpty()) { @@ -55,6 +56,7 @@ internal class RuleVisitor : DetektVisitor() { parent = parent, configuration = configurationByAnnotation, autoCorrect = autoCorrect, + deprecated = deprecationMessage, requiresTypeResolution = requiresTypeResolution ) } @@ -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) } diff --git a/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/printer/DeprecatedPrinter.kt b/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/printer/DeprecatedPrinter.kt index 141e9a38b9d..3a2e743081f 100644 --- a/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/printer/DeprecatedPrinter.kt +++ b/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/printer/DeprecatedPrinter.kt @@ -10,6 +10,9 @@ object DeprecatedPrinter : DocumentationPrinter> { 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)) @@ -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!!}" +} diff --git a/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/printer/defaultconfig/RuleSetConfigPrinter.kt b/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/printer/defaultconfig/RuleSetConfigPrinter.kt index e412afc64d9..638507b5caf 100644 --- a/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/printer/defaultconfig/RuleSetConfigPrinter.kt +++ b/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/printer/defaultconfig/RuleSetConfigPrinter.kt @@ -30,6 +30,8 @@ internal fun YamlNode.printRuleSet(ruleSet: RuleSetProvider, rules: List) } internal fun YamlNode.printRule(rule: Rule) { + if (rule.isDeprecated()) return + node(rule.name) { keyValue { Config.ACTIVE_KEY to "${rule.defaultActivationStatus.active}" } if (rule.autoCorrect) { diff --git a/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/config/ConfigAssert.kt b/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/config/ConfigAssert.kt index 483ca09d259..0b7bdbbfade 100644 --- a/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/config/ConfigAssert.kt +++ b/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/config/ConfigAssert.kt @@ -77,6 +77,9 @@ class ConfigAssert( private fun getRuleClassesInPackage(): List> { 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 } + } } } diff --git a/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/printer/DeprecatedPrinterSpec.kt b/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/printer/DeprecatedPrinterSpec.kt index 0e2690929c0..ec694b070b9 100644 --- a/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/printer/DeprecatedPrinterSpec.kt +++ b/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/printer/DeprecatedPrinterSpec.kt @@ -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) } diff --git a/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/printer/RulePrinterTest.kt b/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/printer/RulePrinterTest.kt index 8b604656f9e..588ec303b05 100644 --- a/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/printer/RulePrinterTest.kt +++ b/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/printer/RulePrinterTest.kt @@ -18,6 +18,7 @@ internal class RulePrinterTest { debt = "10min", aliases = "alias1, alias2", parent = "", + deprecated = "deprecated", ) @Test diff --git a/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/util/RuleSetPageCreator.kt b/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/util/RuleSetPageCreator.kt index c217da2e9ec..4111dd2da78 100644 --- a/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/util/RuleSetPageCreator.kt +++ b/detekt-generator/src/test/kotlin/io/gitlab/arturbosch/detekt/generator/util/RuleSetPageCreator.kt @@ -102,5 +102,17 @@ internal fun createRules(): List { 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) } diff --git a/detekt-generator/src/test/resources/RuleSet.md b/detekt-generator/src/test/resources/RuleSet.md index 9943ce20efc..eef6f0201dc 100644 --- a/detekt-generator/src/test/resources/RuleSet.md +++ b/detekt-generator/src/test/resources/RuleSet.md @@ -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() {} +``` diff --git a/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/DuplicateCaseInWhenExpression.kt b/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/DuplicateCaseInWhenExpression.kt index f38e950eef8..3fc78eb875b 100644 --- a/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/DuplicateCaseInWhenExpression.kt +++ b/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/DuplicateCaseInWhenExpression.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.psi.KtWhenExpression * */ @ActiveByDefault(since = "1.0.0") +@Deprecated("Compiler performs this check by default") class DuplicateCaseInWhenExpression(config: Config) : Rule(config) { override val issue = Issue( diff --git a/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/ElseCaseInsteadOfExhaustiveWhen.kt b/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/ElseCaseInsteadOfExhaustiveWhen.kt index c2bccfdfae8..af5e28c7e50 100644 --- a/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/ElseCaseInsteadOfExhaustiveWhen.kt +++ b/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/ElseCaseInsteadOfExhaustiveWhen.kt @@ -50,6 +50,7 @@ import org.jetbrains.kotlin.types.typeUtil.isBooleanOrNullableBoolean * */ @RequiresTypeResolution +@Deprecated("Compiler performs this check by default") class ElseCaseInsteadOfExhaustiveWhen(config: Config = Config.empty) : Rule(config) { override val issue: Issue = Issue( diff --git a/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/MissingWhenCase.kt b/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/MissingWhenCase.kt index 5a4f1d28467..b4f09b6aa6d 100644 --- a/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/MissingWhenCase.kt +++ b/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/MissingWhenCase.kt @@ -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( diff --git a/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/RedundantElseInWhen.kt b/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/RedundantElseInWhen.kt index 042a03569bb..c9983435624 100644 --- a/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/RedundantElseInWhen.kt +++ b/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/RedundantElseInWhen.kt @@ -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(