Fix 'Redundant override' when delegated member hides super type override
So #KT-20231 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
3daee25ce8
commit
bbb571260b
+29
-1
@@ -19,11 +19,17 @@ package org.jetbrains.kotlin.idea.inspections
|
|||||||
import com.intellij.codeInspection.*
|
import com.intellij.codeInspection.*
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getCallNameExpression
|
import org.jetbrains.kotlin.psi.psiUtil.getCallNameExpression
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
|
|
||||||
class KotlinRedundantOverrideInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
|
class KotlinRedundantOverrideInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
|
||||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) =
|
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) =
|
||||||
@@ -59,6 +65,7 @@ class KotlinRedundantOverrideInspection : AbstractKotlinInspection(), CleanupLoc
|
|||||||
val superCallElement = qualifiedExpression.selectorExpression as? KtCallElement ?: return
|
val superCallElement = qualifiedExpression.selectorExpression as? KtCallElement ?: return
|
||||||
if (!isSameFunctionName(superCallElement, function)) return
|
if (!isSameFunctionName(superCallElement, function)) return
|
||||||
if (!isSameArguments(superCallElement, function)) return
|
if (!isSameArguments(superCallElement, function)) return
|
||||||
|
if (function.isDefinedInDelegatedSuperType(qualifiedExpression)) return
|
||||||
|
|
||||||
val descriptor = holder.manager.createProblemDescriptor(
|
val descriptor = holder.manager.createProblemDescriptor(
|
||||||
function,
|
function,
|
||||||
@@ -98,4 +105,25 @@ class KotlinRedundantOverrideInspection : AbstractKotlinInspection(), CleanupLoc
|
|||||||
companion object {
|
companion object {
|
||||||
private val MODIFIER_EXCLUDE_OVERRIDE = KtTokens.MODIFIER_KEYWORDS_ARRAY.asList() - KtTokens.OVERRIDE_KEYWORD
|
private val MODIFIER_EXCLUDE_OVERRIDE = KtTokens.MODIFIER_KEYWORDS_ARRAY.asList() - KtTokens.OVERRIDE_KEYWORD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun KtNamedFunction.isDefinedInDelegatedSuperType(superQualifiedExpression: KtDotQualifiedExpression): Boolean {
|
||||||
|
val delegatedSuperTypeEntries =
|
||||||
|
containingClassOrObject?.superTypeListEntries?.filterIsInstance<KtDelegatedSuperTypeEntry>() ?: return false
|
||||||
|
if (delegatedSuperTypeEntries.isEmpty()) return false
|
||||||
|
|
||||||
|
val context = superQualifiedExpression.analyze()
|
||||||
|
val delegatedSuperTypes = delegatedSuperTypeEntries.mapNotNull { entry ->
|
||||||
|
context[BindingContext.TYPE, entry.typeReference]
|
||||||
|
}
|
||||||
|
|
||||||
|
val superResolvedCall = superQualifiedExpression.getResolvedCall(context) ?: return false
|
||||||
|
val superCallResolvedDescriptor = superResolvedCall.resultingDescriptor
|
||||||
|
val superCallResolvedReceiverTypes = superCallResolvedDescriptor.overriddenDescriptors.mapNotNull { it.dispatchReceiverParameter?.type }
|
||||||
|
|
||||||
|
return delegatedSuperTypes.any { delegatedSuperType ->
|
||||||
|
superCallResolvedReceiverTypes.any { superCallReceiverType ->
|
||||||
|
delegatedSuperType.isSubtypeOf(superCallReceiverType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// PROBLEM: none
|
||||||
|
interface Foo {
|
||||||
|
fun test(arg: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Bar : Foo {
|
||||||
|
override fun test(arg: String) {}
|
||||||
|
open fun test(a: Int) {}
|
||||||
|
open fun test2() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Baz(val foo: Foo) : Bar(), Foo by foo {
|
||||||
|
override <caret>fun test(arg: String) = super.test(arg)
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
// PROBLEM: none
|
||||||
|
interface A
|
||||||
|
|
||||||
|
interface B {
|
||||||
|
fun test(arg: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Foo : A, B
|
||||||
|
|
||||||
|
open class Bar : Foo {
|
||||||
|
override fun test(arg: String) {}
|
||||||
|
open fun test(a: Int) {}
|
||||||
|
open fun test2() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Baz(val foo: Foo) : Bar(), Foo by foo {
|
||||||
|
override <caret>fun test(arg: String) = super.test(arg)
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
interface Foo {
|
||||||
|
fun test(arg: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Bar : Foo {
|
||||||
|
override fun test(arg: Int) {}
|
||||||
|
open fun test(a: String) {}
|
||||||
|
open fun test2() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Baz(val foo: Foo) : Bar(), Foo by foo {
|
||||||
|
override <caret>fun test(a: String) = super.test(a)
|
||||||
|
}
|
||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
interface Foo {
|
||||||
|
fun test(arg: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Bar : Foo {
|
||||||
|
override fun test(arg: Int) {}
|
||||||
|
open fun test(a: String) {}
|
||||||
|
open fun test2() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Baz(val foo: Foo) : Bar(), Foo by foo {
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
interface Foo {
|
||||||
|
fun test(arg: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Bar : Foo {
|
||||||
|
override fun test(arg: Int) {}
|
||||||
|
open fun test(a: String) {}
|
||||||
|
open fun test2() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Baz(val foo: Foo) : Bar(), Foo by foo {
|
||||||
|
override <caret>fun test2(arg: Int) = super.test2(arg)
|
||||||
|
}
|
||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
interface Foo {
|
||||||
|
fun test(arg: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Bar : Foo {
|
||||||
|
override fun test(arg: Int) {}
|
||||||
|
open fun test(a: String) {}
|
||||||
|
open fun test2() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Baz(val foo: Foo) : Bar(), Foo by foo {
|
||||||
|
}
|
||||||
@@ -1466,6 +1466,30 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("delegatedMemberHidesSuperTypeOverride.kt")
|
||||||
|
public void testDelegatedMemberHidesSuperTypeOverride() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("delegatedMemberHidesSuperTypeOverride2.kt")
|
||||||
|
public void testDelegatedMemberHidesSuperTypeOverride2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("delegatedMemberHidesSuperTypeOverride3.kt")
|
||||||
|
public void testDelegatedMemberHidesSuperTypeOverride3() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride3.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("delegatedMemberHidesSuperTypeOverride4.kt")
|
||||||
|
public void testDelegatedMemberHidesSuperTypeOverride4() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantOverride/delegatedMemberHidesSuperTypeOverride4.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("notCallSuper.kt")
|
@TestMetadata("notCallSuper.kt")
|
||||||
public void testNotCallSuper() throws Exception {
|
public void testNotCallSuper() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantOverride/notCallSuper.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantOverride/notCallSuper.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user