Refactored to avoid code duplication
This commit is contained in:
+3
-3
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+96
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-7
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+62
@@ -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>()
|
||||
}
|
||||
}
|
||||
+154
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-147
@@ -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)
|
||||
}
|
||||
-136
@@ -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
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -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()
|
||||
|
||||
+4
-4
@@ -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
-1
@@ -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
-1
@@ -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
-1
@@ -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:
|
||||
|
||||
+4
-4
@@ -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
|
||||
|
||||
+3
-3
@@ -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
-1
@@ -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
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+2
-2
@@ -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
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user