Overridden methods with generic type shows no implementations found (KT-8723)

#KT-8723 Fixed
This commit is contained in:
Nikolay Krasko
2015-08-31 14:20:51 +03:00
parent 2af541cd4f
commit add43407d3
6 changed files with 168 additions and 0 deletions
+1
View File
@@ -509,6 +509,7 @@
<referencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearcher"/>
<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"/>
<annotatedElementsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinAnnotatedElementsSearcher"/>
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinPropertyAccessorsReferenceSearcher"/>
@@ -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);
}
@TestMetadata("SuperWithNativeToGenericMapping.test")
public void testSuperWithNativeToGenericMapping() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/navigation/gotoSuper/SuperWithNativeToGenericMapping.test");
doTest(fileName);
}
@TestMetadata("TraitSimple.test")
public void testTraitSimple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/navigation/gotoSuper/TraitSimple.test");
@@ -71,6 +71,12 @@ public class KotlinGotoImplementationTestGenerated extends AbstractKotlinGotoImp
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")
public void testOverridesInEnumEntries() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/navigation/implementations/OverridesInEnumEntries.kt");