Overridden methods with generic type shows no implementations found (KT-8723)
#KT-8723 Fixed
This commit is contained in:
@@ -509,6 +509,7 @@
|
|||||||
|
|
||||||
<referencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearcher"/>
|
<referencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearcher"/>
|
||||||
<directClassInheritorsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDirectInheritorsSearcher"/>
|
<directClassInheritorsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDirectInheritorsSearcher"/>
|
||||||
|
<overridingMethodsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinOverridingMethodsWithGenericsSearcher"/>
|
||||||
<definitionsScopedSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDefinitionsSearcher"/>
|
<definitionsScopedSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDefinitionsSearcher"/>
|
||||||
<annotatedElementsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinAnnotatedElementsSearcher"/>
|
<annotatedElementsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinAnnotatedElementsSearcher"/>
|
||||||
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinPropertyAccessorsReferenceSearcher"/>
|
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinPropertyAccessorsReferenceSearcher"/>
|
||||||
|
|||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.search.ideaExtensions
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
|
import com.intellij.psi.PsiMethod
|
||||||
|
import com.intellij.psi.search.searches.ClassInheritorsSearch
|
||||||
|
import com.intellij.psi.search.searches.OverridingMethodsSearch
|
||||||
|
import com.intellij.util.Processor
|
||||||
|
import com.intellij.util.QueryExecutor
|
||||||
|
import org.jetbrains.kotlin.asJava.KotlinLightClass
|
||||||
|
import org.jetbrains.kotlin.asJava.KotlinLightMethod
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
|
import org.jetbrains.kotlin.psi.JetCallableDeclaration
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.OverrideResolver
|
||||||
|
|
||||||
|
public class KotlinOverridingMethodsWithGenericsSearcher : QueryExecutor<PsiMethod, OverridingMethodsSearch.SearchParameters> {
|
||||||
|
override fun execute(p: OverridingMethodsSearch.SearchParameters, consumer: Processor<PsiMethod>): Boolean {
|
||||||
|
val method = p.method
|
||||||
|
if (method !is KotlinLightMethod) return true
|
||||||
|
|
||||||
|
val declaration = method.getOrigin() as? JetCallableDeclaration
|
||||||
|
if (declaration == null) return true
|
||||||
|
|
||||||
|
val callDescriptor = declaration.resolveToDescriptor()
|
||||||
|
if (callDescriptor !is CallableDescriptor) return true
|
||||||
|
|
||||||
|
// Java overriding method search can't find overloads with primitives types, so
|
||||||
|
// we do additional search for such methods.
|
||||||
|
if (!callDescriptor.valueParameters.any { it.type.constructor.declarationDescriptor is TypeParameterDescriptor }) return true
|
||||||
|
|
||||||
|
val parentClass = runReadAction { method.containingClass }!!
|
||||||
|
|
||||||
|
return ClassInheritorsSearch.search(parentClass, p.scope, true).forEach(Processor { inheritor: PsiClass ->
|
||||||
|
val found = runReadAction {
|
||||||
|
findOverridingMethod(inheritor, declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
found == null || (consumer.process(found) && p.isCheckDeep)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findOverridingMethod(inheritor: PsiClass, callableDeclaration: JetCallableDeclaration): PsiMethod? {
|
||||||
|
// Leave Java classes search to JavaOverridingMethodsSearcher
|
||||||
|
if (inheritor !is KotlinLightClass) return null
|
||||||
|
|
||||||
|
val name = callableDeclaration.name
|
||||||
|
val methodsByName = inheritor.findMethodsByName(name, false)
|
||||||
|
|
||||||
|
for (lightMethodCandidate in methodsByName) {
|
||||||
|
val candidateDescriptor = (lightMethodCandidate as? KotlinLightMethod)?.getOrigin()?.resolveToDescriptor() ?: continue
|
||||||
|
if (candidateDescriptor !is CallableMemberDescriptor) continue
|
||||||
|
|
||||||
|
val overriddenDescriptors = OverrideResolver.getDirectlyOverriddenDeclarations(candidateDescriptor)
|
||||||
|
for (candidateSuper in overriddenDescriptors) {
|
||||||
|
val candidateDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(candidateSuper)
|
||||||
|
if (candidateDeclaration == callableDeclaration) {
|
||||||
|
return lightMethodCandidate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// FILE: b.kt
|
||||||
|
open class Foo<T> {
|
||||||
|
open fun bar(t: T) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar() : Foo<Int>() {
|
||||||
|
override fun <caret>bar(ts: Int) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FILE: a.kt
|
||||||
|
open class Foo<T> {
|
||||||
|
open fun <caret>bar(t: T) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar() : Foo<Int>() {
|
||||||
|
override fun bar(ts: Int) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
open class Foo<T, U, Z> {
|
||||||
|
open fun <caret>bar(t: T, u: U): Z {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AllTypes() : Foo<Int, Double, Int>() {
|
||||||
|
override fun bar(i: Int, d: Double): Int = 42
|
||||||
|
}
|
||||||
|
|
||||||
|
class SomeParameters() : Foo<Double, Any, Int>() {
|
||||||
|
override fun bar(d: Double, a: Any): Int = 42
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReturnType() : Foo<Any, String, Byte>() {
|
||||||
|
override fun bar(a: Any, s: String): Byte = 12.toByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParameterStillGeneric<Z>() : Foo<Int, Z, String>() {
|
||||||
|
override fun bar(i: Int, z: Z): String = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReturnStillGeneric<A>() : Foo<Int, Int, A>() {
|
||||||
|
override fun bar(i: Int, i2: Int): A = null
|
||||||
|
}
|
||||||
|
|
||||||
|
open class ThroughProxyAllGenerics<A, B, C>: Foo<A, B, C>()
|
||||||
|
class ThroughProxyAllGenericsImpl: ThroughProxyAllGenerics<Double, Int, Boolean>() {
|
||||||
|
override fun bar(t: Double, i: Int): Boolean = true
|
||||||
|
}
|
||||||
|
|
||||||
|
open class ThroughProxySomeGenerics<A, C>: Foo<A, Int, C>()
|
||||||
|
class ThroughProxySomeGenericsImpl: ThroughProxySomeGenerics<Double, Boolean>() {
|
||||||
|
override fun bar(t: Double, i: Int): Boolean = true
|
||||||
|
}
|
||||||
|
|
||||||
|
class NoPrimitives: Foo<String, Any, String>() {
|
||||||
|
override fun bar(t: String, u: Any): String = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
class NoOverride: Foo<String, Any, String>() {
|
||||||
|
// Error: Not override
|
||||||
|
override fun bar(t: Any, u: String): String = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// REF: "(in AllTypes).bar(Int,Double)"
|
||||||
|
// REF: "(in NoPrimitives).bar(String,Any)"
|
||||||
|
// REF: "(in ParameterStillGeneric).bar(Int,Z)"
|
||||||
|
// REF: "(in ReturnStillGeneric).bar(Int,Int)"
|
||||||
|
// REF: "(in ReturnType).bar(Any,String)"
|
||||||
|
// REF: "(in SomeParameters).bar(Double,Any)"
|
||||||
|
// REF: "(in ThroughProxyAllGenericsImpl).bar(Double,Int)"
|
||||||
|
// REF: "(in ThroughProxySomeGenericsImpl).bar(Double,Int)"
|
||||||
@@ -89,6 +89,12 @@ public class GotoSuperTestGenerated extends AbstractGotoSuperTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("SuperWithNativeToGenericMapping.test")
|
||||||
|
public void testSuperWithNativeToGenericMapping() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/navigation/gotoSuper/SuperWithNativeToGenericMapping.test");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("TraitSimple.test")
|
@TestMetadata("TraitSimple.test")
|
||||||
public void testTraitSimple() throws Exception {
|
public void testTraitSimple() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/navigation/gotoSuper/TraitSimple.test");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/navigation/gotoSuper/TraitSimple.test");
|
||||||
|
|||||||
+6
@@ -71,6 +71,12 @@ public class KotlinGotoImplementationTestGenerated extends AbstractKotlinGotoImp
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ImplementGenericWithPrimitives.kt")
|
||||||
|
public void testImplementGenericWithPrimitives() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/navigation/implementations/ImplementGenericWithPrimitives.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("OverridesInEnumEntries.kt")
|
@TestMetadata("OverridesInEnumEntries.kt")
|
||||||
public void testOverridesInEnumEntries() throws Exception {
|
public void testOverridesInEnumEntries() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/navigation/implementations/OverridesInEnumEntries.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/navigation/implementations/OverridesInEnumEntries.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user