diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index 5237f6c5f663..5fa036661b38 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/kotlin/io/gitlab/arturbosch/detekt/core/config/validation/ConfigValidation.kt b/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/config/validation/ConfigValidation.kt index 3e6051077e36..c984a8ecebec 100644 --- a/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/config/validation/ConfigValidation.kt +++ b/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/config/validation/ConfigValidation.kt @@ -84,7 +84,8 @@ private fun validateYamlConfig( baseline: YamlConfig, excludePatterns: Set ): List { - val deprecatedProperties = loadDeprecations() + val deprecatedProperties = loadDeprecations("deprecation.properties") + val deprecatedRules = loadDeprecations("deprecation.rules") val warningsAsErrors = configToValidate .subConfig("config") .valueOrDefault("warningsAsErrors", false) @@ -92,6 +93,7 @@ private fun validateYamlConfig( val validators: List = listOf( InvalidPropertiesConfigValidator(baseline, deprecatedProperties.keys, excludePatterns), DeprecatedPropertiesConfigValidator(deprecatedProperties), + DeprecatedPropertiesConfigValidator(deprecatedRules), MissingRulesConfigValidator(baseline, excludePatterns) ) diff --git a/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/config/validation/Deprecations.kt b/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/config/validation/Deprecations.kt index 869b745f0413..d959a33c967b 100644 --- a/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/config/validation/Deprecations.kt +++ b/detekt-core/src/main/kotlin/io/gitlab/arturbosch/detekt/core/config/validation/Deprecations.kt @@ -3,9 +3,9 @@ package io.gitlab.arturbosch.detekt.core.config.validation import io.github.detekt.utils.openSafeStream import java.util.Properties -internal fun loadDeprecations(): Map { +internal fun loadDeprecations(name: String): Map { return ValidationSettings::class.java.classLoader - .getResource("deprecation.properties")!! + .getResource(name)!! .openSafeStream() .use { inputStream -> val prop = Properties().apply { load(inputStream) } diff --git a/detekt-core/src/main/resources/default-detekt-config.yml b/detekt-core/src/main/resources/default-detekt-config.yml index 764ba811aa5e..1a4a3c8e6f4d 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.rules b/detekt-core/src/main/resources/deprecation.rules new file mode 100644 index 000000000000..8f8665f501b2 --- /dev/null +++ b/detekt-core/src/main/resources/deprecation.rules @@ -0,0 +1,4 @@ +potential-bugs>DuplicateCaseInWhenExpression=Compiler performs this check by default +potential-bugs>ElseCaseInsteadOfExhaustiveWhen=Compiler performs this check by default +potential-bugs>MissingWhenCase=Compiler performs this check by default +potential-bugs>RedundantElseInWhen=Compiler performs this check by default diff --git a/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/DetektPrinter.kt b/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/DetektPrinter.kt index 7fd4075a4aff..bfbd3497bbe9 100644 --- a/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/DetektPrinter.kt +++ b/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/DetektPrinter.kt @@ -4,8 +4,10 @@ import io.github.detekt.utils.yaml import io.gitlab.arturbosch.detekt.generator.collection.RuleSetPage import io.gitlab.arturbosch.detekt.generator.out.MarkdownWriter import io.gitlab.arturbosch.detekt.generator.out.PropertiesWriter +import io.gitlab.arturbosch.detekt.generator.out.RulesWriter import io.gitlab.arturbosch.detekt.generator.out.YamlWriter import io.gitlab.arturbosch.detekt.generator.printer.DeprecatedPrinter +import io.gitlab.arturbosch.detekt.generator.printer.DeprecatedRulePrinter import io.gitlab.arturbosch.detekt.generator.printer.RuleSetPagePrinter import io.gitlab.arturbosch.detekt.generator.printer.defaultconfig.ConfigPrinter import io.gitlab.arturbosch.detekt.generator.printer.defaultconfig.printRuleSetPage @@ -16,6 +18,7 @@ class DetektPrinter(private val arguments: GeneratorArgs) { private val markdownWriter = MarkdownWriter(System.out) private val yamlWriter = YamlWriter(System.out) private val propertiesWriter = PropertiesWriter(System.out) + private val rulesWriter = RulesWriter(System.out) fun print(pages: List) { pages.forEach { @@ -31,6 +34,9 @@ class DetektPrinter(private val arguments: GeneratorArgs) { // properties from that ruleset as well. DeprecatedPrinter.print(pages) } + rulesWriter.write(arguments.configPath, "deprecation") { + DeprecatedRulePrinter.print(pages) + } yamlWriter.write(Paths.get("../detekt-formatting/src/main/resources/config"), "config") { yaml { printRuleSetPage(pages.first { it.ruleSet.name == "formatting" }) 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 0043eb04d97c..89159c3982df 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 862eb94c0d46..3edbc375b55c 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/out/AbstractWriter.kt b/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/out/AbstractWriter.kt index 835f47d94b18..30cd88d68900 100644 --- a/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/out/AbstractWriter.kt +++ b/detekt-generator/src/main/kotlin/io/gitlab/arturbosch/detekt/generator/out/AbstractWriter.kt @@ -36,3 +36,8 @@ internal class PropertiesWriter(outputPrinter: PrintStream) : AbstractWriter(out override val ending = "properties" } + +internal class RulesWriter(outputPrinter: PrintStream) : AbstractWriter(outputPrinter) { + + override val ending = "rules" +} 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 141e9a38b9d1..fdfe390aa067 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 @@ -25,3 +25,23 @@ private fun writeProperty(ruleSet: RuleSetPage, rule: Rule, configuration: Confi @Suppress("UnsafeCallOnNullableType") return "${ruleSet.ruleSet.name}>${rule.name}>${configuration.name}=${configuration.deprecated!!}" } + +object DeprecatedRulePrinter : DocumentationPrinter> { + @Suppress("NestedBlockDepth") + override fun print(item: List): String { + val builder = StringBuilder() + item.forEach { ruleSet -> + ruleSet.rules.forEach { rule -> + if (rule.isDeprecated()) { + builder.appendLine(writeRuleProperty(ruleSet, rule)) + } + } + } + return builder.toString() + } +} + +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 e412afc64d91..638507b5caff 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 483ca09d259a..0b7bdbbfadea 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 0e2690929c08..f8a7900599b5 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 @@ -16,4 +16,14 @@ class DeprecatedPrinterSpec { """.trimIndent() assertThat(markdownString).isEqualTo(expectedMarkdownString) } + + @Test + fun `prints the correct rules`() { + val markdownString = DeprecatedRulePrinter.print(listOf(createRuleSetPage())) + val expectedMarkdownString = """ + 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 8b604656f9eb..588ec303b057 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 c217da2e9ec4..4111dd2da78b 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 9943ce20efc9..eef6f0201dc2 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 f38e950eef82..3fc78eb875b3 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 c2bccfdfae8c..af5e28c7e508 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 5a4f1d28467e..b4f09b6aa6d2 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 042a03569bbd..c9983435624c 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(