Refactored to avoid code duplication

This commit is contained in:
Valentin Kipyatkov
2016-09-01 01:29:27 +03:00
parent e3b37f9219
commit f2c0d131e4
22 changed files with 365 additions and 335 deletions
@@ -123,7 +123,7 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
when (element) {
is KtFunction -> {
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<PsiReference, ReferencesSearc
//TODO: Java invoke's
if (kotlinOptions.searchInvokeOperator && element is KtFunction && name == OperatorNameConventions.INVOKE.asString()) {
findInvokeOperatorUsages(element, effectiveSearchScope, consumer)
InvokeOperatorReferenceSearcher(element, effectiveSearchScope, consumer, queryParameters.optimizer).run()
}
}
@@ -249,7 +249,7 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
}
if (componentFunction != null) {
searchNamedElement(queryParameters, componentFunction)
findDestructuringDeclarationUsages(componentFunction, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer)
DestructuringDeclarationReferenceSearcher.runForPsiMethod(componentFunction, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer)
}
}
@@ -0,0 +1,96 @@
/*
* 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.KtNodeTypes
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor.Companion.logPresentation
import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor.Companion.testLog
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.dataClassUtils.getComponentIndex
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
class DestructuringDeclarationReferenceSearcher(
targetDeclaration: KtDeclaration,
searchScope: SearchScope,
consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector
) : OperatorReferenceSearcher<KtDestructuringDeclaration>(targetDeclaration, searchScope, consumer, optimizer, wordToSearch = "(") {
companion object {
fun runForPsiMethod(
componentFunction: PsiMethod,
scope: SearchScope,
consumer: Processor<PsiReference>,
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<KtDestructuringDeclarationReference>()
}
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)
}
}
}
@@ -74,16 +74,17 @@ class ExpressionsOfTypeProcessor(
var mode = if (ApplicationManager.getApplication().isUnitTestMode) Mode.ALWAYS_SMART else Mode.PLAIN_WHEN_NEEDED
var testLog: MutableList<String>? = 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
}
}
@@ -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<PsiReference>,
optimizer: SearchRequestCollector
) : OperatorReferenceSearcher<KtCallExpression>(targetDeclaration, searchScope, consumer, optimizer, wordToSearch = null) {
companion object {
fun runForPsiMethod(
invokeFunction: PsiMethod,
scope: SearchScope,
consumer: Processor<PsiReference>,
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<KtInvokeFunctionReference>()
}
}
@@ -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<TReferenceElement : KtElement>(
private val targetDeclaration: KtDeclaration,
private val searchScope: SearchScope,
private val consumer: Processor<PsiReference>,
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<HashSet<KtDeclaration>>() {
override fun initialValue() = HashSet<KtDeclaration>()
}
}
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
}
}
}
}
}
@@ -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<HashSet<KtDeclaration>>() {
override fun initialValue() = HashSet<KtDeclaration>()
}
fun findDestructuringDeclarationUsages(
componentFunction: PsiMethod,
scope: SearchScope,
consumer: Processor<PsiReference>,
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<PsiReference>,
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<PsiReference>) {
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<KtDestructuringDeclarationReference>()
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)
}
@@ -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<PsiReference>
) {
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<PsiReference>
) {
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<PsiReference>) {
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<PsiReference>) {
if (scope is LocalSearchScope) {
for (element in scope.scope) {
val stop = element.anyDescendantOfType<KtCallExpression> { !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<KtCallExpression> {
!processCallExpression(it, ktDeclaration, consumer)
}
if (stop) return@iterateContent false
}
}
true
}
}
}
private fun processCallExpression(callExpression: KtCallExpression, targetDeclaration: KtDeclaration, consumer: Processor<PsiReference>): Boolean {
val reference = callExpression.references.firstIsInstance<KtInvokeFunctionReference>()
if (reference.isReferenceTo(targetDeclaration)) {
return consumer.process(reference)
}
else {
return true
}
}
@@ -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<PsiReferenc
val identifier = Name.identifier(name)
if (isComponentLike(identifier)) {
findDestructuringDeclarationUsages(method, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer)
DestructuringDeclarationReferenceSearcher.runForPsiMethod(method, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer)
}
else if (identifier == OperatorNameConventions.INVOKE) {
findInvokeOperatorUsages(method, queryParameters.effectiveSearchScope, consumer)
InvokeOperatorReferenceSearcher.runForPsiMethod(method, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer)
}
else {
val operationSymbolsToSearch = identifier.getOperationSymbolsToSearch()
@@ -1,11 +1,11 @@
Checked type of (a1, b1)
Checked type of (a2, b2)
Checked type of (a3, b3)
Checked type of (a4, b4)
Checked type of X.f2()
Checked type of constructor
Checked type of fun2
Checked type of fun3
Resolved (a1, b1)
Resolved (a2, b2)
Resolved (a3, b3)
Resolved (a4, b4)
Searched references to A
Searched references to X.f2() in Kotlin files
Searched references to constructor in Kotlin files
@@ -1,5 +1,5 @@
Checked type of (x, y)
Checked type of f()
Resolved (x, y)
Searched references to X
Searched references to f() in Kotlin files
Used plain search in LocalSearchScope:
@@ -1,6 +1,6 @@
Checked type of (x1, y1)
Checked type of f()
Checked type of g()
Resolved (x1, y1)
Searched references to X
Searched references to f() in Kotlin files
Used plain search in LocalSearchScope:
@@ -1,16 +1,16 @@
Checked type of (x, y, z)
Checked type of (x1, y1)
Checked type of (x1, y1, z1)
Checked type of (x2, y2)
Checked type of (x2, y2, z2)
Checked type of (x3, y3, z3)
Checked type of (x4, y4, z4)
Checked type of (x5, y5, z5)
Checked type of a
Checked type of g()
Checked type of h()
Checked type of listOfA()
Checked type of listOfA()
Resolved (x, y, z)
Resolved (x1, y1)
Resolved (x1, y1, z1)
Resolved (x2, y2)
Resolved (x2, y2, z2)
Resolved (x3, y3, z3)
Resolved (x4, y4, z4)
Resolved (x5, y5, z5)
Searched references to JavaClass.getA() in Kotlin files
Searched references to JavaClass2
Searched references to JavaClass3
@@ -1,5 +1,5 @@
Checked type of (x, y, z)
Checked type of a
Resolved (x, y, z)
Searched references to A
Searched references to a in Kotlin files
Used plain search in LocalSearchScope:
@@ -1,7 +1,7 @@
Checked type of (a, n)
Checked type of (a1, n1)
Checked type of (x, y, z)
Checked type of (x1, y1, z1)
Resolved (a, n)
Resolved (a1, n1)
Resolved (x, y, z)
Resolved (x1, y1, z1)
Searched references to A
Searched references to B
Searched references to C
@@ -1,7 +1,7 @@
Checked type of (x, y)
Checked type of (x1, y1)
Checked type of (x2, y2)
Checked type of f()
Resolved (x, y)
Resolved (x1, y1)
Resolved (x2, y2)
Searched references to X
Searched references to Y
Searched references to Z1
@@ -1,6 +1,6 @@
Checked type of (x, y)
Checked type of (x, y, z)
Checked type of parameter a in FOR
Resolved (x, y)
Resolved (x, y, z)
Searched references to A
Searched references to parameter a in FOR in Kotlin files
Used plain search in LocalSearchScope:
@@ -1,6 +1,6 @@
Checked type of (x, y)
Checked type of (x1, y1)
Checked type of list
Resolved (x, y)
Resolved (x1, y1)
Searched references to A
Searched references to list in Kotlin files
Used plain search in LocalSearchScope:
@@ -1,5 +1,5 @@
Checked type of (x1, y1)
Checked type of y1()
Resolved (x1, y1)
Searched references to A
Searched references to parameter a in condition() in Kotlin files
Searched references to parameter a in x() in Kotlin files
@@ -1,9 +1,9 @@
Checked type of (x, y)
Checked type of (x1, y1)
Checked type of (x2, y2)
Checked type of f()
Checked type of g()
Checked type of h()
Resolved (x, y)
Resolved (x1, y1)
Resolved (x2, y2)
Searched references to X
Searched references to Y
Searched references to Z
@@ -1,6 +1,6 @@
Checked type of (a1, n1)
Checked type of (a2, n2)
Checked type of (a2, n2)
Resolved (a1, n1)
Resolved (a2, n2)
Resolved (a2, n2)
Searched references to A
Searched references to parameter a in A() in Kotlin files
Searched references to parameter a in f() in Kotlin files
@@ -1,5 +1,5 @@
Checked type of (a1, s)
Checked type of (b, n)
Resolved (a1, s)
Resolved (b, n)
Searched references to A
Searched references to B
Searched references to a1 in Kotlin files
+3 -3
View File
@@ -1,7 +1,7 @@
Checked type of f()
Resolving call f(1)
Resolving call f(2)
Resolving call f(2)(2)
Resolved f(1)
Resolved f(2)
Resolved f(2)(2)
Searched references to B
Searched references to f() in Kotlin files
Used plain search in LocalSearchScope: