-
-
Notifications
You must be signed in to change notification settings - Fork 783
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Removed UnnecessaryAbstractClass if it inherits from a abstract class #5009
Conversation
@@ -73,8 +73,7 @@ class UnnecessaryAbstractClassSpec(val env: KotlinCoreEnvironment) { | |||
} | |||
abstract class B : A | |||
""" | |||
val findings = subject.compileAndLintWithContext(env, code) | |||
assertFindingMessage(findings, message) | |||
assertThat(subject.compileAndLintWithContext(env, code)).isEmpty() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test shouldn't change, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BraisGabin If we don't change it, the tests will fail. I don't understand your question.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But this one was right. An abstract class that only extends an interface is an unnecessary abstract class. The only one that should change is the case where an abstract class extend another abstract class because there you can't use an interface. (maybe I'm missing something here)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I revert that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. This test shouldn't change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the fix - appreciate it!
...tyle/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryAbstractClassSpec.kt
Outdated
Show resolved
Hide resolved
@gouri-panda please try to rebase this branch and fix the following rule violation. Then this PR is good to go. 👍
|
@@ -98,6 +98,7 @@ class UnnecessaryAbstractClass(config: Config = Config.empty) : Rule(config) { | |||
report(CodeSmell(issue, Entity.from(nameIdentifier), noConcreteMember)) | |||
} | |||
} | |||
hasInheritedMember(true) -> return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The following enhancement to this logic will ensure the rule still fails for interface
super types (as discussed in @BraisGabin's comment):
hasInheritedMember(true) && !isParentInterface() -> return
private fun KtClass.isParentInterface() =
(bindingContext[BindingContext.CLASS, this]?.unsubstitutedMemberScope as? LazyClassMemberScope)
?.supertypes?.firstOrNull()?.isInterface() == true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@amitdash291 Thanks for advice and code :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there's a corner case to test here. What if the class implements an interface and inherits from an abstract class in that order. For eg the following may fail the rule whereas it's expected to pass:
interface I
abstract class A
// some abstract fields here
abstract class B: I, A()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that even valid Kotlin code? Shouldn't the class be defined the first one? I can't check right now. Anyway, a test extending both, a class and an interface seems like a really good case to have a test. @guori-panda, can you add such test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BraisGabin yes interestingly this is valid Kotlin code, given below is the test case (that compiles):
@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()
}
...tyle/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryAbstractClassSpec.kt
Outdated
Show resolved
Hide resolved
...es-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryAbstractClass.kt
Fixed
Show fixed
Hide fixed
…abstract class that has concrete members Removed deprecated annotations Revert "Removed deprecated annotations" This reverts commit 326a356 fix return count rule violation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refer reply to the code suggestion earlier.
@gouri-panda sorry for all the changes. Can you fix the conflicts and add the tests that @amitdash291 point out here: #5009 (comment) ? After that (and if that test passes) I think that this is ready to merge. |
@BraisGabin @amitdash291 Sure :) |
…abstract class that has concrete members Removed deprecated annotations Revert "Removed deprecated annotations" This reverts commit 326a356 fix return count rule violation
# Conflicts: # detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/UnnecessaryAbstractClassSpec.kt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates :). This still has conflicts, could you check that?
abstract class A { | ||
abstract val i: Int | ||
} | ||
abstract class B: A(), I |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
abstract class B: A(), I | |
abstract class B: A(), I | |
abstract class C: I, A() |
We should check both cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure! Let me add another test case as well!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gouri-panda I have an idea to solve this in a generic manner. If you're okay I can raise a PR on your fork branch gouri-panda:fix-4753
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking if we check one of the parent is abstract, then we can return. But go for it :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gouri-panda
I have pushed my changes as a PR to your fork's branch here
In summary I have checked if not all the parents are interfaces, which is equivalent of the fact that at least one parent is abstract.
Please refer to this commit (there are a few other merge commits)
Handle corner case of multiple inheritance in UnnecessaryAbstractClass rule
Thanks for the fix @gouri-panda and @amitdash291 |
closes: #4753
Removed UnnecessaryAbstractClass if it inherits from abstract class an interface or that has concrete members.