From e7a5566464126acea22ebfc19e4fbff49a8ff434 Mon Sep 17 00:00:00 2001 From: Marcelo Hernandez Date: Tue, 29 Mar 2022 19:55:06 -0400 Subject: [PATCH] Add ignoreOverridden support for BooleanPropertyNaming --- .../main/resources/default-detekt-config.yml | 1 + .../rules/naming/BooleanPropertyNaming.kt | 8 +- .../rules/naming/BooleanPropertyNamingSpec.kt | 282 ++++++++++++++++++ 3 files changed, 290 insertions(+), 1 deletion(-) diff --git a/detekt-core/src/main/resources/default-detekt-config.yml b/detekt-core/src/main/resources/default-detekt-config.yml index 890d481a818..3c22d1a1adf 100644 --- a/detekt-core/src/main/resources/default-detekt-config.yml +++ b/detekt-core/src/main/resources/default-detekt-config.yml @@ -284,6 +284,7 @@ naming: BooleanPropertyNaming: active: false allowedPattern: '^(is|has|are)' + ignoreOverridden: false ClassNaming: active: true classPattern: '[A-Z][a-zA-Z0-9]*' diff --git a/detekt-rules-naming/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/naming/BooleanPropertyNaming.kt b/detekt-rules-naming/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/naming/BooleanPropertyNaming.kt index 20d0285e0f0..24c43943783 100644 --- a/detekt-rules-naming/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/naming/BooleanPropertyNaming.kt +++ b/detekt-rules-naming/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/naming/BooleanPropertyNaming.kt @@ -12,6 +12,7 @@ import io.gitlab.arturbosch.detekt.api.internal.Configuration import io.gitlab.arturbosch.detekt.api.internal.RequiresTypeResolution import io.gitlab.arturbosch.detekt.rules.fqNameOrNull import io.gitlab.arturbosch.detekt.rules.identifierName +import io.gitlab.arturbosch.detekt.rules.isOverride import org.jetbrains.kotlin.psi.KtCallableDeclaration import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.KtProperty @@ -35,6 +36,9 @@ class BooleanPropertyNaming(config: Config = Config.empty) : Rule(config) { @Configuration("naming pattern") private val allowedPattern: Regex by config("^(is|has|are)", String::toRegex) + @Configuration("ignores properties that have the override modifier") + private val ignoreOverridden: Boolean by config(false) + override val issue = Issue( javaClass.simpleName, Severity.CodeSmell, "Boolean property name should follow the naming convention set in the projects configuration.", @@ -65,7 +69,7 @@ class BooleanPropertyNaming(config: Config = Config.empty) : Rule(config) { val isBooleanType = typeName == KOTLIN_BOOLEAN_TYPE_NAME || typeName == JAVA_BOOLEAN_TYPE_NAME - if (isBooleanType && !name.contains(allowedPattern)) { + if (isBooleanType && !name.contains(allowedPattern) && !isIgnoreOverridden(declaration)) { report(reportCodeSmell(declaration, name)) } } @@ -89,6 +93,8 @@ class BooleanPropertyNaming(config: Config = Config.empty) : Rule(config) { .toString() } + private fun isIgnoreOverridden(declaration: KtCallableDeclaration) = ignoreOverridden && declaration.isOverride() + companion object { const val KOTLIN_BOOLEAN_TYPE_NAME = "kotlin.Boolean" const val JAVA_BOOLEAN_TYPE_NAME = "java.lang.Boolean" diff --git a/detekt-rules-naming/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/naming/BooleanPropertyNamingSpec.kt b/detekt-rules-naming/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/naming/BooleanPropertyNamingSpec.kt index b75642192c5..9edb73fbb97 100644 --- a/detekt-rules-naming/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/naming/BooleanPropertyNamingSpec.kt +++ b/detekt-rules-naming/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/naming/BooleanPropertyNamingSpec.kt @@ -26,6 +26,35 @@ class BooleanPropertyNamingSpec(val env: KotlinCoreEnvironment) { assertThat(findings).hasSize(1) } + @Test + fun `should warn about Kotlin Boolean override`() { + val code = """ + interface Test { + val default: Boolean + } + + data class TestImpl (override var default: Boolean) : Test + """ + val findings = subject.compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(2) + } + + @Test + fun `should not warn about Kotlin Boolean override if ignoreOverridden is true`() { + val code = """ + interface Test { + val default: Boolean + } + + data class TestImpl (override var default: Boolean) : Test + """ + val config = TestConfig(mapOf(IGNORE_OVERRIDDEN to true)) + val findings = BooleanPropertyNaming(config).compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(1) + } + @Test fun `should warn about Kotlin Boolean nullable`() { val code = """data class Test (var default: Boolean?)""" @@ -34,6 +63,35 @@ class BooleanPropertyNamingSpec(val env: KotlinCoreEnvironment) { assertThat(findings).hasSize(1) } + @Test + fun `should warn about Kotlin Boolean nullable override`() { + val code = """ + interface Test { + val default: Boolean? + } + + data class TestImpl (override var default: Boolean?) : Test + """ + val findings = subject.compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(2) + } + + @Test + fun `should not warn about Kotlin Boolean nullable override if ignoreOverridden is true`() { + val code = """ + interface Test { + val default: Boolean? + } + + data class TestImpl (override var default: Boolean?) : Test + """ + val config = TestConfig(mapOf(IGNORE_OVERRIDDEN to true)) + val findings = BooleanPropertyNaming(config).compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(1) + } + @Test fun `should warn about Kotlin Boolean initialized`() { val code = """data class Test (var default: Boolean = false)""" @@ -42,6 +100,35 @@ class BooleanPropertyNamingSpec(val env: KotlinCoreEnvironment) { assertThat(findings).hasSize(1) } + @Test + fun `should warn about Kotlin Boolean initialized override`() { + val code = """ + interface Test { + val default: Boolean + } + + data class TestImpl (override var default: Boolean = false) : Test + """ + val findings = subject.compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(2) + } + + @Test + fun `should not warn about Kotlin Boolean initialized override if ignoreOverridden is true`() { + val code = """ + interface Test { + val default: Boolean + } + + data class TestImpl (override var default: Boolean = false) : Test + """ + val config = TestConfig(mapOf(IGNORE_OVERRIDDEN to true)) + val findings = BooleanPropertyNaming(config).compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(1) + } + @Test fun `should warn about Java Boolean`() { val code = """data class Test (var default: java.lang.Boolean)""" @@ -50,6 +137,35 @@ class BooleanPropertyNamingSpec(val env: KotlinCoreEnvironment) { assertThat(findings).hasSize(1) } + @Test + fun `should warn about Java Boolean override`() { + val code = """ + interface Test { + val default: java.lang.Boolean + } + + data class TestImpl (override var default: java.lang.Boolean) : Test + """ + val findings = subject.compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(2) + } + + @Test + fun `should not warn about Java Boolean override if ignoreOverridden is true`() { + val code = """ + interface Test { + val default: java.lang.Boolean + } + + data class TestImpl (override var default: java.lang.Boolean) : Test + """ + val config = TestConfig(mapOf(IGNORE_OVERRIDDEN to true)) + val findings = BooleanPropertyNaming(config).compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(1) + } + @Test fun `should not detect primitive types`() { val code = """data class Test (var count: Int)""" @@ -81,6 +197,39 @@ class BooleanPropertyNamingSpec(val env: KotlinCoreEnvironment) { assertThat(findings).hasSize(1) } + @Test + fun `should warn about Kotlin Boolean override`() { + val code = """ + interface Test { + val default: Boolean + } + + class TestImpl : Test { + override var default: Boolean = true + } + """ + val findings = subject.compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(2) + } + + @Test + fun `should not warn about Kotlin Boolean override if isIgnoreOverridden is true`() { + val code = """ + interface Test { + val default: Boolean + } + + class TestImpl : Test { + override var default: Boolean = true + } + """ + val config = TestConfig(mapOf(IGNORE_OVERRIDDEN to true)) + val findings = BooleanPropertyNaming(config).compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(1) + } + @Test fun `should warn about Kotlin Boolean nullable`() { val code = """ @@ -93,6 +242,39 @@ class BooleanPropertyNamingSpec(val env: KotlinCoreEnvironment) { assertThat(findings).hasSize(1) } + @Test + fun `should warn about Kotlin Boolean nullable override`() { + val code = """ + interface Test { + val default: Boolean? + } + + class TestImpl : Test { + override var default: Boolean? = null + } + """ + val findings = subject.compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(2) + } + + @Test + fun `should not warn about Kotlin Boolean nullable override if ignoreOverridden is true`() { + val code = """ + interface Test { + val default: Boolean? + } + + class TestImpl : Test { + override var default: Boolean? = null + } + """ + val config = TestConfig(mapOf(IGNORE_OVERRIDDEN to true)) + val findings = BooleanPropertyNaming(config).compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(1) + } + @Test fun `should warn about Kotlin Boolean initialized`() { val code = """ @@ -105,6 +287,39 @@ class BooleanPropertyNamingSpec(val env: KotlinCoreEnvironment) { assertThat(findings).hasSize(1) } + @Test + fun `should warn about Kotlin Boolean initialized override`() { + val code = """ + interface Test { + val default: Boolean + } + + class TestImpl : Test { + override var default: Boolean = false + } + """ + val findings = subject.compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(2) + } + + @Test + fun `should not warn about Kotlin Boolean initialized override if ignoreOverridden is true`() { + val code = """ + interface Test { + val default: Boolean + } + + class TestImpl : Test { + override var default: Boolean = false + } + """ + val config = TestConfig(mapOf(IGNORE_OVERRIDDEN to true)) + val findings = BooleanPropertyNaming(config).compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(1) + } + @Test fun `should warn about inferred boolean type`() { val code = """ @@ -117,6 +332,39 @@ class BooleanPropertyNamingSpec(val env: KotlinCoreEnvironment) { assertThat(findings).hasSize(1) } + @Test + fun `should warn about inferred boolean type override`() { + val code = """ + interface Test { + val default: Boolean + } + + class TestImpl : Test { + override var default = true + } + """ + val findings = subject.compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(2) + } + + @Test + fun `should not warn about inferred boolean type override if ignoreOverridden is true`() { + val code = """ + interface Test { + val default: Boolean + } + + class TestImpl : Test { + override var default = true + } + """ + val config = TestConfig(mapOf(IGNORE_OVERRIDDEN to true)) + val findings = BooleanPropertyNaming(config).compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(1) + } + @Test fun `should warn about Java Boolean`() { val code = """ @@ -129,6 +377,39 @@ class BooleanPropertyNamingSpec(val env: KotlinCoreEnvironment) { assertThat(findings).hasSize(1) } + @Test + fun `should warn about Java Boolean override`() { + val code = """ + interface Test { + val default: java.lang.Boolean + } + + class TestImpl : Test { + override var default: java.lang.Boolean = java.lang.Boolean(true) + } + """ + val findings = subject.compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(2) + } + + @Test + fun `should not warn about Java Boolean override if ignoreOverridden is true`() { + val code = """ + interface Test { + val default: java.lang.Boolean + } + + class TestImpl : Test { + override var default: java.lang.Boolean = java.lang.Boolean(true) + } + """ + val config = TestConfig(mapOf(IGNORE_OVERRIDDEN to true)) + val findings = BooleanPropertyNaming(config).compileAndLintWithContext(env, code) + + assertThat(findings).hasSize(1) + } + @Test fun `should not detect primitive types`() { val code = """ @@ -171,3 +452,4 @@ class BooleanPropertyNamingSpec(val env: KotlinCoreEnvironment) { } private const val ALLOWED_PATTERN = "allowedPattern" +private const val IGNORE_OVERRIDDEN = "ignoreOverridden"