From 1b330e9e42a385a588c9f61021f2da6ae7495a92 Mon Sep 17 00:00:00 2001 From: gouri-panda Date: Sun, 10 Jul 2022 15:56:49 +0530 Subject: [PATCH] Removed UnnecessaryAbstractClass if it inherits from a abstract class (#5009) * Removed UnnecessaryAbstractClass if it inherits from an interface or abstract class that has concrete members Removed deprecated annotations Revert "Removed deprecated annotations" This reverts commit 326a356e fix return count rule violation * Removed UnnecessaryAbstractClass if it inherits from an interface or abstract class that has concrete members Removed deprecated annotations Revert "Removed deprecated annotations" This reverts commit 326a356e fix return count rule violation * Handle corner case of multiple inheritance in UnnecessaryAbstractClass rule Co-authored-by: Amit Dash --- .../rules/style/UnnecessaryAbstractClass.kt | 8 +++++ .../style/UnnecessaryAbstractClassSpec.kt | 31 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryAbstractClass.kt b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryAbstractClass.kt index 20f4b9f2de5..84487eb3929 100644 --- a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryAbstractClass.kt +++ b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryAbstractClass.kt @@ -22,6 +22,8 @@ import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.psiUtil.isAbstract import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassMemberScope +import org.jetbrains.kotlin.types.typeUtil.isInterface /** * This rule inspects `abstract` classes. In case an `abstract class` does not have any concrete members it should be @@ -86,6 +88,7 @@ class UnnecessaryAbstractClass(config: Config = Config.empty) : Rule(config) { val members = members() when { members.isNotEmpty() -> checkMembers(members, nameIdentifier) + hasInheritedMember(true) && isAnyParentAbstract() -> return !hasConstructorParameter() -> report(CodeSmell(issue, Entity.from(nameIdentifier), noConcreteMember)) else -> @@ -125,4 +128,9 @@ class UnnecessaryAbstractClass(config: Config = Config.empty) : Rule(config) { } } } + + private fun KtClass.isAnyParentAbstract() = + (bindingContext[BindingContext.CLASS, this]?.unsubstitutedMemberScope as? LazyClassMemberScope) + ?.supertypes + ?.all { it.isInterface() } == false } diff --git a/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryAbstractClassSpec.kt b/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryAbstractClassSpec.kt index ba65e69f96c..d9b65a797bd 100644 --- a/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryAbstractClassSpec.kt +++ b/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryAbstractClassSpec.kt @@ -86,8 +86,37 @@ class UnnecessaryAbstractClassSpec(val env: KotlinCoreEnvironment) { } abstract class B : A() """ + assertThat(subject.compileAndLintWithContext(env, code)).isEmpty() + } + + @Test + fun `does not report abstract class that inherits from an abstract class and an interface in that order`() { + val code = """ + interface I + + @Deprecated("We don't care about this first class") + abstract class A { + abstract val i: Int + } + abstract class B: A(), I + """ val findings = subject.compileAndLintWithContext(env, code) - assertFindingMessage(findings, message) + assertThat(findings).isEmpty() + } + + @Test + fun `does not report abstract class that inherits from an interface and an abstract class in that order`() { + val code = """ + interface I + + @Deprecated("We don't care about this first class") + abstract class A { + abstract val i: Int + } + abstract class B: I, A() + """ + val findings = subject.compileAndLintWithContext(env, code) + assertThat(findings).isEmpty() } }