[FIR IDE] Separate searchers from descriptor usage
KotlinConstructorDelegationCallReferenceSearcher KotlinConventionMethodReferencesSearcher KotlinDefinitionsSearcher KotlinOverridingMethodReferenceSearcher KotlinPropertyAccessorsReferenceSearcher KotlinTodoSearcher
This commit is contained in:
+28
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.search
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
@@ -14,6 +15,10 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
|
||||
class KotlinSearchUsagesSupportFirImpl : KotlinSearchUsagesSupport {
|
||||
override fun actualsForExpected(declaration: KtDeclaration, module: Module?): Set<KtDeclaration> {
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
override fun dataClassComponentMethodName(element: KtParameter): String? {
|
||||
return null
|
||||
}
|
||||
@@ -109,4 +114,27 @@ class KotlinSearchUsagesSupportFirImpl : KotlinSearchUsagesSupport {
|
||||
override fun isExpectDeclaration(declaration: KtDeclaration): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canBeResolvedWithFrontEnd(element: PsiElement): Boolean {
|
||||
//TODO FIR: Is the same as PsiElement.hasJavaResolutionFacade() as for FIR?
|
||||
return element.originalElement.containingFile != null
|
||||
}
|
||||
|
||||
override fun createConstructorHandle(ktDeclaration: KtDeclaration): KotlinSearchUsagesSupport.ConstructorCallHandle {
|
||||
//TODO FIR: This is the stub. Need to implement
|
||||
return object : KotlinSearchUsagesSupport.ConstructorCallHandle {
|
||||
override fun referencedTo(element: KtElement): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun createConstructorHandle(psiMethod: PsiMethod): KotlinSearchUsagesSupport.ConstructorCallHandle {
|
||||
//TODO FIR: This is the stub. Need to implement
|
||||
return object : KotlinSearchUsagesSupport.ConstructorCallHandle {
|
||||
override fun referencedTo(element: KtElement): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.idea.search
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
@@ -17,6 +18,10 @@ import org.jetbrains.kotlin.resolve.ImportPath
|
||||
|
||||
interface KotlinSearchUsagesSupport {
|
||||
|
||||
interface ConstructorCallHandle {
|
||||
fun referencedTo(element: KtElement): Boolean
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getInstance(project: Project): KotlinSearchUsagesSupport {
|
||||
return ServiceManager.getService(project, KotlinSearchUsagesSupport::class.java)
|
||||
@@ -95,8 +100,22 @@ interface KotlinSearchUsagesSupport {
|
||||
|
||||
fun KtDeclaration.isExpectDeclaration(): Boolean =
|
||||
getInstance(project).isExpectDeclaration(this)
|
||||
|
||||
fun KtDeclaration.actualsForExpected(module: Module? = null): Set<KtDeclaration> =
|
||||
getInstance(project).actualsForExpected(this, module)
|
||||
|
||||
fun PsiElement.canBeResolvedWithFrontEnd(): Boolean =
|
||||
getInstance(project).canBeResolvedWithFrontEnd(this)
|
||||
|
||||
fun createConstructorHandle(ktDeclaration: KtDeclaration): ConstructorCallHandle =
|
||||
getInstance(ktDeclaration.project).createConstructorHandle(ktDeclaration)
|
||||
|
||||
fun createConstructorHandle(psiMethod: PsiMethod): ConstructorCallHandle =
|
||||
getInstance(psiMethod.project).createConstructorHandle(psiMethod)
|
||||
}
|
||||
|
||||
fun actualsForExpected(declaration: KtDeclaration, module: Module? = null): Set<KtDeclaration>
|
||||
|
||||
fun dataClassComponentMethodName(element: KtParameter): String?
|
||||
|
||||
fun hasType(element: KtExpression): Boolean
|
||||
@@ -149,4 +168,10 @@ interface KotlinSearchUsagesSupport {
|
||||
fun expectedDeclarationIfAny(declaration: KtDeclaration): KtDeclaration?
|
||||
|
||||
fun isExpectDeclaration(declaration: KtDeclaration): Boolean
|
||||
|
||||
fun canBeResolvedWithFrontEnd(element: PsiElement): Boolean
|
||||
|
||||
fun createConstructorHandle(ktDeclaration: KtDeclaration): ConstructorCallHandle
|
||||
|
||||
fun createConstructorHandle(psiMethod: PsiMethod): ConstructorCallHandle
|
||||
}
|
||||
+2
-2
@@ -20,15 +20,15 @@ import com.intellij.openapi.application.QueryExecutorBase
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.search.searches.MethodReferencesSearch.SearchParameters
|
||||
import com.intellij.util.Processor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.util.hasJavaResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.canBeResolvedWithFrontEnd
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.processDelegationCallConstructorUsages
|
||||
|
||||
class KotlinConstructorDelegationCallReferenceSearcher : QueryExecutorBase<PsiReference, SearchParameters>(true) {
|
||||
override fun processQuery(queryParameters: SearchParameters, consumer: Processor<in PsiReference>) {
|
||||
val method = queryParameters.method
|
||||
if (!method.isConstructor) return
|
||||
if (!method.hasJavaResolutionFacade()) return
|
||||
if (!method.canBeResolvedWithFrontEnd()) return
|
||||
|
||||
method.processDelegationCallConstructorUsages(method.useScope.intersectWith(queryParameters.effectiveSearchScope)) {
|
||||
it.calleeExpression?.mainReference?.let { consumer.process(it) } ?: true
|
||||
+2
-2
@@ -20,13 +20,13 @@ import com.intellij.openapi.application.QueryExecutorBase
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.search.searches.MethodReferencesSearch
|
||||
import com.intellij.util.Processor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.util.hasJavaResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.canBeResolvedWithFrontEnd
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.operators.OperatorReferenceSearcher
|
||||
|
||||
class KotlinConventionMethodReferencesSearcher : QueryExecutorBase<PsiReference, MethodReferencesSearch.SearchParameters>(true) {
|
||||
override fun processQuery(queryParameters: MethodReferencesSearch.SearchParameters, consumer: Processor<in PsiReference>) {
|
||||
val method = queryParameters.method
|
||||
if (!method.hasJavaResolutionFacade()) return
|
||||
if (!method.canBeResolvedWithFrontEnd()) return
|
||||
|
||||
val operatorSearcher = OperatorReferenceSearcher.create(
|
||||
queryParameters.method,
|
||||
+8
-6
@@ -28,15 +28,15 @@ import com.intellij.util.QueryExecutor
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.asJava.unwrapped
|
||||
import org.jetbrains.kotlin.idea.caches.lightClasses.KtFakeLightClass
|
||||
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedCreateKtFakeLightClass
|
||||
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightClass
|
||||
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.actualsForExpected
|
||||
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.forEachOverridingMethod
|
||||
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.isExpectDeclaration
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.forEachImplementation
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.forEachOverridingMethod
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.toPossiblyFakeLightMethods
|
||||
import org.jetbrains.kotlin.idea.util.actualsForExpected
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.contains
|
||||
import java.util.*
|
||||
@@ -107,7 +107,9 @@ class KotlinDefinitionsSearcher : QueryExecutor<PsiElement, DefinitionsScopedSea
|
||||
}
|
||||
|
||||
private fun processClassImplementations(klass: KtClass, consumer: Processor<PsiElement>): Boolean {
|
||||
val psiClass = runReadAction { klass.toLightClass() ?: KtFakeLightClass(klass) }
|
||||
val psiClass = runReadAction { klass.providedToLightClass() ?: providedCreateKtFakeLightClass(klass) }
|
||||
as? KtLightClass
|
||||
?: return false //TODO Implement FIR support for not nullable providedCreateKtFakeLightClass
|
||||
|
||||
val searchScope = runReadAction { psiClass.useScope }
|
||||
if (searchScope is LocalSearchScope) {
|
||||
+3
-3
@@ -14,12 +14,12 @@ import com.intellij.psi.search.searches.MethodReferencesSearch
|
||||
import com.intellij.psi.util.MethodSignatureUtil
|
||||
import com.intellij.psi.util.TypeConversionUtil
|
||||
import com.intellij.util.Processor
|
||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightMethods
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.idea.references.SyntheticPropertyAccessorReference
|
||||
import org.jetbrains.kotlin.idea.references.readWriteAccess
|
||||
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
|
||||
import org.jetbrains.kotlin.idea.util.runReadActionInSmartMode
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadActionInSmartMode
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.getPropertyNamesCandidatesByAccessorName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -106,7 +106,7 @@ class KotlinOverridingMethodReferenceSearcher : MethodUsagesSearcher() {
|
||||
}
|
||||
|
||||
fun countNonFinalLightMethods() = refElement
|
||||
.toLightMethods()
|
||||
.providedToLightMethods()
|
||||
.filterNot { it.hasModifierProperty(PsiModifier.FINAL) }
|
||||
|
||||
val lightMethods = when (refElement) {
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.search.usagesSearch
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import com.intellij.psi.search.searches.MethodReferencesSearch
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.asJava.unwrapped
|
||||
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightMethods
|
||||
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport
|
||||
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.createConstructorHandle
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.contains
|
||||
|
||||
fun PsiElement.processDelegationCallConstructorUsages(scope: SearchScope, process: (KtCallElement) -> Boolean): Boolean {
|
||||
val task = buildProcessDelegationCallConstructorUsagesTask(scope, process)
|
||||
return task()
|
||||
}
|
||||
|
||||
// should be executed under read-action, returns long-running part to be executed outside read-action
|
||||
fun PsiElement.buildProcessDelegationCallConstructorUsagesTask(scope: SearchScope, process: (KtCallElement) -> Boolean): () -> Boolean {
|
||||
ApplicationManager.getApplication().assertReadAccessAllowed()
|
||||
val task1 = buildProcessDelegationCallKotlinConstructorUsagesTask(scope, process)
|
||||
val task2 = buildProcessDelegationCallJavaConstructorUsagesTask(scope, process)
|
||||
return { task1() && task2() }
|
||||
}
|
||||
|
||||
private fun PsiElement.buildProcessDelegationCallKotlinConstructorUsagesTask(
|
||||
scope: SearchScope,
|
||||
process: (KtCallElement) -> Boolean
|
||||
): () -> Boolean {
|
||||
val element = unwrapped
|
||||
if (element != null && element !in scope) return { true }
|
||||
|
||||
val klass = when (element) {
|
||||
is KtConstructor<*> -> element.getContainingClassOrObject()
|
||||
is KtClass -> element
|
||||
else -> return { true }
|
||||
}
|
||||
|
||||
if (klass !is KtClass || element !is KtDeclaration) return { true }
|
||||
|
||||
val constructorHandler = createConstructorHandle(element)
|
||||
|
||||
if (!processClassDelegationCallsToSpecifiedConstructor(klass, constructorHandler, process)) return { false }
|
||||
|
||||
// long-running task, return it to execute outside read-action
|
||||
return { processInheritorsDelegatingCallToSpecifiedConstructor(klass, scope, constructorHandler, process) }
|
||||
}
|
||||
|
||||
private fun PsiElement.buildProcessDelegationCallJavaConstructorUsagesTask(
|
||||
scope: SearchScope,
|
||||
process: (KtCallElement) -> Boolean
|
||||
): () -> Boolean {
|
||||
if (this is KtLightElement<*, *>) return { true }
|
||||
// TODO: Temporary hack to avoid NPE while KotlinNoOriginLightMethod is around
|
||||
if (this is KtLightMethod && this.kotlinOrigin == null) return { true }
|
||||
if (!(this is PsiMethod && isConstructor)) return { true }
|
||||
val klass = containingClass ?: return { true }
|
||||
|
||||
val ctorHandle = createConstructorHandle(this)
|
||||
return { processInheritorsDelegatingCallToSpecifiedConstructor(klass, scope, ctorHandle, process) }
|
||||
}
|
||||
|
||||
|
||||
private fun processInheritorsDelegatingCallToSpecifiedConstructor(
|
||||
klass: PsiElement,
|
||||
scope: SearchScope,
|
||||
constructorCallComparator: KotlinSearchUsagesSupport.ConstructorCallHandle,
|
||||
process: (KtCallElement) -> Boolean
|
||||
): Boolean {
|
||||
return HierarchySearchRequest(klass, scope, false).searchInheritors().all {
|
||||
runReadAction {
|
||||
val unwrapped = it.takeIf { it.isValid }?.unwrapped
|
||||
if (unwrapped is KtClass)
|
||||
processClassDelegationCallsToSpecifiedConstructor(unwrapped, constructorCallComparator, process)
|
||||
else
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processClassDelegationCallsToSpecifiedConstructor(
|
||||
klass: KtClass,
|
||||
constructorCallHadle: KotlinSearchUsagesSupport.ConstructorCallHandle,
|
||||
process: (KtCallElement) -> Boolean
|
||||
): Boolean {
|
||||
for (secondaryConstructor in klass.secondaryConstructors) {
|
||||
val delegationCall = secondaryConstructor.getDelegationCall()
|
||||
if (constructorCallHadle.referencedTo(delegationCall)) {
|
||||
if (!process(delegationCall)) return false
|
||||
}
|
||||
}
|
||||
if (!klass.isEnum()) return true
|
||||
for (declaration in klass.declarations) {
|
||||
if (declaration is KtEnumEntry) {
|
||||
val delegationCall =
|
||||
declaration.superTypeListEntries.firstOrNull() as? KtSuperTypeCallEntry
|
||||
?: continue
|
||||
|
||||
if (constructorCallHadle.referencedTo(delegationCall.calleeExpression)) {
|
||||
if (!process(delegationCall)) return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun PsiElement.searchReferencesOrMethodReferences(): Collection<PsiReference> {
|
||||
val lightMethods = providedToLightMethods()
|
||||
return if (lightMethods.isNotEmpty()) {
|
||||
lightMethods.flatMapTo(LinkedHashSet()) { MethodReferencesSearch.search(it) }
|
||||
} else {
|
||||
ReferencesSearch.search(this).findAll()
|
||||
}
|
||||
}
|
||||
@@ -177,6 +177,9 @@ The Kotlin FIR plugin provides language support in IntelliJ IDEA and Android Stu
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
|
||||
<postStartupActivity implementation="org.jetbrains.kotlin.idea.PluginStartupActivity"/>
|
||||
<projectService serviceImplementation="org.jetbrains.kotlin.idea.PluginStartupService"/>
|
||||
|
||||
<iconProvider implementation="org.jetbrains.kotlin.idea.KotlinIconProviderBase"/>
|
||||
|
||||
<projectService serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.IdePackageOracleFactory"/>
|
||||
@@ -217,15 +220,15 @@ The Kotlin FIR plugin provides language support in IntelliJ IDEA and Android Stu
|
||||
<gotoDeclarationHandler implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinImportAliasGotoDeclarationHandler"/>
|
||||
<referencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearcher"/>
|
||||
<referencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinAliasedImportedElementSearcher"/>
|
||||
<!-- <directClassInheritorsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDirectInheritorsSearcher"/>-->
|
||||
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinConstructorDelegationCallReferenceSearcher"/>
|
||||
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinConventionMethodReferencesSearcher"/>
|
||||
<definitionsScopedSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDefinitionsSearcher"/>
|
||||
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinOverridingMethodReferenceSearcher"/>
|
||||
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinPropertyAccessorsReferenceSearcher"/>
|
||||
<!-- <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"/>-->
|
||||
<!-- <classesWithAnnotatedMembersSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinClassesWithAnnotatedMembersSearcher"/>-->
|
||||
<!-- <methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinPropertyAccessorsReferenceSearcher"/>-->
|
||||
<!-- <methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinConstructorDelegationCallReferenceSearcher"/>-->
|
||||
<!-- <methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinOverridingMethodReferenceSearcher"/>-->
|
||||
<!-- <methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinConventionMethodReferencesSearcher"/>-->
|
||||
<!-- <methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.DefaultAnnotationMethodKotlinImplicitReferenceSearcher"/>-->
|
||||
|
||||
<readWriteAccessDetector implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDetector" id="kotlin"/>
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.search
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.util.hasJavaResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.core.isInheritable
|
||||
import org.jetbrains.kotlin.idea.core.isOverridable
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.forEachOverridingMethod
|
||||
@@ -16,12 +18,15 @@ import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOpt
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.*
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinTypeAliasShortNameIndex
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.idea.util.actualsForExpected
|
||||
import org.jetbrains.kotlin.idea.util.expectedDeclarationIfAny
|
||||
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
|
||||
class KotlinSearchUsagesSupportImpl : KotlinSearchUsagesSupport {
|
||||
override fun actualsForExpected(declaration: KtDeclaration, module: Module?): Set<KtDeclaration> =
|
||||
declaration.actualsForExpected(module)
|
||||
|
||||
override fun dataClassComponentMethodName(element: KtParameter): String? =
|
||||
element.dataClassComponentFunction()?.name?.asString()
|
||||
@@ -101,4 +106,13 @@ class KotlinSearchUsagesSupportImpl : KotlinSearchUsagesSupport {
|
||||
|
||||
override fun isExpectDeclaration(declaration: KtDeclaration): Boolean =
|
||||
declaration.isExpectDeclaration()
|
||||
|
||||
override fun canBeResolvedWithFrontEnd(element: PsiElement): Boolean =
|
||||
element.hasJavaResolutionFacade()
|
||||
|
||||
override fun createConstructorHandle(ktDeclaration: KtDeclaration): KotlinSearchUsagesSupport.ConstructorCallHandle =
|
||||
KotlinConstructorCallLazyDescriptorHandle(ktDeclaration)
|
||||
|
||||
override fun createConstructorHandle(psiMethod: PsiMethod): KotlinSearchUsagesSupport.ConstructorCallHandle =
|
||||
JavaConstructorCallLazyDescriptorHandle(psiMethod)
|
||||
}
|
||||
@@ -16,27 +16,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.search.usagesSearch
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import com.intellij.psi.search.searches.MethodReferencesSearch
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.psi.util.MethodSignatureUtil
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.classes.lazyPub
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||
import org.jetbrains.kotlin.asJava.unwrapped
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.caches.project.NotUnderContentRootModuleInfo.project
|
||||
import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToParameterDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMemberDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaOrKotlinMemberDescriptor
|
||||
@@ -46,9 +37,8 @@ import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider
|
||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||
import org.jetbrains.kotlin.idea.project.findAnalyzerServices
|
||||
import org.jetbrains.kotlin.idea.references.unwrappedTargets
|
||||
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport
|
||||
import org.jetbrains.kotlin.idea.search.ReceiverTypeSearcherInfo
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
|
||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
|
||||
import org.jetbrains.kotlin.idea.util.FuzzyType
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
@@ -57,7 +47,6 @@ import org.jetbrains.kotlin.idea.util.toFuzzyType
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.contains
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
@@ -70,6 +59,27 @@ import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.util.isValidOperator
|
||||
|
||||
class KotlinConstructorCallLazyDescriptorHandle(ktElement: KtDeclaration) :
|
||||
KotlinSearchUsagesSupport.ConstructorCallHandle {
|
||||
private val descriptor: ConstructorDescriptor? by lazyPub { ktElement.constructor }
|
||||
|
||||
override fun referencedTo(element: KtElement): Boolean =
|
||||
element.getConstructorCallDescriptor().let {
|
||||
it != null && descriptor != null && it == descriptor
|
||||
}
|
||||
}
|
||||
|
||||
class JavaConstructorCallLazyDescriptorHandle(psiMethod: PsiMethod) :
|
||||
KotlinSearchUsagesSupport.ConstructorCallHandle {
|
||||
|
||||
private val descriptor: ConstructorDescriptor? by lazyPub { psiMethod.getJavaMethodDescriptor() as? ConstructorDescriptor }
|
||||
|
||||
override fun referencedTo(element: KtElement): Boolean =
|
||||
element.getConstructorCallDescriptor().let {
|
||||
it != null && descriptor != null && it == descriptor
|
||||
}
|
||||
}
|
||||
|
||||
fun tryRenderDeclarationCompactStyle(declaration: KtDeclaration): String? =
|
||||
declaration.descriptor?.let { DescriptorRenderer.COMPACT.render(it) }
|
||||
|
||||
@@ -143,104 +153,6 @@ private fun KtElement.getConstructorCallDescriptor(): DeclarationDescriptor? {
|
||||
return null
|
||||
}
|
||||
|
||||
fun PsiElement.processDelegationCallConstructorUsages(scope: SearchScope, process: (KtCallElement) -> Boolean): Boolean {
|
||||
val task = buildProcessDelegationCallConstructorUsagesTask(scope, process)
|
||||
return task()
|
||||
}
|
||||
|
||||
// should be executed under read-action, returns long-running part to be executed outside read-action
|
||||
fun PsiElement.buildProcessDelegationCallConstructorUsagesTask(scope: SearchScope, process: (KtCallElement) -> Boolean): () -> Boolean {
|
||||
ApplicationManager.getApplication().assertReadAccessAllowed()
|
||||
val task1 = buildProcessDelegationCallKotlinConstructorUsagesTask(scope, process)
|
||||
val task2 = buildProcessDelegationCallJavaConstructorUsagesTask(scope, process)
|
||||
return { task1() && task2() }
|
||||
}
|
||||
|
||||
private fun PsiElement.buildProcessDelegationCallKotlinConstructorUsagesTask(
|
||||
scope: SearchScope,
|
||||
process: (KtCallElement) -> Boolean
|
||||
): () -> Boolean {
|
||||
val element = unwrapped
|
||||
if (element != null && element !in scope) return { true }
|
||||
|
||||
val klass = when (element) {
|
||||
is KtConstructor<*> -> element.getContainingClassOrObject()
|
||||
is KtClass -> element
|
||||
else -> return { true }
|
||||
}
|
||||
|
||||
if (klass !is KtClass || element !is KtDeclaration) return { true }
|
||||
val descriptor = lazyPub { element.constructor }
|
||||
|
||||
if (!processClassDelegationCallsToSpecifiedConstructor(klass, descriptor, process)) return { false }
|
||||
|
||||
// long-running task, return it to execute outside read-action
|
||||
return { processInheritorsDelegatingCallToSpecifiedConstructor(klass, scope, descriptor, process) }
|
||||
}
|
||||
|
||||
private fun PsiElement.buildProcessDelegationCallJavaConstructorUsagesTask(
|
||||
scope: SearchScope,
|
||||
process: (KtCallElement) -> Boolean
|
||||
): () -> Boolean {
|
||||
if (this is KtLightElement<*, *>) return { true }
|
||||
// TODO: Temporary hack to avoid NPE while KotlinNoOriginLightMethod is around
|
||||
if (this is KtLightMethod && this.kotlinOrigin == null) return { true }
|
||||
if (!(this is PsiMethod && isConstructor)) return { true }
|
||||
val klass = containingClass ?: return { true }
|
||||
val descriptor = lazyPub { getJavaMethodDescriptor() as? ConstructorDescriptor }
|
||||
return { processInheritorsDelegatingCallToSpecifiedConstructor(klass, scope, descriptor, process) }
|
||||
}
|
||||
|
||||
|
||||
private fun processInheritorsDelegatingCallToSpecifiedConstructor(
|
||||
klass: PsiElement,
|
||||
scope: SearchScope,
|
||||
lazyDescriptor: Lazy<ConstructorDescriptor?>,
|
||||
process: (KtCallElement) -> Boolean
|
||||
): Boolean {
|
||||
return HierarchySearchRequest(klass, scope, false).searchInheritors().all {
|
||||
runReadAction {
|
||||
val unwrapped = it.takeIf { it.isValid }?.unwrapped
|
||||
if (unwrapped is KtClass)
|
||||
processClassDelegationCallsToSpecifiedConstructor(unwrapped, lazyDescriptor, process)
|
||||
else
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processClassDelegationCallsToSpecifiedConstructor(
|
||||
klass: KtClass,
|
||||
lazyDescriptor: Lazy<ConstructorDescriptor?>,
|
||||
process: (KtCallElement) -> Boolean
|
||||
): Boolean {
|
||||
for (secondaryConstructor in klass.secondaryConstructors) {
|
||||
val delegationCallDescriptor =
|
||||
secondaryConstructor.getDelegationCall().getConstructorCallDescriptor()
|
||||
?: continue
|
||||
|
||||
if (lazyDescriptor.value == delegationCallDescriptor) {
|
||||
if (!process(secondaryConstructor.getDelegationCall())) return false
|
||||
}
|
||||
}
|
||||
if (!klass.isEnum()) return true
|
||||
for (declaration in klass.declarations) {
|
||||
if (declaration is KtEnumEntry) {
|
||||
val delegationCall =
|
||||
declaration.superTypeListEntries.firstOrNull() as? KtSuperTypeCallEntry
|
||||
?: continue
|
||||
val constructorCallDescriptor =
|
||||
delegationCall.calleeExpression.getConstructorCallDescriptor()
|
||||
?: continue
|
||||
|
||||
if (lazyDescriptor.value == constructorCallDescriptor) {
|
||||
if (!process(delegationCall)) return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Check if reference resolves to extension function whose receiver is the same as declaration's parent (or its superclass)
|
||||
// Used in extension search
|
||||
fun PsiReference.isExtensionOfDeclarationClassUsage(declaration: KtNamedDeclaration): Boolean {
|
||||
@@ -304,15 +216,6 @@ fun PsiReference.isCallableOverrideUsage(declaration: KtNamedDeclaration): Boole
|
||||
}
|
||||
}
|
||||
|
||||
fun PsiElement.searchReferencesOrMethodReferences(): Collection<PsiReference> {
|
||||
val lightMethods = toLightMethods()
|
||||
return if (lightMethods.isNotEmpty()) {
|
||||
lightMethods.flatMapTo(LinkedHashSet()) { MethodReferencesSearch.search(it) }
|
||||
} else {
|
||||
ReferencesSearch.search(this).findAll()
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : PsiNamedElement> List<T>.filterDataClassComponentsIfDisabled(kotlinOptions: KotlinReferencesSearchOptions): List<T> {
|
||||
if (kotlinOptions.searchForComponentConventions) return this
|
||||
|
||||
|
||||
Reference in New Issue
Block a user