Refactored reference searches to take read-actions when necessary
This commit is contained in:
+6
-6
@@ -23,15 +23,15 @@ import com.intellij.psi.search.searches.ClassInheritorsSearch
|
||||
import com.intellij.util.EmptyQuery
|
||||
import com.intellij.util.Query
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
|
||||
fun HierarchySearchRequest<*>.searchInheritors(): Query<PsiClass> {
|
||||
val psiClass: PsiClass? = when (originalElement) {
|
||||
is KtClassOrObject -> originalElement.toLightClass()
|
||||
is PsiClass -> originalElement
|
||||
else -> null
|
||||
}
|
||||
if (psiClass == null) return EmptyQuery.getEmptyQuery()
|
||||
val psiClass: PsiClass = when (originalElement) {
|
||||
is KtClassOrObject -> runReadAction { originalElement.toLightClass() }
|
||||
is PsiClass -> originalElement
|
||||
else -> null
|
||||
} ?: return EmptyQuery.getEmptyQuery()
|
||||
|
||||
return ClassInheritorsSearch.search(
|
||||
psiClass,
|
||||
|
||||
+173
-182
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.asJava.toLightElements
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.idea.search.KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT
|
||||
import org.jetbrains.kotlin.idea.search.allScope
|
||||
@@ -46,6 +45,8 @@ import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import java.util.*
|
||||
|
||||
data class KotlinReferencesSearchOptions(val acceptCallableOverrides: Boolean = false,
|
||||
val acceptOverloads: Boolean = false,
|
||||
@@ -70,255 +71,245 @@ class KotlinReferencesSearchParameters(elementToSearch: PsiElement,
|
||||
}
|
||||
|
||||
class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearch.SearchParameters>() {
|
||||
|
||||
override fun processQuery(queryParameters: ReferencesSearch.SearchParameters, consumer: Processor<PsiReference>) {
|
||||
val element = queryParameters.elementToSearch
|
||||
val processor = QueryProcessor(queryParameters, consumer)
|
||||
runReadAction { processor.processInReadAction() }
|
||||
processor.executeLongRunningTasks()
|
||||
}
|
||||
|
||||
val unwrappedElement = element.namedUnwrappedElement ?: return
|
||||
private class QueryProcessor(val queryParameters: ReferencesSearch.SearchParameters, val consumer: Processor<PsiReference>) {
|
||||
|
||||
val kotlinOptions = (queryParameters as? KotlinReferencesSearchParameters)?.kotlinOptions
|
||||
?: KotlinReferencesSearchOptions.Empty
|
||||
private val kotlinOptions = (queryParameters as? KotlinReferencesSearchParameters)?.kotlinOptions
|
||||
?: KotlinReferencesSearchOptions.Empty
|
||||
|
||||
val specialSymbols = runReadAction { unwrappedElement.getSpecialNamesToSearch(kotlinOptions) }
|
||||
val words = runReadAction {
|
||||
val classNameForCompanionObject = unwrappedElement.getClassNameForCompanionObject()
|
||||
(specialSymbols?.first ?: emptyList()) +
|
||||
(if (classNameForCompanionObject != null) listOf(classNameForCompanionObject) else emptyList())
|
||||
private val longTasks = ArrayList<() -> Unit>()
|
||||
|
||||
fun executeLongRunningTasks() {
|
||||
longTasks.forEach { it() }
|
||||
}
|
||||
|
||||
val effectiveSearchScope = runReadAction {
|
||||
fun processInReadAction() {
|
||||
val element = queryParameters.elementToSearch
|
||||
if (!element.isValid) return
|
||||
|
||||
val unwrappedElement = element.namedUnwrappedElement ?: return
|
||||
|
||||
val specialSymbols = unwrappedElement.getSpecialNamesToSearch(kotlinOptions)
|
||||
val words = (specialSymbols?.first ?: emptyList()) + unwrappedElement.getClassNameForCompanionObject().singletonOrEmptyList()
|
||||
|
||||
val elements = if (unwrappedElement is KtDeclaration) unwrappedElement.toLightElements() else listOf(unwrappedElement)
|
||||
elements.fold(queryParameters.effectiveSearchScope) { scope, e -> scope.unionSafe(queryParameters.effectiveSearchScope(e)) }
|
||||
}
|
||||
|
||||
val refFilter: (PsiReference) -> Boolean = when {
|
||||
unwrappedElement is KtParameter -> ({ ref: PsiReference -> !ref.isNamedArgumentReference()/* they are processed later*/ })
|
||||
specialSymbols != null -> { ref -> ref.javaClass == specialSymbols.second }
|
||||
else -> ({true})
|
||||
}
|
||||
|
||||
val resultProcessor = KotlinRequestResultProcessor(unwrappedElement, filter = refFilter, options = kotlinOptions)
|
||||
|
||||
val name = runReadAction { unwrappedElement.name }
|
||||
if (kotlinOptions.anyEnabled()) {
|
||||
if (name != null) {
|
||||
queryParameters.optimizer.searchWord(name, effectiveSearchScope, UsageSearchContext.IN_CODE, true, unwrappedElement,
|
||||
resultProcessor)
|
||||
val effectiveSearchScope = elements.fold(queryParameters.effectiveSearchScope) { scope, e ->
|
||||
scope.unionSafe(queryParameters.effectiveSearchScope(e))
|
||||
}
|
||||
}
|
||||
words.forEach { word ->
|
||||
queryParameters.optimizer.searchWord(word, effectiveSearchScope,
|
||||
UsageSearchContext.ANY, true, unwrappedElement,
|
||||
resultProcessor)
|
||||
}
|
||||
|
||||
if (unwrappedElement is KtParameter && kotlinOptions.searchNamedArguments) {
|
||||
runReadAction { searchNamedArguments(unwrappedElement, queryParameters) }
|
||||
}
|
||||
val refFilter: (PsiReference) -> Boolean = when {
|
||||
unwrappedElement is KtParameter -> ({ ref: PsiReference -> !ref.isNamedArgumentReference()/* they are processed later*/ })
|
||||
specialSymbols != null -> { ref -> ref.javaClass == specialSymbols.second }
|
||||
else -> ({true})
|
||||
}
|
||||
|
||||
if (!(unwrappedElement is KtElement && isOnlyKotlinSearch(effectiveSearchScope))) {
|
||||
searchLightElements(queryParameters, element, consumer)
|
||||
}
|
||||
val resultProcessor = KotlinRequestResultProcessor(unwrappedElement, filter = refFilter, options = kotlinOptions)
|
||||
|
||||
if (element is KtFunction || element is PsiMethod) {
|
||||
val referenceSearcher = OperatorReferenceSearcher.create(
|
||||
element, effectiveSearchScope, consumer, queryParameters.optimizer, kotlinOptions)
|
||||
referenceSearcher?.run()
|
||||
}
|
||||
|
||||
if (kotlinOptions.searchForComponentConventions) {
|
||||
when (element) {
|
||||
is KtParameter -> {
|
||||
val componentFunctionDescriptor = runReadAction { element.dataClassComponentFunction() }
|
||||
if (componentFunctionDescriptor != null) {
|
||||
val containingClass = element.getStrictParentOfType<KtClassOrObject>()?.toLightClass()
|
||||
searchDataClassComponentUsages(queryParameters, containingClass, componentFunctionDescriptor, consumer, kotlinOptions)
|
||||
}
|
||||
}
|
||||
|
||||
is KtLightParameter -> {
|
||||
val componentFunctionDescriptor = runReadAction { element.kotlinOrigin?.dataClassComponentFunction() }
|
||||
if (componentFunctionDescriptor != null) {
|
||||
searchDataClassComponentUsages(queryParameters, element.method.containingClass, componentFunctionDescriptor, consumer, kotlinOptions)
|
||||
}
|
||||
val name = unwrappedElement.name
|
||||
if (kotlinOptions.anyEnabled()) {
|
||||
if (name != null) {
|
||||
queryParameters.optimizer.searchWord(
|
||||
name, effectiveSearchScope, UsageSearchContext.IN_CODE, true, unwrappedElement, resultProcessor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
words.forEach { word ->
|
||||
queryParameters.optimizer.searchWord(
|
||||
word, effectiveSearchScope, UsageSearchContext.ANY, true, unwrappedElement, resultProcessor)
|
||||
}
|
||||
|
||||
private fun searchNamedArguments(parameter: KtParameter, queryParameters: ReferencesSearch.SearchParameters) {
|
||||
val parameterName = parameter.name ?: return
|
||||
val function = parameter.ownerFunction ?: return
|
||||
if (function.nameAsName?.isSpecial ?: true) return
|
||||
val project = function.project
|
||||
var namedArgsScope = function.useScope.intersectWith(queryParameters.scopeDeterminedByUser)
|
||||
if (unwrappedElement is KtParameter && kotlinOptions.searchNamedArguments) {
|
||||
searchNamedArguments(unwrappedElement)
|
||||
}
|
||||
|
||||
if (namedArgsScope is GlobalSearchScope) {
|
||||
namedArgsScope = KotlinSourceFilterScope.sourcesAndLibraries(namedArgsScope, project)
|
||||
if (!(unwrappedElement is KtElement && isOnlyKotlinSearch(effectiveSearchScope))) {
|
||||
searchLightElements(element)
|
||||
}
|
||||
|
||||
val filesWithFunctionName = CacheManager.SERVICE.getInstance(project).getVirtualFilesWithWord(
|
||||
function.name!!, UsageSearchContext.IN_CODE, namedArgsScope, true)
|
||||
namedArgsScope = GlobalSearchScope.filesScope(project, filesWithFunctionName.asList())
|
||||
}
|
||||
if (element is KtFunction || element is PsiMethod) {
|
||||
val referenceSearcher = OperatorReferenceSearcher.create(
|
||||
element, effectiveSearchScope, consumer, queryParameters.optimizer, kotlinOptions)
|
||||
if (referenceSearcher != null) {
|
||||
longTasks.add { referenceSearcher.run() }
|
||||
}
|
||||
|
||||
val processor = KotlinRequestResultProcessor(parameter, filter = { it.isNamedArgumentReference() })
|
||||
queryParameters.optimizer.searchWord(parameterName,
|
||||
namedArgsScope,
|
||||
KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT,
|
||||
true,
|
||||
parameter,
|
||||
processor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiReference.isNamedArgumentReference(): Boolean {
|
||||
return this is KtSimpleNameReference && expression.parent is KtValueArgumentName
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun processKtClassOrObject(element: KtClassOrObject, queryParameters: ReferencesSearch.SearchParameters) {
|
||||
val className = runReadAction { element.name }
|
||||
if (className != null) {
|
||||
val lightClass = runReadAction { element.toLightClass() }
|
||||
if (lightClass != null) {
|
||||
searchNamedElement(queryParameters, lightClass, className)
|
||||
|
||||
if (element is KtObjectDeclaration && element.isCompanion()) {
|
||||
val fieldForCompanionObject = runReadAction { LightClassUtil.getLightFieldForCompanionObject(element) }
|
||||
if (fieldForCompanionObject != null) {
|
||||
searchNamedElement(queryParameters, fieldForCompanionObject)
|
||||
if (kotlinOptions.searchForComponentConventions) {
|
||||
when (element) {
|
||||
is KtParameter -> {
|
||||
val componentFunctionDescriptor = element.dataClassComponentFunction()
|
||||
if (componentFunctionDescriptor != null) {
|
||||
val containingClass = element.getStrictParentOfType<KtClassOrObject>()?.toLightClass()
|
||||
searchDataClassComponentUsages(containingClass, componentFunctionDescriptor, kotlinOptions)
|
||||
}
|
||||
}
|
||||
|
||||
val kotlinReferencesSearchOptions = (queryParameters as? KotlinReferencesSearchParameters)?.kotlinOptions
|
||||
if (kotlinReferencesSearchOptions?.acceptCompanionObjectMembers == true) {
|
||||
runReadAction {
|
||||
val originClass = element.getStrictParentOfType<KtClass>()
|
||||
val originLightClass = originClass?.toLightClass()
|
||||
if (originLightClass != null) {
|
||||
val lightDeclarations: List<KtLightElement<*, *>?> =
|
||||
originLightClass.methods.map { it as? KtLightMethod } +
|
||||
originLightClass.fields.map { it as? KtLightField }
|
||||
|
||||
for (declaration in element.declarations) {
|
||||
val lightDeclaration = lightDeclarations.find { it?.kotlinOrigin == declaration }
|
||||
if (lightDeclaration != null) {
|
||||
searchNamedElement(queryParameters, lightDeclaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is KtLightParameter -> {
|
||||
val componentFunctionDescriptor = element.kotlinOrigin?.dataClassComponentFunction()
|
||||
if (componentFunctionDescriptor != null) {
|
||||
searchDataClassComponentUsages(element.method.containingClass, componentFunctionDescriptor, kotlinOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun findStaticMethodsFromCompanionObject(declaration: KtDeclaration): List<PsiMethod> {
|
||||
val originObject = declaration.parents
|
||||
.dropWhile { it is KtClassBody }
|
||||
.firstOrNull() as? KtObjectDeclaration ?: return emptyList()
|
||||
if (originObject.isCompanion()) {
|
||||
val originClass = originObject.getStrictParentOfType<KtClass>()
|
||||
val originLightClass = originClass?.toLightClass() ?: return emptyList()
|
||||
val allMethods = originLightClass.allMethods
|
||||
return allMethods.filter { it is KtLightMethod && it.kotlinOrigin == declaration }
|
||||
private fun searchNamedArguments(parameter: KtParameter) {
|
||||
val parameterName = parameter.name ?: return
|
||||
val function = parameter.ownerFunction ?: return
|
||||
if (function.nameAsName?.isSpecial ?: true) return
|
||||
val project = function.project
|
||||
var namedArgsScope = function.useScope.intersectWith(queryParameters.scopeDeterminedByUser)
|
||||
|
||||
if (namedArgsScope is GlobalSearchScope) {
|
||||
namedArgsScope = KotlinSourceFilterScope.sourcesAndLibraries(namedArgsScope, project)
|
||||
|
||||
val filesWithFunctionName = CacheManager.SERVICE.getInstance(project).getVirtualFilesWithWord(
|
||||
function.name!!, UsageSearchContext.IN_CODE, namedArgsScope, true)
|
||||
namedArgsScope = GlobalSearchScope.filesScope(project, filesWithFunctionName.asList())
|
||||
}
|
||||
return emptyList()
|
||||
|
||||
val processor = KotlinRequestResultProcessor(parameter, filter = { it.isNamedArgumentReference() })
|
||||
queryParameters.optimizer.searchWord(parameterName,
|
||||
namedArgsScope,
|
||||
KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT,
|
||||
true,
|
||||
parameter,
|
||||
processor)
|
||||
}
|
||||
|
||||
private fun processStaticsFromCompanionObject(element: KtDeclaration, queryParameters: ReferencesSearch.SearchParameters) {
|
||||
val staticsFromCompanionObject = runReadAction { findStaticMethodsFromCompanionObject(element) }
|
||||
staticsFromCompanionObject.forEach { searchNamedElement(queryParameters, it) }
|
||||
}
|
||||
|
||||
private fun searchPropertyMethods(queryParameters: ReferencesSearch.SearchParameters, parameter: KtParameter) {
|
||||
val lightElements = runReadAction { parameter.toLightElements() }
|
||||
lightElements.forEach { searchNamedElement(queryParameters, it) }
|
||||
}
|
||||
|
||||
private fun searchDataClassComponentUsages(queryParameters: ReferencesSearch.SearchParameters,
|
||||
containingClass: PsiClass?,
|
||||
componentFunctionDescriptor: FunctionDescriptor,
|
||||
consumer: Processor<PsiReference>,
|
||||
kotlinOptions: KotlinReferencesSearchOptions
|
||||
) {
|
||||
val componentFunction = containingClass?.methods?.find {
|
||||
it.name == componentFunctionDescriptor.name.asString() && it.parameterList.parametersCount == 0
|
||||
}
|
||||
if (componentFunction != null) {
|
||||
searchNamedElement(queryParameters, componentFunction)
|
||||
val searcher = OperatorReferenceSearcher.create(
|
||||
componentFunction, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer, kotlinOptions)
|
||||
searcher!!.run()
|
||||
}
|
||||
}
|
||||
|
||||
private fun searchLightElements(queryParameters: ReferencesSearch.SearchParameters, element: PsiElement, consumer: Processor<PsiReference>) {
|
||||
private fun searchLightElements(element: PsiElement) {
|
||||
when (element) {
|
||||
is KtClassOrObject -> processKtClassOrObject(element, queryParameters)
|
||||
is KtClassOrObject -> {
|
||||
processKtClassOrObject(element)
|
||||
}
|
||||
|
||||
is KtNamedFunction, is KtSecondaryConstructor -> {
|
||||
val function = element as KtFunction
|
||||
val name = runReadAction { function.name }
|
||||
val name = (element as KtFunction).name
|
||||
if (name != null) {
|
||||
val methods = runReadAction { LightClassUtil.getLightClassMethods(function) }
|
||||
val methods = LightClassUtil.getLightClassMethods(element)
|
||||
for (method in methods) {
|
||||
searchNamedElement(queryParameters, method)
|
||||
searchNamedElement(method)
|
||||
}
|
||||
}
|
||||
|
||||
processStaticsFromCompanionObject(element, queryParameters)
|
||||
processStaticsFromCompanionObject(element)
|
||||
}
|
||||
|
||||
is KtProperty -> {
|
||||
val propertyMethods = runReadAction { LightClassUtil.getLightClassPropertyMethods(element) }
|
||||
propertyMethods.allDeclarations.forEach { searchNamedElement(queryParameters, it) }
|
||||
processStaticsFromCompanionObject(element, queryParameters)
|
||||
val propertyMethods = LightClassUtil.getLightClassPropertyMethods(element)
|
||||
propertyMethods.allDeclarations.forEach { searchNamedElement(it) }
|
||||
processStaticsFromCompanionObject(element)
|
||||
}
|
||||
|
||||
is KtParameter -> {
|
||||
searchPropertyMethods(queryParameters, element)
|
||||
searchPropertyAccessorMethods(element)
|
||||
}
|
||||
|
||||
is KtLightMethod -> {
|
||||
val declaration = element.kotlinOrigin
|
||||
if (declaration is KtProperty || (declaration is KtParameter && declaration.hasValOrVar())) {
|
||||
searchNamedElement(queryParameters, declaration as PsiNamedElement)
|
||||
processStaticsFromCompanionObject(declaration, queryParameters)
|
||||
searchNamedElement(declaration as PsiNamedElement)
|
||||
processStaticsFromCompanionObject(declaration)
|
||||
}
|
||||
else if (declaration is KtPropertyAccessor) {
|
||||
val property = declaration.getStrictParentOfType<KtProperty>()
|
||||
searchNamedElement(queryParameters, property)
|
||||
searchNamedElement(property)
|
||||
}
|
||||
else if (declaration is KtFunction) {
|
||||
processStaticsFromCompanionObject(declaration, queryParameters)
|
||||
processStaticsFromCompanionObject(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
is KtLightParameter -> {
|
||||
val origin = element.kotlinOrigin ?: return
|
||||
searchPropertyMethods(queryParameters, origin)
|
||||
searchPropertyAccessorMethods(origin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isOnlyKotlinSearch(searchScope: SearchScope) =
|
||||
searchScope is LocalSearchScope && runReadAction {
|
||||
searchScope.scope.all { it.containingFile.fileType == KotlinFileType.INSTANCE }
|
||||
}
|
||||
private fun searchPropertyAccessorMethods(origin: KtParameter) {
|
||||
origin.toLightElements().forEach { searchNamedElement(it) }
|
||||
}
|
||||
|
||||
private fun searchNamedElement(queryParameters: ReferencesSearch.SearchParameters,
|
||||
element: PsiNamedElement?,
|
||||
name: String? = element?.name) {
|
||||
private fun processKtClassOrObject(element: KtClassOrObject) {
|
||||
val className = element.name ?: return
|
||||
val lightClass = element.toLightClass() ?: return
|
||||
searchNamedElement(lightClass, className)
|
||||
|
||||
if (element is KtObjectDeclaration && element.isCompanion()) {
|
||||
LightClassUtil.getLightFieldForCompanionObject(element)?.let { searchNamedElement(it) }
|
||||
|
||||
if (kotlinOptions.acceptCompanionObjectMembers) {
|
||||
val originLightClass = element.getStrictParentOfType<KtClass>()?.toLightClass()
|
||||
if (originLightClass != null) {
|
||||
val lightDeclarations: List<KtLightElement<*, *>?> =
|
||||
originLightClass.methods.map { it as? KtLightMethod } +
|
||||
originLightClass.fields.map { it as? KtLightField }
|
||||
|
||||
for (declaration in element.declarations) {
|
||||
lightDeclarations
|
||||
.firstOrNull { it?.kotlinOrigin == declaration }
|
||||
?.let { searchNamedElement(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun searchDataClassComponentUsages(containingClass: PsiClass?,
|
||||
componentFunctionDescriptor: FunctionDescriptor,
|
||||
kotlinOptions: KotlinReferencesSearchOptions
|
||||
) {
|
||||
val componentFunction = containingClass?.methods?.firstOrNull {
|
||||
it.name == componentFunctionDescriptor.name.asString() && it.parameterList.parametersCount == 0
|
||||
}
|
||||
if (componentFunction != null) {
|
||||
searchNamedElement(componentFunction)
|
||||
|
||||
val searcher = OperatorReferenceSearcher.create(
|
||||
componentFunction, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer, kotlinOptions)
|
||||
longTasks.add { searcher!!.run() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun isOnlyKotlinSearch(searchScope: SearchScope): Boolean {
|
||||
return searchScope is LocalSearchScope && searchScope.scope.all { it.containingFile is KtFile }
|
||||
}
|
||||
|
||||
private fun processStaticsFromCompanionObject(element: KtDeclaration) {
|
||||
findStaticMethodsFromCompanionObject(element).forEach { searchNamedElement(it) }
|
||||
}
|
||||
|
||||
private fun findStaticMethodsFromCompanionObject(declaration: KtDeclaration): List<PsiMethod> {
|
||||
val originObject = declaration.parents
|
||||
.dropWhile { it is KtClassBody }
|
||||
.firstOrNull() as? KtObjectDeclaration ?: return emptyList()
|
||||
if (!originObject.isCompanion()) return emptyList()
|
||||
val originClass = originObject.getStrictParentOfType<KtClass>()
|
||||
val originLightClass = originClass?.toLightClass() ?: return emptyList()
|
||||
val allMethods = originLightClass.allMethods
|
||||
return allMethods.filter { it is KtLightMethod && it.kotlinOrigin == declaration }
|
||||
}
|
||||
|
||||
private fun searchNamedElement(element: PsiNamedElement?, name: String? = element?.name) {
|
||||
if (name != null && element != null) {
|
||||
val scope = runReadAction { queryParameters.effectiveSearchScope(element) }
|
||||
val scope = queryParameters.effectiveSearchScope(element)
|
||||
val context = UsageSearchContext.IN_CODE + UsageSearchContext.IN_FOREIGN_LANGUAGES + UsageSearchContext.IN_COMMENTS
|
||||
val kotlinOptions = (queryParameters as? KotlinReferencesSearchParameters)?.kotlinOptions
|
||||
?: KotlinReferencesSearchOptions.Empty
|
||||
val resultProcessor = KotlinRequestResultProcessor(element,
|
||||
queryParameters.elementToSearch.namedUnwrappedElement ?: element,
|
||||
options = kotlinOptions)
|
||||
queryParameters.optimizer.searchWord(name, scope, context.toShort(), true, element,
|
||||
resultProcessor)
|
||||
queryParameters.optimizer.searchWord(name, scope, context.toShort(), true, element, resultProcessor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiReference.isNamedArgumentReference(): Boolean {
|
||||
return this is KtSimpleNameReference && expression.parent is KtValueArgumentName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+83
-45
@@ -47,6 +47,7 @@ import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchPar
|
||||
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
|
||||
import org.jetbrains.kotlin.idea.util.FuzzyType
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
|
||||
@@ -78,18 +79,20 @@ class ExpressionsOfTypeProcessor(
|
||||
var testLog: MutableList<String>? = null
|
||||
|
||||
fun logPresentation(element: PsiElement): String? {
|
||||
if (element !is KtDeclaration && element !is PsiMember) return element.text
|
||||
val fqName = element.getKotlinFqName()?.asString()
|
||||
?: (element as? KtNamedDeclaration)?.name
|
||||
return when (element) {
|
||||
is PsiMethod -> fqName + element.parameterList.text
|
||||
is KtFunction -> fqName + element.valueParameterList!!.text
|
||||
is KtParameter -> {
|
||||
val owner = element.ownerFunction?.let { logPresentation(it) } ?: element.parent.toString()
|
||||
"parameter ${element.name} of $owner"
|
||||
return runReadAction {
|
||||
if (element !is KtDeclaration && element !is PsiMember) return@runReadAction element.text
|
||||
val fqName = element.getKotlinFqName()?.asString()
|
||||
?: (element as? KtNamedDeclaration)?.name
|
||||
when (element) {
|
||||
is PsiMethod -> fqName + element.parameterList.text
|
||||
is KtFunction -> fqName + element.valueParameterList!!.text
|
||||
is KtParameter -> {
|
||||
val owner = element.ownerFunction?.let { logPresentation(it) } ?: element.parent.toString()
|
||||
"parameter ${element.name} of $owner"
|
||||
}
|
||||
is KtDestructuringDeclaration -> element.entries.joinToString(", ", prefix = "(", postfix = ")") { it.text }
|
||||
else -> fqName
|
||||
}
|
||||
is KtDestructuringDeclaration -> element.entries.joinToString(", ", prefix = "(", postfix = ")") { it.text }
|
||||
else -> fqName
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,18 +121,10 @@ class ExpressionsOfTypeProcessor(
|
||||
private val scopesToUsePlainSearch = LinkedHashMap<KtFile, ArrayList<PsiElement>>()
|
||||
|
||||
fun run() {
|
||||
if (searchScope.restrictToKotlinSources().isEmpty()) return // optimization
|
||||
|
||||
val classDescriptor = typeToSearch.type.constructor.declarationDescriptor ?: return
|
||||
val classDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, classDescriptor)
|
||||
val psiClass = when (classDeclaration) {
|
||||
is PsiClass -> classDeclaration
|
||||
is KtClassOrObject -> classDeclaration.toLightClass() ?: return
|
||||
else -> return
|
||||
}
|
||||
val psiClass = runReadAction { detectClassToSearch() } ?: return
|
||||
|
||||
// for class from library always use plain search because we cannot search usages in compiled code (we could though)
|
||||
if (!ProjectRootsUtil.isInProjectSource(psiClass)) {
|
||||
if (!runReadAction { psiClass.isValid && ProjectRootsUtil.isInProjectSource (psiClass) }) {
|
||||
suspiciousScopeHandler(searchScope)
|
||||
return
|
||||
}
|
||||
@@ -138,9 +133,26 @@ class ExpressionsOfTypeProcessor(
|
||||
|
||||
processTasks()
|
||||
|
||||
val scopeElements = scopesToUsePlainSearch.values.flatMap { it }.toTypedArray()
|
||||
if (scopeElements.isNotEmpty()) {
|
||||
suspiciousScopeHandler(LocalSearchScope(scopeElements))
|
||||
runReadAction {
|
||||
val scopeElements = scopesToUsePlainSearch.values
|
||||
.flatMap { it }
|
||||
.filter { it.isValid }
|
||||
.toTypedArray()
|
||||
if (scopeElements.isNotEmpty()) {
|
||||
suspiciousScopeHandler(LocalSearchScope(scopeElements))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun detectClassToSearch(): PsiClass? {
|
||||
if (searchScope.restrictToKotlinSources().isEmpty()) return null // optimization
|
||||
|
||||
val classDescriptor = typeToSearch.type.constructor.declarationDescriptor ?: return null
|
||||
val classDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, classDescriptor)
|
||||
return when (classDeclaration) {
|
||||
is PsiClass -> classDeclaration
|
||||
is KtClassOrObject -> classDeclaration.toLightClass()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,19 +179,19 @@ class ExpressionsOfTypeProcessor(
|
||||
data class ProcessClassUsagesTask(val classToSearch: PsiClass) : Task {
|
||||
override fun perform() {
|
||||
testLog?.add("Searched references to ${logPresentation(classToSearch)}")
|
||||
ReferencesSearch.search(classToSearch).forEach(Processor processor@ { reference -> //TODO: see KT-13607
|
||||
if (processClassUsage(reference)) return@processor true
|
||||
searchReferences(classToSearch, GlobalSearchScope.allScope(project)) { reference ->
|
||||
if (processClassUsage(reference)) return@searchReferences true
|
||||
|
||||
if (mode != Mode.ALWAYS_SMART) {
|
||||
downShiftToPlainSearch()
|
||||
return@processor false
|
||||
return@searchReferences false
|
||||
}
|
||||
|
||||
val element = reference.element
|
||||
val document = PsiDocumentManager.getInstance(project).getDocument(element.containingFile)
|
||||
val lineAndCol = DiagnosticUtils.offsetToLineAndColumn(document, element.startOffset)
|
||||
error("Unsupported reference: '${element.text}' in ${element.containingFile.name} line ${lineAndCol.line} column ${lineAndCol.column}")
|
||||
})
|
||||
}
|
||||
|
||||
// we must use plain search inside our class (and inheritors) because implicit 'this' can happen anywhere
|
||||
(classToSearch as? KtLightClass)?.kotlinOrigin?.let { usePlainSearch(it) }
|
||||
@@ -211,7 +223,7 @@ class ExpressionsOfTypeProcessor(
|
||||
testLog?.add("Searched references to ${logPresentation(declaration)} in Kotlin files")
|
||||
val searchParameters = KotlinReferencesSearchParameters(
|
||||
declaration, scope, kotlinOptions = KotlinReferencesSearchOptions(searchNamedArguments = false))
|
||||
ReferencesSearch.search(searchParameters).forEach { reference ->
|
||||
searchReferences(searchParameters) { reference ->
|
||||
when (kind) {
|
||||
CallableToProcessKind.HAS_OUR_CLASS_TYPE -> {
|
||||
if (reference is KtDestructuringDeclarationReference) {
|
||||
@@ -227,6 +239,7 @@ class ExpressionsOfTypeProcessor(
|
||||
(reference.element as? KtReferenceExpression)?.let { processLambdasForCallableReference(it) }
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,13 +252,14 @@ class ExpressionsOfTypeProcessor(
|
||||
//TODO: what about other JVM languages?
|
||||
val scope = GlobalSearchScope.getScopeRestrictedByFileTypes(GlobalSearchScope.projectScope(project), JavaFileType.INSTANCE)
|
||||
testLog?.add("Searched references to ${logPresentation(psiClass)} in java files")
|
||||
ReferencesSearch.search(psiClass, scope).forEach { reference ->
|
||||
searchReferences(psiClass, scope) { reference ->
|
||||
// check if the reference is method parameter type
|
||||
val parameter = ((reference as? PsiJavaCodeReferenceElement)?.parent as? PsiTypeElement)?.parent as? PsiParameter
|
||||
val method = parameter?.declarationScope as? PsiMethod
|
||||
if (method != null) {
|
||||
addCallableDeclarationToProcess(method, CallableToProcessKind.PROCESS_LAMBDAS)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -559,24 +573,30 @@ class ExpressionsOfTypeProcessor(
|
||||
}
|
||||
|
||||
private fun usePlainSearch(scope: KtElement) {
|
||||
val file = scope.getContainingKtFile()
|
||||
val restricted = LocalSearchScope(scope).intersectWith(searchScope)
|
||||
if (restricted is LocalSearchScope) {
|
||||
ScopeLoop@
|
||||
for (element in restricted.scope) {
|
||||
val prevElements = scopesToUsePlainSearch.getOrPut(file) { ArrayList() }
|
||||
for ((index, prevElement) in prevElements.withIndex()) {
|
||||
if (prevElement.isAncestor(element, strict = false)) continue@ScopeLoop
|
||||
if (element.isAncestor(prevElement)) {
|
||||
prevElements[index] = element
|
||||
continue@ScopeLoop
|
||||
runReadAction {
|
||||
if (!scope.isValid) return@runReadAction
|
||||
|
||||
val file = scope.getContainingKtFile()
|
||||
val restricted = LocalSearchScope(scope).intersectWith(searchScope)
|
||||
if (restricted is LocalSearchScope) {
|
||||
ScopeLoop@
|
||||
for (element in restricted.scope) {
|
||||
val prevElements = scopesToUsePlainSearch.getOrPut(file) { ArrayList() }
|
||||
for ((index, prevElement) in prevElements.withIndex()) {
|
||||
if (!prevElement.isValid) continue@ScopeLoop
|
||||
if (prevElement.isAncestor(element, strict = false)) continue@ScopeLoop
|
||||
if (element.isAncestor(prevElement)) {
|
||||
prevElements[index] = element
|
||||
continue@ScopeLoop
|
||||
}
|
||||
}
|
||||
prevElements.add(element)
|
||||
}
|
||||
prevElements.add(element)
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(restricted == GlobalSearchScope.EMPTY_SCOPE)
|
||||
else {
|
||||
assert(restricted == GlobalSearchScope.EMPTY_SCOPE)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,4 +662,22 @@ class ExpressionsOfTypeProcessor(
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun searchReferences(element: PsiElement,scope: SearchScope, processor: (PsiReference) -> Boolean) {
|
||||
val parameters = ReferencesSearch.SearchParameters(element, scope, false)
|
||||
searchReferences(parameters, processor)
|
||||
}
|
||||
|
||||
private fun searchReferences(parameters: ReferencesSearch.SearchParameters, processor: (PsiReference) -> Boolean) {
|
||||
ReferencesSearch.search(parameters).forEach(Processor { ref ->
|
||||
runReadAction {
|
||||
if (ref.element.isValid) {
|
||||
processor(ref)
|
||||
}
|
||||
else {
|
||||
true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+28
-9
@@ -79,6 +79,21 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
consumer: Processor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
): OperatorReferenceSearcher<*>? {
|
||||
return runReadAction {
|
||||
if (declaration.isValid)
|
||||
_create(declaration, searchScope, consumer, optimizer, options)
|
||||
else
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun _create(
|
||||
declaration: PsiElement,
|
||||
searchScope: SearchScope,
|
||||
consumer: Processor<PsiReference>,
|
||||
optimizer: SearchRequestCollector,
|
||||
options: KotlinReferencesSearchOptions
|
||||
): OperatorReferenceSearcher<*>? {
|
||||
val functionName = when (declaration) {
|
||||
is KtNamedFunction -> declaration.name
|
||||
@@ -212,16 +227,20 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
|
||||
if (scope is LocalSearchScope) {
|
||||
for (element in scope.scope) {
|
||||
element.accept(object : PsiRecursiveElementWalkingVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
val reference = extractReference(element)
|
||||
if (reference != null && reference.isReferenceTo(targetDeclaration)) {
|
||||
consumer.process(reference)
|
||||
}
|
||||
runReadAction {
|
||||
if (element.isValid) {
|
||||
element.accept(object : PsiRecursiveElementWalkingVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
val reference = extractReference(element)
|
||||
if (reference != null && reference.isReferenceTo(targetDeclaration)) {
|
||||
consumer.process(reference)
|
||||
}
|
||||
|
||||
super.visitElement(element)
|
||||
super.visitElement(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -238,7 +257,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
ProjectRootManager.getInstance(project).fileIndex.iterateContent { file ->
|
||||
if (file in scope) {
|
||||
val ktFile = psiManager.findFile(file) as? KtFile
|
||||
val ktFile = runReadAction { psiManager.findFile(file) as? KtFile }
|
||||
if (ktFile != null) {
|
||||
doPlainSearch(LocalSearchScope(ktFile))
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.getJavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.idea.references.unwrappedTargets
|
||||
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
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
@@ -39,6 +40,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
|
||||
val KtDeclaration.descriptor: DeclarationDescriptor?
|
||||
get() = this.analyze().get(BindingContext.DECLARATION_TO_DESCRIPTOR, this)
|
||||
@@ -109,36 +111,40 @@ private fun KtElement.getConstructorCallDescriptor(): DeclarationDescriptor? {
|
||||
return null
|
||||
}
|
||||
|
||||
fun PsiElement.processDelegationCallConstructorUsages(scope: SearchScope, process: (KtCallElement) -> Boolean): Boolean {
|
||||
if (!processDelegationCallKotlinConstructorUsages(scope, process)) return false
|
||||
return processDelegationCallJavaConstructorUsages(scope, process)
|
||||
// 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 {
|
||||
val task1 = buildProcessDelegationCallKotlinConstructorUsagesTask(scope, process)
|
||||
val task2 = buildProcessDelegationCallJavaConstructorUsagesTask(scope, process)
|
||||
return { task1() && task2() }
|
||||
}
|
||||
|
||||
private fun PsiElement.processDelegationCallKotlinConstructorUsages(scope: SearchScope, process: (KtCallElement) -> Boolean): Boolean {
|
||||
private fun PsiElement.buildProcessDelegationCallKotlinConstructorUsagesTask(scope: SearchScope, process: (KtCallElement) -> Boolean): () -> Boolean {
|
||||
val element = unwrapped
|
||||
if (element != null && element !in scope) return true
|
||||
if (element != null && element !in scope) return { true }
|
||||
|
||||
val klass = when (element) {
|
||||
is KtConstructor<*> -> element.getContainingClassOrObject()
|
||||
is KtClass -> element
|
||||
else -> return true
|
||||
else -> return { true }
|
||||
}
|
||||
|
||||
if (klass !is KtClass || element !is KtDeclaration) return true
|
||||
val descriptor = element.constructor ?: return true
|
||||
if (klass !is KtClass || element !is KtDeclaration) return { true }
|
||||
val descriptor = element.constructor ?: return { true }
|
||||
|
||||
if (!processClassDelegationCallsToSpecifiedConstructor(klass, descriptor, process)) return false
|
||||
return processInheritorsDelegatingCallToSpecifiedConstructor(klass, scope, descriptor, process)
|
||||
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.processDelegationCallJavaConstructorUsages(scope: SearchScope, process: (KtCallElement) -> Boolean): Boolean {
|
||||
if (this is KtLightElement<*, *>) return true
|
||||
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 = getJavaMethodDescriptor() as? ConstructorDescriptor ?: return true
|
||||
return processInheritorsDelegatingCallToSpecifiedConstructor(klass, scope, descriptor, process)
|
||||
if (this is KtLightMethod && this.kotlinOrigin == null) return { true }
|
||||
if (!(this is PsiMethod && isConstructor)) return { true }
|
||||
val klass = containingClass ?: return { true }
|
||||
val descriptor = getJavaMethodDescriptor() as? ConstructorDescriptor ?: return { true }
|
||||
return { processInheritorsDelegatingCallToSpecifiedConstructor(klass, scope, descriptor, process) }
|
||||
}
|
||||
|
||||
|
||||
@@ -149,11 +155,13 @@ private fun processInheritorsDelegatingCallToSpecifiedConstructor(
|
||||
process: (KtCallElement) -> Boolean
|
||||
): Boolean {
|
||||
return HierarchySearchRequest(klass, scope, false).searchInheritors().all {
|
||||
val unwrapped = it.unwrapped
|
||||
if (unwrapped is KtClass) {
|
||||
processClassDelegationCallsToSpecifiedConstructor(unwrapped, descriptor, process)
|
||||
} else
|
||||
true
|
||||
runReadAction {
|
||||
val unwrapped = it.check { it.isValid }?.unwrapped
|
||||
if (unwrapped is KtClass)
|
||||
processClassDelegationCallsToSpecifiedConstructor(unwrapped, descriptor, process)
|
||||
else
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+81
-93
@@ -22,8 +22,6 @@ import com.intellij.find.findUsages.JavaFindUsagesHelper
|
||||
import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.search.PsiElementProcessor
|
||||
import com.intellij.psi.search.PsiElementProcessorAdapter
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
@@ -44,9 +42,10 @@ import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchPar
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.isConstructorUsage
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.processDelegationCallConstructorUsages
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.buildProcessDelegationCallConstructorUsagesTask
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.contains
|
||||
import org.jetbrains.kotlin.psi.psiUtil.effectiveDeclarations
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
@@ -71,19 +70,60 @@ class KotlinFindClassUsagesHandler(
|
||||
this)
|
||||
}
|
||||
|
||||
override fun searchReferences(element: PsiElement, processor: Processor<UsageInfo>, options: FindUsagesOptions): Boolean {
|
||||
val kotlinOptions = options as KotlinClassFindUsagesOptions
|
||||
override fun createSearcher(element: PsiElement, processor: Processor<UsageInfo>, options: FindUsagesOptions): Searcher {
|
||||
return MySearcher(element, processor, options)
|
||||
}
|
||||
|
||||
fun processInheritors(): Boolean {
|
||||
val request = HierarchySearchRequest(element, options.searchScope, options.isCheckDeepInheritance)
|
||||
return runReadAction {
|
||||
private class MySearcher(
|
||||
element: PsiElement, processor: Processor<UsageInfo>, options: FindUsagesOptions
|
||||
) : Searcher(element, processor, options) {
|
||||
|
||||
private val kotlinOptions = options as KotlinClassFindUsagesOptions
|
||||
private val referenceProcessor = KotlinFindUsagesHandler.createReferenceProcessor(processor)
|
||||
|
||||
override fun buildTaskList(): Boolean {
|
||||
val classOrObject = element as KtClassOrObject
|
||||
|
||||
if (kotlinOptions.isUsages || kotlinOptions.searchConstructorUsages) {
|
||||
processClassReferencesLater(classOrObject)
|
||||
}
|
||||
|
||||
if (kotlinOptions.isFieldsUsages || kotlinOptions.isMethodsUsages) {
|
||||
processMemberReferencesLater(classOrObject)
|
||||
}
|
||||
|
||||
if (kotlinOptions.isUsages && classOrObject is KtObjectDeclaration && classOrObject.isCompanion() && classOrObject in options.searchScope ) {
|
||||
if (!processCompanionObjectInternalReferences(classOrObject)) return false
|
||||
}
|
||||
|
||||
if (kotlinOptions.searchConstructorUsages) {
|
||||
classOrObject.toLightClass()?.constructors?.filterIsInstance<KtLightMethod>()?.forEach { constructor ->
|
||||
val scope = constructor.useScope.intersectWith(options.searchScope)
|
||||
val task = constructor.buildProcessDelegationCallConstructorUsagesTask(scope) {
|
||||
it.calleeExpression?.mainReference?.let { referenceProcessor.process(it) } ?: false
|
||||
}
|
||||
addTask(task)
|
||||
}
|
||||
}
|
||||
|
||||
if (kotlinOptions.isDerivedClasses || kotlinOptions.isDerivedInterfaces) {
|
||||
processInheritorsLater()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun processInheritorsLater() {
|
||||
val request = HierarchySearchRequest(element, options.searchScope, kotlinOptions.isCheckDeepInheritance)
|
||||
addTask {
|
||||
request.searchInheritors().forEach(
|
||||
PsiElementProcessorAdapter(
|
||||
object : PsiElementProcessor<PsiClass> {
|
||||
override fun execute(element: PsiClass): Boolean {
|
||||
PsiElementProcessor<PsiClass> { element ->
|
||||
runReadAction {
|
||||
if (!element.isValid) return@runReadAction false
|
||||
val isInterface = element.isInterface
|
||||
return when {
|
||||
isInterface && options.isDerivedInterfaces || !isInterface && options.isDerivedClasses ->
|
||||
when {
|
||||
isInterface && kotlinOptions.isDerivedInterfaces || !isInterface && kotlinOptions.isDerivedClasses ->
|
||||
KotlinFindUsagesHandler.processUsage(processor, element.navigationElement)
|
||||
else -> true
|
||||
}
|
||||
@@ -94,101 +134,49 @@ class KotlinFindClassUsagesHandler(
|
||||
}
|
||||
}
|
||||
|
||||
val classOrObject = element as KtClassOrObject
|
||||
val referenceProcessor = KotlinFindUsagesHandler.createReferenceProcessor(processor)
|
||||
private fun processClassReferencesLater(classOrObject: KtClassOrObject) {
|
||||
val searchParameters = KotlinReferencesSearchParameters(classOrObject,
|
||||
scope = options.searchScope,
|
||||
kotlinOptions = KotlinReferencesSearchOptions(acceptCompanionObjectMembers = true))
|
||||
var usagesQuery = ReferencesSearch.search(searchParameters)
|
||||
|
||||
if (kotlinOptions.isUsages || kotlinOptions.searchConstructorUsages) {
|
||||
if (!processClassReferences(classOrObject, kotlinOptions, referenceProcessor)) return false
|
||||
}
|
||||
|
||||
if (kotlinOptions.isFieldsUsages || kotlinOptions.isMethodsUsages) {
|
||||
if (!processMemberReferences(classOrObject, kotlinOptions, referenceProcessor)) return false
|
||||
}
|
||||
|
||||
if (kotlinOptions.isUsages && classOrObject is KtObjectDeclaration && classOrObject.isCompanion() && classOrObject in options.searchScope) {
|
||||
if (!processCompanionObjectInternalReferences(classOrObject, referenceProcessor)) {
|
||||
return false
|
||||
if (kotlinOptions.isSkipImportStatements) {
|
||||
usagesQuery = FilteredQuery(usagesQuery) { !it.isImportUsage() }
|
||||
}
|
||||
}
|
||||
|
||||
if (kotlinOptions.searchConstructorUsages) {
|
||||
val result = runReadAction {
|
||||
val constructors = classOrObject.toLightClass()?.constructors ?: PsiMethod.EMPTY_ARRAY
|
||||
constructors.filterIsInstance<KtLightMethod>().all { constructor ->
|
||||
constructor.processDelegationCallConstructorUsages(constructor.useScope.intersectWith(options.searchScope)) {
|
||||
it.calleeExpression?.mainReference?.let { referenceProcessor.process(it) } ?: false
|
||||
}
|
||||
}
|
||||
if (!kotlinOptions.searchConstructorUsages) {
|
||||
usagesQuery = FilteredQuery(usagesQuery) { !it.isConstructorUsage(classOrObject) }
|
||||
}
|
||||
if (!result) return false
|
||||
else if (!options.isUsages) {
|
||||
usagesQuery = FilteredQuery(usagesQuery) { it.isConstructorUsage(classOrObject) }
|
||||
}
|
||||
addTask { usagesQuery.forEach(referenceProcessor) }
|
||||
}
|
||||
|
||||
if (options.isDerivedClasses || options.isDerivedInterfaces) {
|
||||
if (!processInheritors()) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun processClassReferences(classOrObject: KtClassOrObject,
|
||||
options: KotlinClassFindUsagesOptions,
|
||||
processor: Processor<PsiReference>): Boolean {
|
||||
val searchParameters = KotlinReferencesSearchParameters(classOrObject,
|
||||
scope = options.searchScope,
|
||||
kotlinOptions = KotlinReferencesSearchOptions(acceptCompanionObjectMembers = true))
|
||||
var usagesQuery = ReferencesSearch.search(searchParameters)
|
||||
|
||||
if (options.isSkipImportStatements) {
|
||||
usagesQuery = FilteredQuery(usagesQuery) { !it.isImportUsage() }
|
||||
}
|
||||
|
||||
if (!options.searchConstructorUsages) {
|
||||
usagesQuery = FilteredQuery(usagesQuery) { !it.isConstructorUsage(classOrObject) }
|
||||
}
|
||||
else if (!options.isUsages) {
|
||||
usagesQuery = FilteredQuery(usagesQuery) { it.isConstructorUsage(classOrObject) }
|
||||
}
|
||||
return usagesQuery.forEach(processor)
|
||||
}
|
||||
|
||||
private fun processCompanionObjectInternalReferences(companionObject: KtObjectDeclaration,
|
||||
processor: Processor<PsiReference>): Boolean {
|
||||
var stop: Boolean = false
|
||||
runReadAction {
|
||||
val klass = companionObject.getStrictParentOfType<KtClass>() ?: return@runReadAction
|
||||
private fun processCompanionObjectInternalReferences(companionObject: KtObjectDeclaration): Boolean {
|
||||
val klass = companionObject.getStrictParentOfType<KtClass>() ?: return true
|
||||
val companionObjectDescriptor = companionObject.descriptor
|
||||
klass.acceptChildren(object : KtVisitorVoid() {
|
||||
override fun visitKtElement(element: KtElement) {
|
||||
if (element == companionObject) return // skip companion object itself
|
||||
if (stop) return
|
||||
element.acceptChildren(this)
|
||||
return !klass.anyDescendantOfType<KtElement>(fun (element: KtElement): Boolean {
|
||||
if (element == companionObject) return false // skip companion object itself
|
||||
|
||||
val bindingContext = element.analyze()
|
||||
val resolvedCall = bindingContext[BindingContext.CALL, element]?.getResolvedCall(bindingContext) ?: return
|
||||
if ((resolvedCall.dispatchReceiver as? ImplicitClassReceiver)?.declarationDescriptor == companionObjectDescriptor
|
||||
|| (resolvedCall.extensionReceiver as? ImplicitClassReceiver)?.declarationDescriptor == companionObjectDescriptor) {
|
||||
element.references.forEach {
|
||||
if (!stop && !processor.process(it)) {
|
||||
stop = true
|
||||
}
|
||||
}
|
||||
}
|
||||
val bindingContext = element.analyze()
|
||||
val resolvedCall = bindingContext[BindingContext.CALL, element]?.getResolvedCall(bindingContext) ?: return false
|
||||
if ((resolvedCall.dispatchReceiver as? ImplicitClassReceiver)?.declarationDescriptor == companionObjectDescriptor
|
||||
|| (resolvedCall.extensionReceiver as? ImplicitClassReceiver)?.declarationDescriptor == companionObjectDescriptor) {
|
||||
return element.references.any { !referenceProcessor.process(it) }
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
return !stop
|
||||
}
|
||||
|
||||
private fun processMemberReferences(classOrObject: KtClassOrObject,
|
||||
options: KotlinClassFindUsagesOptions,
|
||||
processor: Processor<PsiReference>): Boolean {
|
||||
for (decl in classOrObject.effectiveDeclarations()) {
|
||||
if ((decl is KtNamedFunction && options.isMethodsUsages) ||
|
||||
((decl is KtProperty || decl is KtParameter) && options.isFieldsUsages)) {
|
||||
if (!ReferencesSearch.search(decl, options.searchScope).forEach(processor)) return false
|
||||
private fun processMemberReferencesLater(classOrObject: KtClassOrObject) {
|
||||
for (declaration in classOrObject.effectiveDeclarations()) {
|
||||
if ((declaration is KtNamedFunction && kotlinOptions.isMethodsUsages) ||
|
||||
((declaration is KtProperty || declaration is KtParameter) && kotlinOptions.isFieldsUsages)) {
|
||||
addTask { ReferencesSearch.search(declaration, options.searchScope).forEach(referenceProcessor) }
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getStringsToSearch(element: PsiElement): Collection<String> {
|
||||
|
||||
+60
-45
@@ -54,6 +54,7 @@ import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
|
||||
abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration>
|
||||
protected constructor(declaration: T, elementsToSearch: Collection<PsiElement>, factory: KotlinFindUsagesHandlerFactory)
|
||||
@@ -98,7 +99,7 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration>
|
||||
}
|
||||
|
||||
override fun applyQueryFilters(element: PsiElement, options: FindUsagesOptions, query: Query<PsiReference>): Query<PsiReference> {
|
||||
var kotlinOptions = options as KotlinPropertyFindUsagesOptions
|
||||
val kotlinOptions = options as KotlinPropertyFindUsagesOptions
|
||||
|
||||
if (!kotlinOptions.isReadAccess && !kotlinOptions.isWriteAccess) {
|
||||
return EmptyQuery()
|
||||
@@ -127,53 +128,67 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration>
|
||||
}
|
||||
}
|
||||
|
||||
override fun searchReferences(element: PsiElement, processor: Processor<UsageInfo>, options: FindUsagesOptions): Boolean {
|
||||
val kotlinOptions = options as KotlinCallableFindUsagesOptions
|
||||
|
||||
val referenceProcessor = KotlinFindUsagesHandler.createReferenceProcessor(processor)
|
||||
val uniqueProcessor = CommonProcessors.UniqueProcessor(processor)
|
||||
|
||||
if (options.isUsages) {
|
||||
val kotlinSearchOptions = createKotlinReferencesSearchOptions(options)
|
||||
val searchParameters = KotlinReferencesSearchParameters(element, options.searchScope, kotlinOptions = kotlinSearchOptions)
|
||||
|
||||
with(applyQueryFilters(element, options, ReferencesSearch.search(searchParameters))) {
|
||||
if (!forEach(referenceProcessor)) return false
|
||||
}
|
||||
|
||||
for (psiMethod in runReadAction { element.toLightMethods() }) {
|
||||
var searchScope = options.searchScope
|
||||
// TODO: very bad code!! ReferencesSearch does not work correctly for constructors and annotation parameters
|
||||
if (element is KtNamedFunction || (element is KtParameter && element.dataClassComponentFunction() != null)) {
|
||||
searchScope = searchScope.excludeKotlinSources()
|
||||
}
|
||||
with(applyQueryFilters(element, options, MethodReferencesSearch.search(psiMethod, searchScope, true))) {
|
||||
if (!forEach(referenceProcessor)) return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (kotlinOptions.searchOverrides) {
|
||||
for (method in HierarchySearchRequest(element, options.searchScope, true).searchOverriders()) {
|
||||
if (!KotlinFindUsagesHandler.processUsage(uniqueProcessor, method.navigationElement)) break
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
override fun createSearcher(element: PsiElement, processor: Processor<UsageInfo>, options: FindUsagesOptions): Searcher {
|
||||
return MySearcher(element, processor, options)
|
||||
}
|
||||
|
||||
private fun SearchScope.excludeKotlinSources(): SearchScope {
|
||||
if (this is GlobalSearchScope) {
|
||||
val fileTypes = FileTypeManager.getInstance().registeredFileTypes.filter { it != KotlinFileType.INSTANCE }.toTypedArray()
|
||||
return GlobalSearchScope.getScopeRestrictedByFileTypes(this, *fileTypes)
|
||||
private inner class MySearcher(
|
||||
element: PsiElement, processor: Processor<UsageInfo>, options: FindUsagesOptions
|
||||
) : Searcher(element, processor, options) {
|
||||
|
||||
private val kotlinOptions = options as KotlinCallableFindUsagesOptions
|
||||
|
||||
override fun buildTaskList(): Boolean {
|
||||
val referenceProcessor = KotlinFindUsagesHandler.createReferenceProcessor(processor)
|
||||
val uniqueProcessor = CommonProcessors.UniqueProcessor(processor)
|
||||
|
||||
if (options.isUsages) {
|
||||
val kotlinSearchOptions = createKotlinReferencesSearchOptions(options)
|
||||
val searchParameters = KotlinReferencesSearchParameters(element, options.searchScope, kotlinOptions = kotlinSearchOptions)
|
||||
|
||||
applyQueryFilters(element, options, ReferencesSearch.search(searchParameters)).let { query ->
|
||||
addTask { query.forEach(referenceProcessor) }
|
||||
}
|
||||
|
||||
|
||||
for (psiMethod in element.toLightMethods()) {
|
||||
var searchScope = options.searchScope
|
||||
// TODO: very bad code!! ReferencesSearch does not work correctly for constructors and annotation parameters
|
||||
if (element is KtNamedFunction || (element is KtParameter && element.dataClassComponentFunction() != null)) {
|
||||
searchScope = searchScope.excludeKotlinSources()
|
||||
}
|
||||
applyQueryFilters(element, options, MethodReferencesSearch.search(psiMethod, searchScope, true)).let { query ->
|
||||
addTask { query.forEach(referenceProcessor) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (kotlinOptions.searchOverrides) {
|
||||
addTask {
|
||||
val overriders = HierarchySearchRequest(element, options.searchScope, true).searchOverriders()
|
||||
overriders.all {
|
||||
val element = runReadAction { it.check { it.isValid }?.navigationElement } ?: return@all true
|
||||
KotlinFindUsagesHandler.processUsage(uniqueProcessor, element)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
else {
|
||||
this as LocalSearchScope
|
||||
val filteredElements = scope.filter { it.containingFile !is KtFile }
|
||||
return if (filteredElements.isNotEmpty())
|
||||
LocalSearchScope(filteredElements.toTypedArray())
|
||||
else
|
||||
GlobalSearchScope.EMPTY_SCOPE
|
||||
|
||||
private fun SearchScope.excludeKotlinSources(): SearchScope {
|
||||
if (this is GlobalSearchScope) {
|
||||
val fileTypes = FileTypeManager.getInstance().registeredFileTypes.filter { it != KotlinFileType.INSTANCE }.toTypedArray()
|
||||
return GlobalSearchScope.getScopeRestrictedByFileTypes(this, *fileTypes)
|
||||
}
|
||||
else {
|
||||
this as LocalSearchScope
|
||||
val filteredElements = scope.filter { it.containingFile !is KtFile }
|
||||
return if (filteredElements.isNotEmpty())
|
||||
LocalSearchScope(filteredElements.toTypedArray())
|
||||
else
|
||||
GlobalSearchScope.EMPTY_SCOPE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,13 @@ abstract class KotlinFindUsagesHandler<T : PsiElement>(psiElement: T,
|
||||
return searchReferences(element, processor, options) && searchTextOccurrences(element, processor, options)
|
||||
}
|
||||
|
||||
protected abstract fun searchReferences(element: PsiElement, processor: Processor<UsageInfo>, options: FindUsagesOptions): Boolean
|
||||
protected fun searchReferences(element: PsiElement, processor: Processor<UsageInfo>, options: FindUsagesOptions): Boolean {
|
||||
val searcher = createSearcher(element, processor, options)
|
||||
if (!runReadAction { searcher.buildTaskList() }) return false
|
||||
return searcher.executeTasks()
|
||||
}
|
||||
|
||||
protected abstract fun createSearcher(element: PsiElement, processor: Processor<UsageInfo>, options: FindUsagesOptions): Searcher
|
||||
|
||||
override fun findReferencesToHighlight(target: PsiElement, searchScope: SearchScope): Collection<PsiReference> {
|
||||
val results = Collections.synchronizedList(arrayListOf<PsiReference>())
|
||||
@@ -86,6 +92,20 @@ abstract class KotlinFindUsagesHandler<T : PsiElement>(psiElement: T,
|
||||
return results
|
||||
}
|
||||
|
||||
protected abstract class Searcher(val element: PsiElement, val processor: Processor<UsageInfo>, val options: FindUsagesOptions) {
|
||||
private val tasks = ArrayList<() -> Boolean>()
|
||||
|
||||
protected fun addTask(task: () -> Boolean) {
|
||||
tasks.add(task)
|
||||
}
|
||||
|
||||
fun executeTasks(): Boolean {
|
||||
return tasks.all { it() }
|
||||
}
|
||||
|
||||
abstract fun buildTaskList(): Boolean
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LOG = Logger.getInstance(KotlinFindUsagesHandler::class.java)
|
||||
|
||||
|
||||
+9
-2
@@ -39,8 +39,15 @@ class KotlinTypeParameterFindUsagesHandler(
|
||||
)
|
||||
}
|
||||
|
||||
override fun searchReferences(element: PsiElement, processor: Processor<UsageInfo>, options: FindUsagesOptions): Boolean {
|
||||
return ReferencesSearch.search(element, options.searchScope).all { KotlinFindUsagesHandler.processUsage(processor, it ) }
|
||||
override fun createSearcher(element: PsiElement, processor: Processor<UsageInfo>, options: FindUsagesOptions): Searcher {
|
||||
return object: Searcher(element, processor, options) {
|
||||
override fun buildTaskList(): Boolean {
|
||||
addTask {
|
||||
ReferencesSearch.search(element, options.searchScope).all { KotlinFindUsagesHandler.processUsage(processor, it ) }
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFindUsagesOptions(dataContext: DataContext?): FindUsagesOptions {
|
||||
|
||||
+3
-3
@@ -52,7 +52,7 @@ import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
|
||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
|
||||
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.processDelegationCallConstructorUsages
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.buildProcessDelegationCallConstructorUsagesTask
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
|
||||
@@ -311,13 +311,13 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
functionPsi.processDelegationCallConstructorUsages(functionPsi.useScope) {
|
||||
functionPsi.buildProcessDelegationCallConstructorUsagesTask(functionPsi.useScope) {
|
||||
when (it) {
|
||||
is KtConstructorDelegationCall -> result.add(KotlinConstructorDelegationCallUsage(it, changeInfo))
|
||||
is KtSuperTypeCallEntry -> result.add(KotlinFunctionCallUsage(it, functionUsageInfo))
|
||||
}
|
||||
true
|
||||
}
|
||||
}.invoke()
|
||||
}
|
||||
|
||||
private fun processInternalReferences(functionUsageInfo: KotlinCallableDefinitionUsage<*>, visitor: KtTreeVisitor<BindingContext>) {
|
||||
|
||||
+3
-3
@@ -43,7 +43,7 @@ import org.jetbrains.kotlin.idea.refactoring.checkSuperMethods
|
||||
import org.jetbrains.kotlin.idea.refactoring.formatClass
|
||||
import org.jetbrains.kotlin.idea.refactoring.formatFunction
|
||||
import org.jetbrains.kotlin.idea.references.KtReference
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.processDelegationCallConstructorUsages
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.buildProcessDelegationCallConstructorUsagesTask
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
@@ -179,12 +179,12 @@ class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() {
|
||||
else -> return
|
||||
}
|
||||
for (constructor in constructors) {
|
||||
constructor.processDelegationCallConstructorUsages(constructor.useScope) {
|
||||
constructor.buildProcessDelegationCallConstructorUsagesTask(constructor.useScope) {
|
||||
if (!getIgnoranceCondition().value(it)) {
|
||||
usages.add(SafeDeleteReferenceSimpleDeleteUsageInfo(it, element, false))
|
||||
}
|
||||
true
|
||||
}
|
||||
}.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -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.search.usagesSearch.processDelegationCallConstructorUsages
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.buildProcessDelegationCallConstructorUsagesTask
|
||||
|
||||
class KotlinConstructorDelegationCallReferenceSearcher() : QueryExecutorBase<PsiReference, SearchParameters>(true) {
|
||||
override fun processQuery(queryParameters: SearchParameters, consumer: Processor<PsiReference>) {
|
||||
val method = queryParameters.method
|
||||
if (!method.isConstructor) return
|
||||
|
||||
method.processDelegationCallConstructorUsages(method.useScope.intersectWith(queryParameters.effectiveSearchScope)) {
|
||||
method.buildProcessDelegationCallConstructorUsagesTask(method.useScope.intersectWith(queryParameters.effectiveSearchScope)) {
|
||||
it.calleeExpression?.reference?.let { consumer.process(it) } ?: true
|
||||
}
|
||||
}.invoke()
|
||||
}
|
||||
}
|
||||
@@ -388,8 +388,6 @@ abstract class AbstractFindUsagesTest : KotlinLightCodeInsightFixtureTestCase()
|
||||
options: FindUsagesOptions?,
|
||||
highlightingMode: Boolean
|
||||
): Collection<UsageInfo> {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
var options = options
|
||||
val project = project
|
||||
|
||||
val handler: FindUsagesHandler = (if (targetElement is PsiMember) {
|
||||
@@ -402,21 +400,26 @@ abstract class AbstractFindUsagesTest : KotlinLightCodeInsightFixtureTestCase()
|
||||
(FindManager.getInstance(project) as FindManagerImpl).findUsagesManager.getFindUsagesHandler(targetElement, false)
|
||||
}) ?: error("Cannot find handler for: $targetElement")
|
||||
|
||||
if (options == null) {
|
||||
options = handler.getFindUsagesOptions(null)
|
||||
}
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val options = options ?: handler.getFindUsagesOptions(null)
|
||||
|
||||
options.searchScope = GlobalSearchScope.allScope(project)
|
||||
|
||||
val processor = CommonProcessors.CollectProcessor<UsageInfo>()
|
||||
for (psiElement in handler.primaryElements + handler.secondaryElements) {
|
||||
if (highlightingMode) {
|
||||
//TODO: should findReferencesToHighlight work outside read-action or it makes no sense?
|
||||
for (reference in handler.findReferencesToHighlight(psiElement, options.searchScope)) {
|
||||
processor.process(UsageInfo(reference))
|
||||
}
|
||||
}
|
||||
else {
|
||||
handler.processElementUsages(psiElement, processor, options)
|
||||
// run in another thread to test read-action assertions
|
||||
val thread = Thread {
|
||||
handler.processElementUsages(psiElement, processor, options)
|
||||
}
|
||||
thread.start()
|
||||
thread.join()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user