diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.kt index e1aa29b7dda..d1008b333ca 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.kt @@ -123,7 +123,7 @@ class KotlinReferencesSearcher : QueryExecutorBase { if (name != null && isComponentLike(name)) { - findDestructuringDeclarationUsages(element, effectiveSearchScope, consumer, queryParameters.optimizer) + DestructuringDeclarationReferenceSearcher(element, effectiveSearchScope, consumer, queryParameters.optimizer).run() } } @@ -146,7 +146,7 @@ class KotlinReferencesSearcher : QueryExecutorBase, + optimizer: SearchRequestCollector +) : OperatorReferenceSearcher(targetDeclaration, searchScope, consumer, optimizer, wordToSearch = "(") { + + companion object { + fun runForPsiMethod( + componentFunction: PsiMethod, + scope: SearchScope, + consumer: Processor, + optimizer: SearchRequestCollector + ) { + if (componentFunction !is KtLightMethod) return //TODO + val ktDeclarationTarget = componentFunction.kotlinOrigin as? KtDeclaration ?: return //TODO? + DestructuringDeclarationReferenceSearcher(ktDeclarationTarget, scope, consumer, optimizer).run() + } + } + + private val componentIndex = when (targetDeclaration) { + is KtParameter -> targetDeclaration.dataClassComponentFunction()?.name?.asString()?.let { getComponentIndex(it) } + is KtFunction -> targetDeclaration.name?.let { getComponentIndex(it) } + //TODO: java component functions (see KT-13605) + else -> null + } + + override fun run() { + if (componentIndex == null) return + super.run() + } + + override fun extractReference(element: PsiElement): PsiReference? { + val destructuringDeclaration = element as? KtDestructuringDeclaration ?: return null + val entries = destructuringDeclaration.entries + if (entries.size < componentIndex!!) return null + return entries[componentIndex - 1].references.firstIsInstance() + } + + override fun isReferenceToCheck(ref: PsiReference) = ref is KtDestructuringDeclarationReference + + override fun processSuspiciousExpression(expression: KtExpression) { + val parent = expression.parent + val destructuringDeclaration = when (parent) { + is KtDestructuringDeclaration -> parent + + is KtContainerNode -> { + if (parent.node.elementType == KtNodeTypes.LOOP_RANGE) { + (parent.parent as KtForExpression).destructuringParameter + } + else { + null + } + } + + else -> null + } + + if (destructuringDeclaration != null) { + processReferenceElement(destructuringDeclaration) + } + } +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/ExpressionsOfTypeProcessor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/ExpressionsOfTypeProcessor.kt index e7daca40d4b..4c1d1d3e5c9 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/ExpressionsOfTypeProcessor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/ExpressionsOfTypeProcessor.kt @@ -74,16 +74,17 @@ class ExpressionsOfTypeProcessor( var mode = if (ApplicationManager.getApplication().isUnitTestMode) Mode.ALWAYS_SMART else Mode.PLAIN_WHEN_NEEDED var testLog: MutableList? = null - fun logPresentation(declaration: PsiElement): String? { - val fqName = declaration.getKotlinFqName()?.asString() - ?: (declaration as? KtNamedDeclaration)?.name - return when (declaration) { + 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, is KtFunction -> fqName + "()" is KtParameter -> { - val owner = declaration.ownerFunction?.let { logPresentation(it) } ?: declaration.parent.toString() - "parameter ${declaration.name} in $owner" + val owner = element.ownerFunction?.let { logPresentation(it) } ?: element.parent.toString() + "parameter ${element.name} in $owner" } - is KtDestructuringDeclaration -> declaration.entries.joinToString(", ", prefix = "(", postfix = ")") { it.text } + is KtDestructuringDeclaration -> element.entries.joinToString(", ", prefix = "(", postfix = ")") { it.text } else -> fqName } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/InvokeOperatorReferenceSearcher.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/InvokeOperatorReferenceSearcher.kt new file mode 100644 index 00000000000..47c2fb4bb8a --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/InvokeOperatorReferenceSearcher.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.search.usagesSearch + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiReference +import com.intellij.psi.search.SearchRequestCollector +import com.intellij.psi.search.SearchScope +import com.intellij.util.Processor +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.idea.references.KtInvokeFunctionReference +import org.jetbrains.kotlin.psi.KtCallExpression +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance + +class InvokeOperatorReferenceSearcher( + targetDeclaration: KtDeclaration, + searchScope: SearchScope, + consumer: Processor, + optimizer: SearchRequestCollector +) : OperatorReferenceSearcher(targetDeclaration, searchScope, consumer, optimizer, wordToSearch = null) { + + companion object { + fun runForPsiMethod( + invokeFunction: PsiMethod, + scope: SearchScope, + consumer: Processor, + optimizer: SearchRequestCollector + ) { + if (invokeFunction !is KtLightMethod) return //TODO + val ktDeclarationTarget = invokeFunction.kotlinOrigin as? KtDeclaration ?: return //TODO? + InvokeOperatorReferenceSearcher(ktDeclarationTarget, scope, consumer, optimizer).run() + } + } + + override fun processSuspiciousExpression(expression: KtExpression) { + val callExpression = expression.parent as? KtCallExpression ?: return + processReferenceElement(callExpression) + } + + override fun isReferenceToCheck(ref: PsiReference) = ref is KtInvokeFunctionReference + + override fun extractReference(element: PsiElement): PsiReference? { + return (element as? KtCallExpression)?.references?.firstIsInstance() + } +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/OperatorReferenceSearch.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/OperatorReferenceSearch.kt new file mode 100644 index 00000000000..3e37fe55c84 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/OperatorReferenceSearch.kt @@ -0,0 +1,154 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.search.usagesSearch + +import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiRecursiveElementWalkingVisitor +import com.intellij.psi.PsiReference +import com.intellij.psi.search.* +import com.intellij.util.Processor +import org.jetbrains.kotlin.asJava.namedUnwrappedElement +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor +import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinRequestResultProcessor +import org.jetbrains.kotlin.idea.search.restrictToKotlinSources +import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor.Companion.logPresentation +import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor.Companion.testLog +import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType +import org.jetbrains.kotlin.idea.util.toFuzzyType +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension +import org.jetbrains.kotlin.util.isValidOperator +import java.util.* + +abstract class OperatorReferenceSearcher( + private val targetDeclaration: KtDeclaration, + private val searchScope: SearchScope, + private val consumer: Processor, + private val optimizer: SearchRequestCollector, + private val wordToSearch: String? +) { + private val project = targetDeclaration.project + + protected abstract fun processSuspiciousExpression(expression: KtExpression) + + protected abstract fun extractReference(element: PsiElement): PsiReference? + + protected abstract fun isReferenceToCheck(ref: PsiReference): Boolean + + protected fun processReferenceElement(element: TReferenceElement): Boolean { + val reference = extractReference(element) ?: return true + testLog?.add("Resolved ${logPresentation(element)}") + if (reference.isReferenceTo(targetDeclaration)) { + return consumer.process(reference) + } + else { + return true + } + } + + companion object { + private object SearchesInProgress : ThreadLocal>() { + override fun initialValue() = HashSet() + } + } + + open fun run() { + val inProgress = SearchesInProgress.get() + try { + if (!inProgress.add(targetDeclaration)) return //TODO: it's not quite correct + + val usePlainSearch = when (ExpressionsOfTypeProcessor.mode) { + ExpressionsOfTypeProcessor.Mode.ALWAYS_SMART -> false + ExpressionsOfTypeProcessor.Mode.ALWAYS_PLAIN -> true + ExpressionsOfTypeProcessor.Mode.PLAIN_WHEN_NEEDED -> searchScope is LocalSearchScope // for local scope it's faster to use plain search + } + if (usePlainSearch) { + doPlainSearch(searchScope) + return + } + + val descriptor = targetDeclaration.resolveToDescriptor() as? CallableDescriptor ?: return + if (descriptor is FunctionDescriptor && !descriptor.isValidOperator()) return + + val dataType = if (descriptor.isExtension) { + descriptor.fuzzyExtensionReceiverType()!! + } + else { + val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return + classDescriptor.defaultType.toFuzzyType(classDescriptor.typeConstructor.parameters) + } + + ExpressionsOfTypeProcessor( + dataType, + searchScope, + suspiciousExpressionHandler = { expression -> processSuspiciousExpression(expression) }, + suspiciousScopeHandler = { searchScope -> doPlainSearch(searchScope) }, + resolutionFacade = targetDeclaration.getResolutionFacade() + ).run() + } + finally { + inProgress.remove(targetDeclaration) + } + } + + private fun doPlainSearch(scope: SearchScope) { + 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) + } + + super.visitElement(element) + } + }) + } + } + else { + scope as GlobalSearchScope + if (wordToSearch != null) { + val unwrappedElement = targetDeclaration.namedUnwrappedElement ?: return + val resultProcessor = KotlinRequestResultProcessor(unwrappedElement, + filter = { ref -> isReferenceToCheck(ref) }) + optimizer.searchWord(wordToSearch, scope.restrictToKotlinSources(), UsageSearchContext.IN_CODE, true, unwrappedElement, resultProcessor) + } + else { + val psiManager = PsiManager.getInstance(project) + ProjectRootManager.getInstance(project).fileIndex.iterateContent { file -> + if (file in scope) { + val ktFile = psiManager.findFile(file) as? KtFile + if (ktFile != null) { + doPlainSearch(LocalSearchScope(ktFile)) + } + } + true + } + } + } + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/findDestructuringDeclarationUsages.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/findDestructuringDeclarationUsages.kt deleted file mode 100644 index cce1170db90..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/findDestructuringDeclarationUsages.kt +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.idea.search.usagesSearch - -import com.intellij.psi.PsiMethod -import com.intellij.psi.PsiReference -import com.intellij.psi.search.LocalSearchScope -import com.intellij.psi.search.SearchRequestCollector -import com.intellij.psi.search.SearchScope -import com.intellij.psi.search.UsageSearchContext -import com.intellij.util.Processor -import org.jetbrains.kotlin.KtNodeTypes -import org.jetbrains.kotlin.asJava.elements.KtLightMethod -import org.jetbrains.kotlin.asJava.namedUnwrappedElement -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade -import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor -import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference -import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinRequestResultProcessor -import org.jetbrains.kotlin.idea.search.restrictToKotlinSources -import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor.Companion.logPresentation -import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor.Companion.testLog -import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType -import org.jetbrains.kotlin.idea.util.toFuzzyType -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.resolve.dataClassUtils.getComponentIndex -import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension -import org.jetbrains.kotlin.util.isValidOperator -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance -import java.util.* - -private object DestructuringDeclarationSearchesInProgress : ThreadLocal>() { - override fun initialValue() = HashSet() -} - -fun findDestructuringDeclarationUsages( - componentFunction: PsiMethod, - scope: SearchScope, - consumer: Processor, - optimizer: SearchRequestCollector -) { - if (componentFunction !is KtLightMethod) return //TODO - val ktDeclarationTarget = componentFunction.kotlinOrigin as? KtDeclaration ?: return //TODO? - findDestructuringDeclarationUsages(ktDeclarationTarget, scope, consumer, optimizer) -} - -fun findDestructuringDeclarationUsages( - targetDeclaration: KtDeclaration, - searchScope: SearchScope, - consumer: Processor, - optimizer: SearchRequestCollector -) { - val inProgress = DestructuringDeclarationSearchesInProgress.get() - try { - if (!inProgress.add(targetDeclaration)) return - - val usePlainSearch = when (ExpressionsOfTypeProcessor.mode) { - ExpressionsOfTypeProcessor.Mode.ALWAYS_SMART -> false - ExpressionsOfTypeProcessor.Mode.ALWAYS_PLAIN -> true - ExpressionsOfTypeProcessor.Mode.PLAIN_WHEN_NEEDED -> searchScope is LocalSearchScope // for local scope it's faster to use plain search - } - if (usePlainSearch) { - doPlainSearch(targetDeclaration, searchScope, optimizer) - return - } - - val descriptor = targetDeclaration.resolveToDescriptor() as? CallableDescriptor ?: return - - if (descriptor is FunctionDescriptor && !descriptor.isValidOperator()) return - - val dataType = if (descriptor.isExtension) { - descriptor.fuzzyExtensionReceiverType()!! - } - else { - val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return - classDescriptor.defaultType.toFuzzyType(classDescriptor.typeConstructor.parameters) - } - - val componentIndex = when (targetDeclaration) { - is KtParameter -> targetDeclaration.dataClassComponentFunction()?.name?.asString()?.let { getComponentIndex(it) } - is KtFunction -> targetDeclaration.name?.let { getComponentIndex(it) } - //TODO: java component functions (see KT-13605) - else -> null - } ?: return - - ExpressionsOfTypeProcessor( - dataType, - searchScope, - suspiciousExpressionHandler = { expression -> processSuspiciousExpression(expression, targetDeclaration, componentIndex, consumer) }, - suspiciousScopeHandler = { searchScope -> doPlainSearch(targetDeclaration, searchScope, optimizer) }, - resolutionFacade = targetDeclaration.getResolutionFacade() - ).run() - } - finally { - inProgress.remove(targetDeclaration) - } -} - -private fun processSuspiciousExpression(expression: KtExpression, targetDeclaration: KtDeclaration, componentIndex: Int, consumer: Processor) { - val parent = expression.parent - val destructuringDeclaration = when (parent) { - is KtDestructuringDeclaration -> parent - - is KtContainerNode -> { - if (parent.node.elementType == KtNodeTypes.LOOP_RANGE) { - (parent.parent as KtForExpression).destructuringParameter - } - else { - null - } - } - - else -> null - } - - if (destructuringDeclaration != null && componentIndex <= destructuringDeclaration.entries.size) { - testLog?.add("Checked type of ${logPresentation(destructuringDeclaration)}") - - val declarationReference = destructuringDeclaration.entries[componentIndex - 1].references.firstIsInstance() - if (declarationReference.isReferenceTo(targetDeclaration)) { - consumer.process(declarationReference) - } - } -} - -private fun doPlainSearch(ktDeclaration: KtDeclaration, scope: SearchScope, optimizer: SearchRequestCollector) { - val unwrappedElement = ktDeclaration.namedUnwrappedElement ?: return - val resultProcessor = KotlinRequestResultProcessor(unwrappedElement, - filter = { ref -> ref is KtDestructuringDeclarationReference }) - optimizer.searchWord("(", scope.restrictToKotlinSources(), UsageSearchContext.IN_CODE, true, unwrappedElement, resultProcessor) -} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/findInvokeOperatorUsages.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/findInvokeOperatorUsages.kt deleted file mode 100644 index 870ad829fd8..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/findInvokeOperatorUsages.kt +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.idea.search.usagesSearch - -import com.intellij.openapi.roots.ProjectRootManager -import com.intellij.psi.PsiManager -import com.intellij.psi.PsiMethod -import com.intellij.psi.PsiReference -import com.intellij.psi.search.GlobalSearchScope -import com.intellij.psi.search.LocalSearchScope -import com.intellij.psi.search.SearchScope -import com.intellij.util.Processor -import org.jetbrains.kotlin.asJava.elements.KtLightMethod -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade -import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor -import org.jetbrains.kotlin.idea.references.KtInvokeFunctionReference -import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor.Companion.testLog -import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType -import org.jetbrains.kotlin.idea.util.toFuzzyType -import org.jetbrains.kotlin.psi.KtCallExpression -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType -import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension -import org.jetbrains.kotlin.util.isValidOperator -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance - -//TODO: problem with infinite recursion not solved - -//TODO: code duplication - -fun findInvokeOperatorUsages( - invokeFunction: PsiMethod, - scope: SearchScope, - consumer: Processor -) { - if (invokeFunction !is KtLightMethod) return //TODO - val ktDeclarationTarget = invokeFunction.kotlinOrigin as? KtDeclaration ?: return //TODO? - findInvokeOperatorUsages(ktDeclarationTarget, scope, consumer) -} - -fun findInvokeOperatorUsages( - targetDeclaration: KtDeclaration, - searchScope: SearchScope, - consumer: Processor -) { - val usePlainSearch = when (ExpressionsOfTypeProcessor.mode) { - ExpressionsOfTypeProcessor.Mode.ALWAYS_SMART -> false - ExpressionsOfTypeProcessor.Mode.ALWAYS_PLAIN -> true - ExpressionsOfTypeProcessor.Mode.PLAIN_WHEN_NEEDED -> searchScope is LocalSearchScope // for local scope it's faster to use plain search - } - if (usePlainSearch) { - doPlainSearch(targetDeclaration, searchScope, consumer) - return - } - - val descriptor = targetDeclaration.resolveToDescriptor() as? CallableDescriptor ?: return - - if (descriptor is FunctionDescriptor && !descriptor.isValidOperator()) return - - val dataType = if (descriptor.isExtension) { - descriptor.fuzzyExtensionReceiverType()!! - } - else { - val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return - classDescriptor.defaultType.toFuzzyType(classDescriptor.typeConstructor.parameters) - } - - ExpressionsOfTypeProcessor( - dataType, - searchScope, - suspiciousExpressionHandler = { expression -> processSuspiciousExpression(expression, targetDeclaration, consumer) }, - suspiciousScopeHandler = { searchScope -> doPlainSearch(targetDeclaration, searchScope, consumer) }, - resolutionFacade = targetDeclaration.getResolutionFacade() - ).run() -} - -private fun processSuspiciousExpression(expression: KtExpression, targetDeclaration: KtDeclaration, consumer: Processor) { - val callExpression = expression.parent as? KtCallExpression ?: return - testLog?.add("Resolving call ${callExpression.text}") - processCallExpression(callExpression, targetDeclaration, consumer) -} - -private fun doPlainSearch(ktDeclaration: KtDeclaration, scope: SearchScope, consumer: Processor) { - if (scope is LocalSearchScope) { - for (element in scope.scope) { - val stop = element.anyDescendantOfType { !processCallExpression(it, ktDeclaration, consumer) } - if (stop) break - } - } - else { - scope as GlobalSearchScope - val project = ktDeclaration.project - val psiManager = PsiManager.getInstance(project) - ProjectRootManager.getInstance(project).fileIndex.iterateContent { file -> - if (file in scope) { - val ktFile = psiManager.findFile(file) as? KtFile - if (ktFile != null) { - val stop = ktFile.anyDescendantOfType { - !processCallExpression(it, ktDeclaration, consumer) - } - if (stop) return@iterateContent false - } - } - true - } - } -} - -private fun processCallExpression(callExpression: KtCallExpression, targetDeclaration: KtDeclaration, consumer: Processor): Boolean { - val reference = callExpression.references.firstIsInstance() - if (reference.isReferenceTo(targetDeclaration)) { - return consumer.process(reference) - } - else { - return true - } -} diff --git a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinConventionMethodReferencesSearcher.kt b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinConventionMethodReferencesSearcher.kt index 61fd25b0a94..4b7b53f0308 100644 --- a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinConventionMethodReferencesSearcher.kt +++ b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinConventionMethodReferencesSearcher.kt @@ -22,8 +22,8 @@ import com.intellij.psi.search.UsageSearchContext import com.intellij.psi.search.searches.MethodReferencesSearch import com.intellij.util.Processor import org.jetbrains.kotlin.idea.search.restrictToKotlinSources -import org.jetbrains.kotlin.idea.search.usagesSearch.findDestructuringDeclarationUsages -import org.jetbrains.kotlin.idea.search.usagesSearch.findInvokeOperatorUsages +import org.jetbrains.kotlin.idea.search.usagesSearch.DestructuringDeclarationReferenceSearcher +import org.jetbrains.kotlin.idea.search.usagesSearch.InvokeOperatorReferenceSearcher import org.jetbrains.kotlin.idea.search.usagesSearch.getOperationSymbolsToSearch import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.lexer.KtSingleValueToken @@ -39,10 +39,10 @@ class KotlinConventionMethodReferencesSearcher() : QueryExecutorBase