Finding implicit usages of companion object in containing class.
This commit is contained in:
+2
-1
@@ -84,7 +84,8 @@ public class KotlinReferencesSearcher extends QueryExecutorBase<PsiReference, Re
|
|||||||
UsagesSearchRequestItem requestItem = new UsagesSearchRequestItem(
|
UsagesSearchRequestItem requestItem = new UsagesSearchRequestItem(
|
||||||
searchTarget,
|
searchTarget,
|
||||||
UsagesSearchPackage.getSpecialNamesToSearch(unwrappedElement),
|
UsagesSearchPackage.getSpecialNamesToSearch(unwrappedElement),
|
||||||
UsagesSearchPackage.getIsTargetUsage()
|
UsagesSearchPackage.getIsTargetUsage(),
|
||||||
|
null
|
||||||
);
|
);
|
||||||
searchHelper.processFilesWithText(requestItem, consumer);
|
searchHelper.processFilesWithText(requestItem, consumer);
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-1
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchFilter.*
|
|||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import com.intellij.psi.PsiNamedElement
|
import com.intellij.psi.PsiNamedElement
|
||||||
|
import com.intellij.util.Processor
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtil.PropertyAccessorsPsiMethods
|
import org.jetbrains.kotlin.asJava.LightClassUtil.PropertyAccessorsPsiMethods
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
@@ -33,7 +34,10 @@ import org.jetbrains.kotlin.lexer.JetTokens
|
|||||||
import org.jetbrains.kotlin.idea.references.*
|
import org.jetbrains.kotlin.idea.references.*
|
||||||
import com.intellij.util.containers.ContainerUtil
|
import com.intellij.util.containers.ContainerUtil
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassReceiver
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
||||||
|
|
||||||
val isTargetUsage = (PsiReference::matchesTarget).searchFilter
|
val isTargetUsage = (PsiReference::matchesTarget).searchFilter
|
||||||
@@ -113,8 +117,10 @@ public abstract class UsagesSearchHelper<T : PsiNamedElement> {
|
|||||||
protected open fun makeItemList(target: UsagesSearchTarget<T>): List<UsagesSearchRequestItem> =
|
protected open fun makeItemList(target: UsagesSearchTarget<T>): List<UsagesSearchRequestItem> =
|
||||||
Collections.singletonList(newItem(target))
|
Collections.singletonList(newItem(target))
|
||||||
|
|
||||||
|
protected open fun makeAdditionalSearchDelegate(target: T): ((Processor<PsiReference>) -> Boolean)? = null
|
||||||
|
|
||||||
fun newItem(target: UsagesSearchTarget<T>): UsagesSearchRequestItem {
|
fun newItem(target: UsagesSearchTarget<T>): UsagesSearchRequestItem {
|
||||||
return UsagesSearchRequestItem(target, makeWordList(target), makeFilter(target))
|
return UsagesSearchRequestItem(target, makeWordList(target), makeFilter(target), makeAdditionalSearchDelegate(target.element))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun newRequest(target: UsagesSearchTarget<T>): UsagesSearchRequest {
|
fun newRequest(target: UsagesSearchTarget<T>): UsagesSearchRequest {
|
||||||
@@ -151,6 +157,32 @@ class ClassUsagesSearchHelper(
|
|||||||
!constructorUsages && !nonConstructorUsages -> False
|
!constructorUsages && !nonConstructorUsages -> False
|
||||||
else -> True
|
else -> True
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun makeAdditionalSearchDelegate(target: JetClassOrObject): ((Processor<PsiReference>) -> Boolean)? {
|
||||||
|
if (target is JetObjectDeclaration && target.isCompanion()) {
|
||||||
|
val companionObjectDescriptor = target.descriptor
|
||||||
|
val klass = target.getStrictParentOfType<JetClass>() ?: return null
|
||||||
|
return { processor ->
|
||||||
|
klass.acceptChildren(object : JetVisitorVoid() {
|
||||||
|
override fun visitJetElement(element: JetElement) {
|
||||||
|
if (element == target) return // skip companion object itself
|
||||||
|
element.acceptChildren(this)
|
||||||
|
|
||||||
|
val bindingContext = element.analyze()
|
||||||
|
val call = bindingContext[BindingContext.CALL, element] ?: return
|
||||||
|
val resolvedCall = bindingContext[BindingContext.RESOLVED_CALL, call] ?: return
|
||||||
|
if ((resolvedCall.getDispatchReceiver() as? ClassReceiver)?.getDeclarationDescriptor() == companionObjectDescriptor
|
||||||
|
|| (resolvedCall.getExtensionReceiver() as? ClassReceiver)?.getDeclarationDescriptor() == companionObjectDescriptor) {
|
||||||
|
element.getReference()?.let { processor.process(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ClassDeclarationsUsagesSearchHelper(
|
class ClassDeclarationsUsagesSearchHelper(
|
||||||
|
|||||||
+4
-2
@@ -103,7 +103,8 @@ public trait UsagesSearchFilter {
|
|||||||
public data class UsagesSearchRequestItem(
|
public data class UsagesSearchRequestItem(
|
||||||
val target: UsagesSearchTarget<PsiElement>,
|
val target: UsagesSearchTarget<PsiElement>,
|
||||||
val words: List<String>,
|
val words: List<String>,
|
||||||
val filter: UsagesSearchFilter
|
val filter: UsagesSearchFilter,
|
||||||
|
val additionalSearchDelegate: ((Processor<PsiReference>) -> Boolean)?
|
||||||
)
|
)
|
||||||
|
|
||||||
public data class UsagesSearchRequest(val project: Project, val items: List<UsagesSearchRequestItem>) {
|
public data class UsagesSearchRequest(val project: Project, val items: List<UsagesSearchRequestItem>) {
|
||||||
@@ -164,7 +165,8 @@ public object UsagesSearch: QueryFactory<PsiReference, UsagesSearchRequest>() {
|
|||||||
val executorImpl = object : QueryExecutorBase<PsiReference, UsagesSearchRequest>() {
|
val executorImpl = object : QueryExecutorBase<PsiReference, UsagesSearchRequest>() {
|
||||||
override fun processQuery(request: UsagesSearchRequest, consumer: Processor<PsiReference>) {
|
override fun processQuery(request: UsagesSearchRequest, consumer: Processor<PsiReference>) {
|
||||||
val searchHelper = KotlinPsiSearchHelper(request.project)
|
val searchHelper = KotlinPsiSearchHelper(request.project)
|
||||||
request.items.filter { it.filter != False }.all { searchHelper.processFilesWithText(it, consumer) }
|
request.items.filter { it.filter != False }.all {
|
||||||
|
searchHelper.processFilesWithText(it, consumer) && (it.additionalSearchDelegate?.invoke(consumer) ?: true) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetObjectDeclaration
|
||||||
|
// OPTIONS: usages
|
||||||
|
class A {
|
||||||
|
init {
|
||||||
|
foo()
|
||||||
|
v
|
||||||
|
|
||||||
|
1[2] // using companion object function by convention
|
||||||
|
|
||||||
|
ext() // companion object is extension receiver
|
||||||
|
}
|
||||||
|
|
||||||
|
companion <caret>object: Foo {
|
||||||
|
fun foo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
val v = 42
|
||||||
|
|
||||||
|
fun Int.get(a: Int) = this + a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Foo
|
||||||
|
|
||||||
|
fun Foo.ext() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
Function call (10: 9) ext() // companion object is extension receiver
|
||||||
|
Function call (5: 9) foo()
|
||||||
|
Implicit 'get' (8: 9) 1[2] // using companion object function by convention
|
||||||
|
Value read (6: 9) v
|
||||||
@@ -176,6 +176,12 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
|
|||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/findUsages/kotlin/defaultObject"), Pattern.compile("^(.+)\\.0\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/findUsages/kotlin/defaultObject"), Pattern.compile("^(.+)\\.0\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inContainingClass.0.kt")
|
||||||
|
public void testInContainingClass() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/defaultObject/inContainingClass.0.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("javaUsage.0.kt")
|
@TestMetadata("javaUsage.0.kt")
|
||||||
public void testJavaUsage() throws Exception {
|
public void testJavaUsage() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/defaultObject/javaUsage.0.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/defaultObject/javaUsage.0.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user