Use classes to increase search pattern for static declarations
Static common names like 'INSTANCE', 'create' can give many irrelevant references in the project. #KT-17000 Fixed #KT-14974 Fixed
This commit is contained in:
+108
-9
@@ -21,13 +21,14 @@ import com.intellij.ide.highlighter.XmlFileType
|
||||
import com.intellij.lang.java.JavaLanguage
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.search.FileTypeIndex
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.LocalSearchScope
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference
|
||||
import com.intellij.psi.search.*
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.util.Processor
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
@@ -271,10 +272,108 @@ class ExpressionsOfTypeProcessor(
|
||||
})
|
||||
}
|
||||
|
||||
private fun addCallableDeclarationToProcess(declaration: PsiElement, scope: SearchScope, processor: ReferenceProcessor) {
|
||||
data class ProcessCallableUsagesTask(val declaration: PsiElement, val processor: ReferenceProcessor) : Task {
|
||||
private class StaticMemberRequestResultProcessor(val psiMember: PsiMember) : RequestResultProcessor(psiMember) {
|
||||
override fun processTextOccurrence(element: PsiElement, offsetInElement: Int, consumer: Processor<PsiReference>): Boolean {
|
||||
if (element !is KtQualifiedExpression) return true
|
||||
|
||||
val selectorExpression = element.selectorExpression ?: return true
|
||||
val selectorReference = element.findReferenceAt(selectorExpression.startOffsetInParent)
|
||||
|
||||
val references = when (selectorReference) {
|
||||
is PsiMultiReference -> selectorReference.references.toList()
|
||||
else -> listOf(selectorReference)
|
||||
}.filterNotNull()
|
||||
|
||||
for (ref in references) {
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
if (ref.isReferenceTo(psiMember)) {
|
||||
consumer.process(ref)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private fun classUseScope(psiClass: PsiClass) = runReadAction {
|
||||
if (!psiClass.isValid) {
|
||||
throw ProcessCanceledException()
|
||||
}
|
||||
|
||||
val file = psiClass.containingFile
|
||||
(file ?: psiClass).useScope
|
||||
}
|
||||
|
||||
private fun addStaticMemberToProcess(psiMember: PsiMember, scope: SearchScope, processor: ReferenceProcessor) {
|
||||
val declarationClass = runReadAction { psiMember.containingClass } ?: return
|
||||
val declarationName = runReadAction { psiMember.name } ?: return
|
||||
if (declarationName.isEmpty()) return
|
||||
|
||||
data class ProcessStaticCallableUsagesTask(val member: PsiMember, val memberScope: SearchScope, val taskProcessor: ReferenceProcessor) : Task {
|
||||
override fun perform() {
|
||||
testLog?.add("Searched references to ${logPresentation(declaration)} in non-Java files")
|
||||
// This class will look through the whole hierarchy anyway, so shouldn't be a big overhead here
|
||||
val inheritanceClasses = ClassInheritorsSearch.search(
|
||||
declarationClass,
|
||||
classUseScope(declarationClass),
|
||||
true, true, false).findAll()
|
||||
|
||||
val classes = (inheritanceClasses + declarationClass).filter {
|
||||
it !is KtLightClass
|
||||
}
|
||||
|
||||
val searchRequestCollector = SearchRequestCollector(SearchSession())
|
||||
val resultProcessor = StaticMemberRequestResultProcessor(member)
|
||||
|
||||
for (klass in classes) {
|
||||
val request = klass.name + "." + declarationName
|
||||
|
||||
testLog?.add("Searched references to static member in non-Java files by request $request")
|
||||
|
||||
searchRequestCollector.searchWord(
|
||||
request, classUseScope(klass).intersectWith(memberScope), UsageSearchContext.IN_CODE, true, member, resultProcessor)
|
||||
}
|
||||
|
||||
PsiSearchHelper.SERVICE.getInstance(project).processRequests(searchRequestCollector) { reference ->
|
||||
if (reference.element.parents.any { it is KtImportDirective }) {
|
||||
// Found declaration in import - process all file with an ordinal reference search
|
||||
val containingFile = reference.element.containingFile
|
||||
addCallableDeclarationToProcess(member, LocalSearchScope(containingFile), taskProcessor)
|
||||
|
||||
true
|
||||
}
|
||||
else {
|
||||
val processed = taskProcessor.handler(this@ExpressionsOfTypeProcessor, reference)
|
||||
if (!processed) { // we don't know how to handle this reference and down-shift to plain search
|
||||
downShiftToPlainSearch(reference)
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addTask(ProcessStaticCallableUsagesTask(psiMember, scope, processor))
|
||||
return
|
||||
}
|
||||
|
||||
private fun addCallableDeclarationToProcess(declaration: PsiElement, scope: SearchScope, processor: ReferenceProcessor) {
|
||||
if (scope !is LocalSearchScope && declaration is PsiMember && (declaration.modifierList?.hasModifierProperty(PsiModifier.STATIC) ?: false)) {
|
||||
addStaticMemberToProcess(declaration, scope, processor)
|
||||
return
|
||||
}
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
data class ProcessCallableUsagesTask(val declaration: PsiElement, val processor: ReferenceProcessor, val scope: SearchScope) : Task {
|
||||
override fun perform() {
|
||||
if (scope is LocalSearchScope) {
|
||||
testLog?.add("Searched imported static member $declaration in ${scope.scope.toList()}")
|
||||
}
|
||||
else {
|
||||
testLog?.add("Searched references to ${logPresentation(declaration)} in non-Java files")
|
||||
}
|
||||
|
||||
val searchParameters = KotlinReferencesSearchParameters(
|
||||
declaration, scope, kotlinOptions = KotlinReferencesSearchOptions(searchNamedArguments = false))
|
||||
searchReferences(searchParameters) { reference ->
|
||||
@@ -286,7 +385,7 @@ class ExpressionsOfTypeProcessor(
|
||||
}
|
||||
}
|
||||
}
|
||||
addTask(ProcessCallableUsagesTask(declaration, processor))
|
||||
addTask(ProcessCallableUsagesTask(declaration, processor, scope))
|
||||
}
|
||||
|
||||
private fun addPsiMemberTask(member: PsiMember) {
|
||||
@@ -542,7 +641,7 @@ class ExpressionsOfTypeProcessor(
|
||||
break@ParentsLoop
|
||||
}
|
||||
|
||||
//TODO: if Java parameter has Kotlin functional type then we should process method usages
|
||||
//TODO: if Java parameter has Kotlin functional type then we should process method usages
|
||||
is PsiParameter -> {
|
||||
if (prev == parent.typeElement) { // usage in parameter type - check if the method is in SAM interface
|
||||
processParameterInSamClass(parent)
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
// PSI_ELEMENT: com.intellij.psi.PsiMethod
|
||||
// OPTIONS: usages
|
||||
|
||||
public class JavaClass {
|
||||
public class JavaClassInvoke {
|
||||
public void <caret>invoke() {
|
||||
}
|
||||
|
||||
public static class OtherJavaClass extends JavaClass {
|
||||
public static JavaClassInvoke INSTANCE = new JavaClassInvoke();
|
||||
|
||||
public static class Other extends JavaClassInvoke {}
|
||||
public static class AnotherOther extends Other {}
|
||||
|
||||
public static class JavaOther {
|
||||
public void invoke() {
|
||||
}
|
||||
|
||||
public static JavaOther INSTANCE = new JavaOther();
|
||||
}
|
||||
|
||||
public static class OtherJavaClass extends JavaClassInvoke {
|
||||
public static OtherJavaClass OJC = new OtherJavaClass();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
fun f(c: JavaClass) {
|
||||
fun f(c: JavaClassInvoke) {
|
||||
c()
|
||||
}
|
||||
|
||||
fun foo(o: JavaClass.OtherJavaClass) {
|
||||
fun foo(o: JavaClassInvoke.OtherJavaClass) {
|
||||
o()
|
||||
JavaClass.OtherJavaClass.OJC()
|
||||
}
|
||||
JavaClassInvoke.OtherJavaClass.OJC()
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
JavaClassInvoke.INSTANCE()
|
||||
JavaClassInvoke.AnotherOther.INSTANCE()
|
||||
JavaClassInvoke.JavaOther.INSTANCE()
|
||||
}
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
Resolved INSTANCE()
|
||||
Resolved INSTANCE()
|
||||
Resolved INSTANCE()
|
||||
Resolved INSTANCE()
|
||||
Resolved OJC()
|
||||
Resolved c()
|
||||
Resolved o()
|
||||
Searched references to JavaClass
|
||||
Searched references to JavaClass.OtherJavaClass
|
||||
Searched references to JavaClass.OtherJavaClass.OJC in non-Java files
|
||||
Searched references to parameter c of f(c: JavaClass) in non-Java files
|
||||
Searched references to parameter o of foo(o: JavaClass.OtherJavaClass) in non-Java files
|
||||
Searched references to JavaClassInvoke
|
||||
Searched references to JavaClassInvoke.AnotherOther
|
||||
Searched references to JavaClassInvoke.Other
|
||||
Searched references to JavaClassInvoke.OtherJavaClass
|
||||
Searched references to parameter c of f(c: JavaClassInvoke) in non-Java files
|
||||
Searched references to parameter o of foo(o: JavaClassInvoke.OtherJavaClass) in non-Java files
|
||||
Searched references to static member in non-Java files by request AnotherOther.INSTANCE
|
||||
Searched references to static member in non-Java files by request JavaClassInvoke.INSTANCE
|
||||
Searched references to static member in non-Java files by request Other.INSTANCE
|
||||
Searched references to static member in non-Java files by request OtherJavaClass.INSTANCE
|
||||
Searched references to static member in non-Java files by request OtherJavaClass.OJC
|
||||
@@ -1,3 +1,5 @@
|
||||
Implicit 'invoke' 11 JavaClassInvoke.INSTANCE()
|
||||
Implicit 'invoke' 12 JavaClassInvoke.AnotherOther.INSTANCE()
|
||||
Implicit 'invoke' 2 c()
|
||||
Implicit 'invoke' 6 o()
|
||||
Implicit 'invoke' 7 JavaClass.OtherJavaClass.OJC()
|
||||
Implicit 'invoke' 7 JavaClassInvoke.OtherJavaClass.OJC()
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// PSI_ELEMENT: com.intellij.psi.PsiMethod
|
||||
// OPTIONS: usages
|
||||
|
||||
public class JavaClassWI {
|
||||
public void <caret>invoke() {
|
||||
}
|
||||
|
||||
public static JavaClassWI INSTANCE = new JavaClass();
|
||||
|
||||
public static class Other extends JavaClassWI {}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import JavaClassWI.Other.INSTANCE
|
||||
|
||||
fun foo() {
|
||||
INSTANCE()
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
Resolved INSTANCE()
|
||||
Searched imported static member PsiField:INSTANCE in [JetFile: javaInvokeWithStaticImport.0.kt]
|
||||
Searched references to JavaClassWI
|
||||
Searched references to JavaClassWI.Other
|
||||
Searched references to static member in non-Java files by request JavaClassWI.INSTANCE
|
||||
Searched references to static member in non-Java files by request Other.INSTANCE
|
||||
+1
@@ -0,0 +1 @@
|
||||
Implicit 'invoke' 4 INSTANCE()
|
||||
@@ -41,7 +41,6 @@ Searched references to JavaClass2
|
||||
Searched references to JavaClass3
|
||||
Searched references to JavaClass4.NestedPrivate
|
||||
Searched references to JavaClass4.NestedPublic
|
||||
Searched references to JavaClass4.getNested() in non-Java files
|
||||
Searched references to a in non-Java files
|
||||
Searched references to f() in non-Java files
|
||||
Searched references to g() in non-Java files
|
||||
@@ -51,6 +50,7 @@ Searched references to pack.A
|
||||
Searched references to pack.X
|
||||
Searched references to parameter p1 of test2(p1: JavaClass2, p2: JavaClass3) in non-Java files
|
||||
Searched references to parameter p2 of test2(p1: JavaClass2, p2: JavaClass3) in non-Java files
|
||||
Searched references to static member in non-Java files by request JavaClass4.getNested
|
||||
Used plain search of parameter n of A(val n: Int, val s: String, val o: Any) in LocalSearchScope:
|
||||
CLASS:A
|
||||
CLASS:X
|
||||
|
||||
@@ -1639,6 +1639,12 @@ public class FindUsagesTestGenerated extends AbstractFindUsagesTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("javaInvokeWithStaticImport.0.java")
|
||||
public void testJavaInvokeWithStaticImport() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/java/findJavaMethodUsages/javaInvokeWithStaticImport.0.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("JavaWithGroovyInvoke.0.java")
|
||||
public void testJavaWithGroovyInvoke() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/java/findJavaMethodUsages/JavaWithGroovyInvoke.0.java");
|
||||
|
||||
Reference in New Issue
Block a user