Fix 'Redundant override' when delegated member hides super type override

So #KT-20231 Fixed
This commit is contained in:
Toshiaki Kameyama
2017-10-02 10:32:07 +03:00
committed by Mikhail Glukhikh
parent 3daee25ce8
commit bbb571260b
8 changed files with 135 additions and 1 deletions
@@ -19,11 +19,17 @@ package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInspection.*
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.lexer.KtTokens
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.getCallNameExpression
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 {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) =
@@ -59,6 +65,7 @@ class KotlinRedundantOverrideInspection : AbstractKotlinInspection(), CleanupLoc
val superCallElement = qualifiedExpression.selectorExpression as? KtCallElement ?: return
if (!isSameFunctionName(superCallElement, function)) return
if (!isSameArguments(superCallElement, function)) return
if (function.isDefinedInDelegatedSuperType(qualifiedExpression)) return
val descriptor = holder.manager.createProblemDescriptor(
function,
@@ -98,4 +105,25 @@ class KotlinRedundantOverrideInspection : AbstractKotlinInspection(), CleanupLoc
companion object {
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)
}
}
}
@@ -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)
}
@@ -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)
}
@@ -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)
}
@@ -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 {
}
@@ -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)
}
@@ -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);
}
@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")
public void testNotCallSuper() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantOverride/notCallSuper.kt");