From efccde2c0b88def8464f9e7c80d27378692265f8 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Wed, 18 Mar 2015 22:14:01 +0300 Subject: [PATCH] Finding implicit usages of companion object in containing class. --- .../KotlinReferencesSearcher.java | 3 +- .../idea/search/usagesSearch/searchHelpers.kt | 34 ++++++++++++++++++- .../idea/search/usagesSearch/usagesSearch.kt | 6 ++-- .../defaultObject/inContainingClass.0.kt | 26 ++++++++++++++ .../inContainingClass.results.txt | 4 +++ .../JetFindUsagesTestGenerated.java | 6 ++++ 6 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 idea/testData/findUsages/kotlin/defaultObject/inContainingClass.0.kt create mode 100644 idea/testData/findUsages/kotlin/defaultObject/inContainingClass.results.txt diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.java index ad73b8c18af..034ca7ea324 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.java +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.java @@ -84,7 +84,8 @@ public class KotlinReferencesSearcher extends QueryExecutorBase { protected open fun makeItemList(target: UsagesSearchTarget): List = Collections.singletonList(newItem(target)) + protected open fun makeAdditionalSearchDelegate(target: T): ((Processor) -> Boolean)? = null + fun newItem(target: UsagesSearchTarget): UsagesSearchRequestItem { - return UsagesSearchRequestItem(target, makeWordList(target), makeFilter(target)) + return UsagesSearchRequestItem(target, makeWordList(target), makeFilter(target), makeAdditionalSearchDelegate(target.element)) } fun newRequest(target: UsagesSearchTarget): UsagesSearchRequest { @@ -151,6 +157,32 @@ class ClassUsagesSearchHelper( !constructorUsages && !nonConstructorUsages -> False else -> True } + + override fun makeAdditionalSearchDelegate(target: JetClassOrObject): ((Processor) -> Boolean)? { + if (target is JetObjectDeclaration && target.isCompanion()) { + val companionObjectDescriptor = target.descriptor + val klass = target.getStrictParentOfType() ?: 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( diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/usagesSearch.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/usagesSearch.kt index c3b2f2caded..d562fab6cd9 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/usagesSearch.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/usagesSearch.kt @@ -103,7 +103,8 @@ public trait UsagesSearchFilter { public data class UsagesSearchRequestItem( val target: UsagesSearchTarget, val words: List, - val filter: UsagesSearchFilter + val filter: UsagesSearchFilter, + val additionalSearchDelegate: ((Processor) -> Boolean)? ) public data class UsagesSearchRequest(val project: Project, val items: List) { @@ -164,7 +165,8 @@ public object UsagesSearch: QueryFactory() { val executorImpl = object : QueryExecutorBase() { override fun processQuery(request: UsagesSearchRequest, consumer: Processor) { 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) } } } diff --git a/idea/testData/findUsages/kotlin/defaultObject/inContainingClass.0.kt b/idea/testData/findUsages/kotlin/defaultObject/inContainingClass.0.kt new file mode 100644 index 00000000000..fd5b1f3ec8e --- /dev/null +++ b/idea/testData/findUsages/kotlin/defaultObject/inContainingClass.0.kt @@ -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 object: Foo { + fun foo() { + } + + val v = 42 + + fun Int.get(a: Int) = this + a + } +} + +trait Foo + +fun Foo.ext() { +} \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/defaultObject/inContainingClass.results.txt b/idea/testData/findUsages/kotlin/defaultObject/inContainingClass.results.txt new file mode 100644 index 00000000000..c87b2dcf188 --- /dev/null +++ b/idea/testData/findUsages/kotlin/defaultObject/inContainingClass.results.txt @@ -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 \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/findUsages/JetFindUsagesTestGenerated.java b/idea/tests/org/jetbrains/kotlin/findUsages/JetFindUsagesTestGenerated.java index f4602920680..98d6524f65c 100644 --- a/idea/tests/org/jetbrains/kotlin/findUsages/JetFindUsagesTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/findUsages/JetFindUsagesTestGenerated.java @@ -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); } + @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") public void testJavaUsage() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/defaultObject/javaUsage.0.kt");