Implemented fast search for binary operators

This commit is contained in:
Valentin Kipyatkov
2016-09-02 14:07:21 +03:00
parent f2c0d131e4
commit 1ca698cfc4
27 changed files with 225 additions and 93 deletions
@@ -37,21 +37,22 @@ import org.jetbrains.kotlin.idea.search.KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT
import org.jetbrains.kotlin.idea.search.allScope import org.jetbrains.kotlin.idea.search.allScope
import org.jetbrains.kotlin.idea.search.effectiveSearchScope import org.jetbrains.kotlin.idea.search.effectiveSearchScope
import org.jetbrains.kotlin.idea.search.unionSafe import org.jetbrains.kotlin.idea.search.unionSafe
import org.jetbrains.kotlin.idea.search.usagesSearch.* import org.jetbrains.kotlin.idea.search.usagesSearch.OperatorReferenceSearcher
import org.jetbrains.kotlin.idea.search.usagesSearch.dataClassComponentFunction
import org.jetbrains.kotlin.idea.search.usagesSearch.getClassNameForCompanionObject
import org.jetbrains.kotlin.idea.search.usagesSearch.getSpecialNamesToSearch
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
import org.jetbrains.kotlin.util.OperatorNameConventions
data class KotlinReferencesSearchOptions(val acceptCallableOverrides: Boolean = false, data class KotlinReferencesSearchOptions(val acceptCallableOverrides: Boolean = false,
val acceptOverloads: Boolean = false, val acceptOverloads: Boolean = false,
val acceptExtensionsOfDeclarationClass: Boolean = false, val acceptExtensionsOfDeclarationClass: Boolean = false,
val acceptCompanionObjectMembers: Boolean = false, val acceptCompanionObjectMembers: Boolean = false,
val searchForComponentConventions: Boolean = true, val searchForComponentConventions: Boolean = true,
val searchInvokeOperator: Boolean = true, val searchForOperatorConventions: Boolean = true,
val searchNamedArguments: Boolean = true) { val searchNamedArguments: Boolean = true) {
fun anyEnabled(): Boolean = acceptCallableOverrides || acceptOverloads || acceptExtensionsOfDeclarationClass fun anyEnabled(): Boolean = acceptCallableOverrides || acceptOverloads || acceptExtensionsOfDeclarationClass
@@ -119,35 +120,31 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
searchLightElements(queryParameters, element, consumer) searchLightElements(queryParameters, element, consumer)
} }
//TODO: operator functions from Java
if (element is KtFunction) {
val referenceSearcher = OperatorReferenceSearcher.createForKtFunction(
element, effectiveSearchScope, consumer, queryParameters.optimizer, kotlinOptions)
referenceSearcher?.run()
}
if (kotlinOptions.searchForComponentConventions) { if (kotlinOptions.searchForComponentConventions) {
when (element) { when (element) {
is KtFunction -> {
if (name != null && isComponentLike(name)) {
DestructuringDeclarationReferenceSearcher(element, effectiveSearchScope, consumer, queryParameters.optimizer).run()
}
}
is KtParameter -> { is KtParameter -> {
val componentFunctionDescriptor = runReadAction { element.dataClassComponentFunction() } val componentFunctionDescriptor = runReadAction { element.dataClassComponentFunction() }
if (componentFunctionDescriptor != null) { if (componentFunctionDescriptor != null) {
val containingClass = element.getStrictParentOfType<KtClassOrObject>()?.toLightClass() val containingClass = element.getStrictParentOfType<KtClassOrObject>()?.toLightClass()
searchDataClassComponentUsages(queryParameters, containingClass, componentFunctionDescriptor, consumer) searchDataClassComponentUsages(queryParameters, containingClass, componentFunctionDescriptor, consumer, kotlinOptions)
} }
} }
is KtLightParameter -> { is KtLightParameter -> {
val componentFunctionDescriptor = runReadAction { element.kotlinOrigin?.dataClassComponentFunction() } val componentFunctionDescriptor = runReadAction { element.kotlinOrigin?.dataClassComponentFunction() }
if (componentFunctionDescriptor != null) { if (componentFunctionDescriptor != null) {
searchDataClassComponentUsages(queryParameters, element.method.containingClass, componentFunctionDescriptor, consumer) searchDataClassComponentUsages(queryParameters, element.method.containingClass, componentFunctionDescriptor, consumer, kotlinOptions)
} }
} }
} }
} }
//TODO: Java invoke's
if (kotlinOptions.searchInvokeOperator && element is KtFunction && name == OperatorNameConventions.INVOKE.asString()) {
InvokeOperatorReferenceSearcher(element, effectiveSearchScope, consumer, queryParameters.optimizer).run()
}
} }
private fun searchNamedArguments(parameter: KtParameter, queryParameters: ReferencesSearch.SearchParameters) { private fun searchNamedArguments(parameter: KtParameter, queryParameters: ReferencesSearch.SearchParameters) {
@@ -242,14 +239,17 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
private fun searchDataClassComponentUsages(queryParameters: ReferencesSearch.SearchParameters, private fun searchDataClassComponentUsages(queryParameters: ReferencesSearch.SearchParameters,
containingClass: PsiClass?, containingClass: PsiClass?,
componentFunctionDescriptor: FunctionDescriptor, componentFunctionDescriptor: FunctionDescriptor,
consumer: Processor<PsiReference> consumer: Processor<PsiReference>,
kotlinOptions: KotlinReferencesSearchOptions
) { ) {
val componentFunction = containingClass?.methods?.find { val componentFunction = containingClass?.methods?.find {
it.name == componentFunctionDescriptor.name.asString() && it.parameterList.parametersCount == 0 it.name == componentFunctionDescriptor.name.asString() && it.parameterList.parametersCount == 0
} }
if (componentFunction != null) { if (componentFunction != null) {
searchNamedElement(queryParameters, componentFunction) searchNamedElement(queryParameters, componentFunction)
DestructuringDeclarationReferenceSearcher.runForPsiMethod(componentFunction, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer) val searcher = OperatorReferenceSearcher.createForPsiMethod(
componentFunction, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer, kotlinOptions)
searcher!!.run()
} }
} }
@@ -0,0 +1,55 @@
/*
* 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.PsiReference
import com.intellij.psi.search.SearchRequestCollector
import com.intellij.psi.search.SearchScope
import com.intellij.util.Processor
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
class BinaryOperatorReferenceSearcher(
targetDeclaration: KtDeclaration,
private val operationTokens: List<KtSingleValueToken>,
searchScope: SearchScope,
consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector
) : OperatorReferenceSearcher<KtBinaryExpression>(targetDeclaration, searchScope, consumer, optimizer, wordsToSearch = operationTokens.map { it.value }) {
override fun processSuspiciousExpression(expression: KtExpression) {
val binaryExpression = expression.parent as? KtBinaryExpression ?: return
if (binaryExpression.operationToken !in operationTokens) return
if (expression != binaryExpression.left) return
processReferenceElement(binaryExpression)
}
override fun isReferenceToCheck(ref: PsiReference): Boolean {
return ref is KtSimpleNameReference && ref.element.getReferencedNameElementType() in operationTokens
}
override fun extractReference(element: PsiElement): PsiReference? {
val binaryExpression = element as? KtBinaryExpression ?: return null
if (binaryExpression.operationToken !in operationTokens) return null
return binaryExpression.operationReference.references.firstIsInstance<KtSimpleNameReference>()
}
}
@@ -17,16 +17,12 @@
package org.jetbrains.kotlin.idea.search.usagesSearch package org.jetbrains.kotlin.idea.search.usagesSearch
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiReference import com.intellij.psi.PsiReference
import com.intellij.psi.search.SearchRequestCollector import com.intellij.psi.search.SearchRequestCollector
import com.intellij.psi.search.SearchScope import com.intellij.psi.search.SearchScope
import com.intellij.util.Processor import com.intellij.util.Processor
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference 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.psi.*
import org.jetbrains.kotlin.resolve.dataClassUtils.getComponentIndex import org.jetbrains.kotlin.resolve.dataClassUtils.getComponentIndex
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
@@ -36,20 +32,7 @@ class DestructuringDeclarationReferenceSearcher(
searchScope: SearchScope, searchScope: SearchScope,
consumer: Processor<PsiReference>, consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector optimizer: SearchRequestCollector
) : OperatorReferenceSearcher<KtDestructuringDeclaration>(targetDeclaration, searchScope, consumer, optimizer, wordToSearch = "(") { ) : OperatorReferenceSearcher<KtDestructuringDeclaration>(targetDeclaration, searchScope, consumer, optimizer, wordsToSearch = listOf("(")) {
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) { private val componentIndex = when (targetDeclaration) {
is KtParameter -> targetDeclaration.dataClassComponentFunction()?.name?.asString()?.let { getComponentIndex(it) } is KtParameter -> targetDeclaration.dataClassComponentFunction()?.name?.asString()?.let { getComponentIndex(it) }
@@ -28,10 +28,8 @@ import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.util.Processor import com.intellij.util.Processor
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
@@ -46,12 +44,10 @@ import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
import org.jetbrains.kotlin.idea.util.FuzzyType import org.jetbrains.kotlin.idea.util.FuzzyType
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.* import java.util.*
//TODO: check if smart search is too expensive //TODO: check if smart search is too expensive
@@ -592,6 +588,8 @@ class ExpressionsOfTypeProcessor(
} }
private fun PsiElement.isOperatorExpensiveToSearch(): Boolean { private fun PsiElement.isOperatorExpensiveToSearch(): Boolean {
return false //TODO
/*
when (this) { when (this) {
is KtFunction -> { is KtFunction -> {
if (name?.startsWith("component") == true || name == OperatorNameConventions.INVOKE.asString()) return false if (name?.startsWith("component") == true || name == OperatorNameConventions.INVOKE.asString()) return false
@@ -607,6 +605,7 @@ class ExpressionsOfTypeProcessor(
return false return false
} }
} }
*/
} }
private fun KotlinType.containsTypeOrDerivedInside(type: FuzzyType): Boolean { private fun KotlinType.containsTypeOrDerivedInside(type: FuzzyType): Boolean {
@@ -25,16 +25,16 @@ import com.intellij.util.Processor
import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.idea.references.KtInvokeFunctionReference import org.jetbrains.kotlin.idea.references.KtInvokeFunctionReference
import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
class InvokeOperatorReferenceSearcher( class InvokeOperatorReferenceSearcher(
targetDeclaration: KtDeclaration, targetDeclaration: KtFunction,
searchScope: SearchScope, searchScope: SearchScope,
consumer: Processor<PsiReference>, consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector optimizer: SearchRequestCollector
) : OperatorReferenceSearcher<KtCallExpression>(targetDeclaration, searchScope, consumer, optimizer, wordToSearch = null) { ) : OperatorReferenceSearcher<KtCallExpression>(targetDeclaration, searchScope, consumer, optimizer, wordsToSearch = emptyList()) {
companion object { companion object {
fun runForPsiMethod( fun runForPsiMethod(
@@ -44,8 +44,8 @@ class InvokeOperatorReferenceSearcher(
optimizer: SearchRequestCollector optimizer: SearchRequestCollector
) { ) {
if (invokeFunction !is KtLightMethod) return //TODO if (invokeFunction !is KtLightMethod) return //TODO
val ktDeclarationTarget = invokeFunction.kotlinOrigin as? KtDeclaration ?: return //TODO? val ktFunction = invokeFunction.kotlinOrigin as? KtFunction ?: return //TODO?
InvokeOperatorReferenceSearcher(ktDeclarationTarget, scope, consumer, optimizer).run() InvokeOperatorReferenceSearcher(ktFunction, scope, consumer, optimizer).run()
} }
} }
@@ -17,29 +17,29 @@
package org.jetbrains.kotlin.idea.search.usagesSearch package org.jetbrains.kotlin.idea.search.usagesSearch
import com.intellij.openapi.roots.ProjectRootManager import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.psi.PsiElement import com.intellij.psi.*
import com.intellij.psi.PsiManager
import com.intellij.psi.PsiRecursiveElementWalkingVisitor
import com.intellij.psi.PsiReference
import com.intellij.psi.search.* import com.intellij.psi.search.*
import com.intellij.util.Processor import com.intellij.util.Processor
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinRequestResultProcessor import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinRequestResultProcessor
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources 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.logPresentation
import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor.Companion.testLog import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor.Companion.testLog
import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType
import org.jetbrains.kotlin.idea.util.toFuzzyType import org.jetbrains.kotlin.idea.util.toFuzzyType
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.util.isValidOperator import org.jetbrains.kotlin.util.isValidOperator
import java.util.* import java.util.*
@@ -48,7 +48,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
private val searchScope: SearchScope, private val searchScope: SearchScope,
private val consumer: Processor<PsiReference>, private val consumer: Processor<PsiReference>,
private val optimizer: SearchRequestCollector, private val optimizer: SearchRequestCollector,
private val wordToSearch: String? private val wordsToSearch: List<String>
) { ) {
private val project = targetDeclaration.project private val project = targetDeclaration.project
@@ -70,6 +70,62 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
} }
companion object { companion object {
fun createForKtFunction(
function: KtFunction,
searchScope: SearchScope,
consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector,
options: KotlinReferencesSearchOptions
): OperatorReferenceSearcher<*>? {
val name = function.name ?: return null
return create(function, name, searchScope, consumer, optimizer, options)
}
fun createForPsiMethod(
psiMethod: PsiMethod,
searchScope: SearchScope,
consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector,
options: KotlinReferencesSearchOptions
): OperatorReferenceSearcher<*>? {
if (psiMethod !is KtLightMethod) return null //TODO?
val ktDeclaration = psiMethod.kotlinOrigin as? KtDeclaration ?: return null //TODO?
return create(ktDeclaration, psiMethod.name, searchScope, consumer, optimizer, options)
}
private fun create(
declaration: KtDeclaration,
functionName: String,
searchScope: SearchScope,
consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector,
options: KotlinReferencesSearchOptions
): OperatorReferenceSearcher<*>? {
if (!Name.isValidIdentifier(functionName)) return null
val name = Name.identifier(functionName)
if (isComponentLike(name)) {
if (!options.searchForComponentConventions) return null
return DestructuringDeclarationReferenceSearcher(declaration, searchScope, consumer, optimizer)
}
if (!options.searchForOperatorConventions) return null
if (declaration !is KtFunction) return null
if (name == OperatorNameConventions.INVOKE) {
return InvokeOperatorReferenceSearcher(declaration, searchScope, consumer, optimizer)
}
val binaryOp = OperatorConventions.BINARY_OPERATION_NAMES.inverse()[name]
if (binaryOp != null) {
val assignmentOp = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.inverse()[binaryOp]
val operationTokens = listOf(binaryOp, assignmentOp).filterNotNull()
return BinaryOperatorReferenceSearcher(declaration, operationTokens, searchScope, consumer, optimizer)
}
return null
}
private object SearchesInProgress : ThreadLocal<HashSet<KtDeclaration>>() { private object SearchesInProgress : ThreadLocal<HashSet<KtDeclaration>>() {
override fun initialValue() = HashSet<KtDeclaration>() override fun initialValue() = HashSet<KtDeclaration>()
} }
@@ -77,9 +133,9 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
open fun run() { open fun run() {
val inProgress = SearchesInProgress.get() val inProgress = SearchesInProgress.get()
try { if (!inProgress.add(targetDeclaration)) return //TODO: it's not quite correct
if (!inProgress.add(targetDeclaration)) return //TODO: it's not quite correct
try {
val usePlainSearch = when (ExpressionsOfTypeProcessor.mode) { val usePlainSearch = when (ExpressionsOfTypeProcessor.mode) {
ExpressionsOfTypeProcessor.Mode.ALWAYS_SMART -> false ExpressionsOfTypeProcessor.Mode.ALWAYS_SMART -> false
ExpressionsOfTypeProcessor.Mode.ALWAYS_PLAIN -> true ExpressionsOfTypeProcessor.Mode.ALWAYS_PLAIN -> true
@@ -131,11 +187,13 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
} }
else { else {
scope as GlobalSearchScope scope as GlobalSearchScope
if (wordToSearch != null) { if (wordsToSearch.isNotEmpty()) {
val unwrappedElement = targetDeclaration.namedUnwrappedElement ?: return val unwrappedElement = targetDeclaration.namedUnwrappedElement ?: return
val resultProcessor = KotlinRequestResultProcessor(unwrappedElement, val resultProcessor = KotlinRequestResultProcessor(unwrappedElement,
filter = { ref -> isReferenceToCheck(ref) }) filter = { ref -> isReferenceToCheck(ref) })
optimizer.searchWord(wordToSearch, scope.restrictToKotlinSources(), UsageSearchContext.IN_CODE, true, unwrappedElement, resultProcessor) wordsToSearch.forEach {
optimizer.searchWord(it, scope.restrictToKotlinSources(), UsageSearchContext.IN_CODE, true, unwrappedElement, resultProcessor)
}
} }
else { else {
val psiManager = PsiManager.getInstance(project) val psiManager = PsiManager.getInstance(project)
@@ -62,11 +62,13 @@ fun Name.getOperationSymbolsToSearch(): Pair<Set<KtToken>, Class<*>?> {
val unaryOp = UNARY_OPERATION_NAMES_WITH_DEPRECATED_INVERTED[this] val unaryOp = UNARY_OPERATION_NAMES_WITH_DEPRECATED_INVERTED[this]
if (unaryOp != null) return setOf(unaryOp) to KtSimpleNameReference::class.java if (unaryOp != null) return setOf(unaryOp) to KtSimpleNameReference::class.java
/*
val binaryOp = BINARY_OPERATION_NAMES.inverse()[this] val binaryOp = BINARY_OPERATION_NAMES.inverse()[this]
if (binaryOp != null) { if (binaryOp != null) {
val assignmentOp = ASSIGNMENT_OPERATION_COUNTERPARTS.inverse()[binaryOp] val assignmentOp = ASSIGNMENT_OPERATION_COUNTERPARTS.inverse()[binaryOp]
return (if (assignmentOp != null) setOf(binaryOp, assignmentOp) else setOf(binaryOp)) to KtSimpleNameReference::class.java return (if (assignmentOp != null) setOf(binaryOp, assignmentOp) else setOf(binaryOp)) to KtSimpleNameReference::class.java
} }
*/
val assignmentOp = ASSIGNMENT_OPERATIONS.inverse()[this] val assignmentOp = ASSIGNMENT_OPERATIONS.inverse()[this]
if (assignmentOp != null) return setOf(assignmentOp) to KtSimpleNameReference::class.java if (assignmentOp != null) return setOf(assignmentOp) to KtSimpleNameReference::class.java
@@ -131,9 +131,9 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration>
val uniqueProcessor = CommonProcessors.UniqueProcessor(processor) val uniqueProcessor = CommonProcessors.UniqueProcessor(processor)
if (options.isUsages) { if (options.isUsages) {
// we disable searchForComponentConventions and searchInvokeOperator for ReferencesSearch because they will be searched by MethodReferencesSearch // we disable searchForComponentConventions and searchForOperatorConventions for ReferencesSearch because they will be searched by MethodReferencesSearch
val kotlinSearchOptions = createKotlinReferencesSearchOptions(options) val kotlinSearchOptions = createKotlinReferencesSearchOptions(options)
.copy(searchForComponentConventions = false, searchInvokeOperator = false) .copy(searchForComponentConventions = false, searchForOperatorConventions = false)
val searchParameters = KotlinReferencesSearchParameters(element, options.searchScope, kotlinOptions = kotlinSearchOptions) val searchParameters = KotlinReferencesSearchParameters(element, options.searchScope, kotlinOptions = kotlinSearchOptions)
with(applyQueryFilters(element, options, ReferencesSearch.search(searchParameters))) { with(applyQueryFilters(element, options, ReferencesSearch.search(searchParameters))) {
@@ -22,14 +22,11 @@ import com.intellij.psi.search.UsageSearchContext
import com.intellij.psi.search.searches.MethodReferencesSearch import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.util.Processor import com.intellij.util.Processor
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
import org.jetbrains.kotlin.idea.search.usagesSearch.DestructuringDeclarationReferenceSearcher import org.jetbrains.kotlin.idea.search.usagesSearch.OperatorReferenceSearcher
import org.jetbrains.kotlin.idea.search.usagesSearch.InvokeOperatorReferenceSearcher
import org.jetbrains.kotlin.idea.search.usagesSearch.getOperationSymbolsToSearch import org.jetbrains.kotlin.idea.search.usagesSearch.getOperationSymbolsToSearch
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.lexer.KtSingleValueToken import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
import org.jetbrains.kotlin.util.OperatorNameConventions
class KotlinConventionMethodReferencesSearcher() : QueryExecutorBase<PsiReference, MethodReferencesSearch.SearchParameters>(true) { class KotlinConventionMethodReferencesSearcher() : QueryExecutorBase<PsiReference, MethodReferencesSearch.SearchParameters>(true) {
override fun processQuery(queryParameters: MethodReferencesSearch.SearchParameters, consumer: Processor<PsiReference>) { override fun processQuery(queryParameters: MethodReferencesSearch.SearchParameters, consumer: Processor<PsiReference>) {
@@ -38,11 +35,10 @@ class KotlinConventionMethodReferencesSearcher() : QueryExecutorBase<PsiReferenc
if (!Name.isValidIdentifier(name)) return if (!Name.isValidIdentifier(name)) return
val identifier = Name.identifier(name) val identifier = Name.identifier(name)
if (isComponentLike(identifier)) { val operatorSearcher = OperatorReferenceSearcher.createForPsiMethod(
DestructuringDeclarationReferenceSearcher.runForPsiMethod(method, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer) method, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer, KotlinReferencesSearchOptions.Empty)
} if (operatorSearcher != null) {
else if (identifier == OperatorNameConventions.INVOKE) { operatorSearcher.run()
InvokeOperatorReferenceSearcher.runForPsiMethod(method, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer)
} }
else { else {
val operationSymbolsToSearch = identifier.getOperationSymbolsToSearch() val operationSymbolsToSearch = identifier.getOperationSymbolsToSearch()
+2 -2
View File
@@ -2,8 +2,8 @@
// OPTIONS: usages // OPTIONS: usages
class A(val n: Int) { class A(val n: Int) {
fun <caret>compareTo(other: A): Int = compareTo(other.n) infix operator fun <caret>compareTo(other: A): Int = compareTo(other.n)
fun compareTo(m: Int): Int = n.compareTo(m) infix operator fun compareTo(m: Int): Int = n.compareTo(m)
} }
fun test() { fun test() {
@@ -1,4 +1,13 @@
Resolved (x, y)
Resolved b1 + b2
Searched references to A Searched references to A
Searched references to B
Searched references to parameter b1 in f() in Kotlin files
Searched references to parameter b2 in f() in Kotlin files
Searched references to parameter other in plus() in Kotlin files
Searched references to plus() in Kotlin files
Used plain search in LocalSearchScope: Used plain search in LocalSearchScope:
CLASS:A CLASS:A
Used plain search in whole search scope Used plain search in LocalSearchScope:
CLASS:B
FUN:plus
+1 -1
View File
@@ -2,7 +2,7 @@
// OPTIONS: usages // OPTIONS: usages
class A(val n: Int) { class A(val n: Int) {
fun <caret>contains(k: Int): Boolean = k <= n infix operator fun <caret>contains(k: Int): Boolean = k <= n
} }
fun test() { fun test() {
+1 -1
View File
@@ -3,7 +3,7 @@
// FIND_BY_REF // FIND_BY_REF
class A(val n: Int) { class A(val n: Int) {
override fun equals(other: Any?): Boolean = other is A && other.n <caret>== n infix override fun equals(other: Any?): Boolean = other is A && other.n <caret>== n
} }
fun test() { fun test() {
@@ -1,4 +1,4 @@
Function call 10 A(0) == A(1) Function call 10 A(0) == A(1)
Function call 11 A(0) != A(1) Function call 11 A(0) != A(1)
Function call 12 A(0) equals A(1) Function call 12 A(0) equals A(1)
Function call 6 override fun equals(other: Any?): Boolean = other is A && other.n == n Function call 6 infix override fun equals(other: Any?): Boolean = other is A && other.n == n
@@ -2,11 +2,11 @@
// OPTIONS: usages // OPTIONS: usages
class A<T: Any> { class A<T: Any> {
public fun <caret>iterator(): Iterator<T> = throw IllegalStateException("") operator fun <caret>iterator(): Iterator<T> = throw IllegalStateException("")
} }
class B<T: Any> { class B<T: Any> {
public fun iterator(): Iterator<T> = throw IllegalStateException("") operator fun iterator(): Iterator<T> = throw IllegalStateException("")
} }
fun test() { fun test() {
+1 -1
View File
@@ -2,7 +2,7 @@
// OPTIONS: usages // OPTIONS: usages
class B(val n: Int) { class B(val n: Int) {
fun <caret>get(i: Int): B = B(i) operator fun <caret>get(i: Int): B = B(i)
} }
fun test() { fun test() {
@@ -4,7 +4,7 @@
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
class Delegate() { class Delegate() {
fun <caret>getValue(thisRef: Any?, property: KProperty<*>): String = ":)" operator fun <caret>getValue(thisRef: Any?, property: KProperty<*>): String = ":)"
} }
val p: String by Delegate() val p: String by Delegate()
+1 -1
View File
@@ -2,7 +2,7 @@
// OPTIONS: usages // OPTIONS: usages
class A(val n: Int) { class A(val n: Int) {
fun <caret>inc(): A = A(n + 1) operator fun <caret>inc(): A = A(n + 1)
} }
fun test() { fun test() {
+2 -2
View File
@@ -2,8 +2,8 @@
// OPTIONS: usages // OPTIONS: usages
class A(val n: Int) { class A(val n: Int) {
fun <caret>plus(m: Int): A = A(n + m) operator fun <caret>plus(m: Int): A = A(n + m)
fun plus(a: A): A = this + a.n operator fun plus(a: A): A = this + a.n
} }
fun test() { fun test() {
+28
View File
@@ -0,0 +1,28 @@
Checked type of a
Checked type of a
Resolved A(0) + A(1)
Resolved A(0) + A(1)
Resolved A(0) + A(1) + 2
Resolved A(0) + A(1) + 2
Resolved A(0) + A(1) + 2
Resolved A(0) + A(1) + 2
Resolved A(0) + A(1) + 2
Resolved A(0) + A(1) + 2
Resolved a += 1
Resolved a += 1
Resolved a += A(1)
Resolved a += A(1)
Searched references to A
Searched references to A
Searched references to A.plus() in Kotlin files
Searched references to A.plus() in Kotlin files
Searched references to A.plus() in Kotlin files
Searched references to A.plus() in Kotlin files
Searched references to a in Kotlin files
Searched references to a in Kotlin files
Searched references to parameter a in A.plus() in Kotlin files
Searched references to parameter a in A.plus() in Kotlin files
Used plain search in LocalSearchScope:
CLASS:A
Used plain search in LocalSearchScope:
CLASS:A
@@ -2,4 +2,4 @@ Function call 10 A(0) + A(1) + 2
Function call 11 A(0) plus A(1) plus 2 Function call 11 A(0) plus A(1) plus 2
Function call 12 A(0).plus(A(1).plus(2)) Function call 12 A(0).plus(A(1).plus(2))
Function call 15 a += 1 Function call 15 a += 1
Function call 6 fun plus(a: A): A = this + a.n Function call 6 operator fun plus(a: A): A = this + a.n
@@ -2,11 +2,11 @@
// OPTIONS: usages // OPTIONS: usages
class A(var n: Int) { class A(var n: Int) {
fun <caret>plusAssign(m: Int) { operator fun <caret>plusAssign(m: Int) {
n += m n += m
} }
fun plusAssign(a: A) { operator fun plusAssign(a: A) {
this += a.n this += a.n
} }
} }
@@ -4,8 +4,9 @@
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
class Delegate() { class Delegate() {
fun getValue(thisRef: Any?, property: KProperty<*>): String = ":)" operator fun getValue(thisRef: Any?, property: KProperty<*>): String = ":)"
fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
} }
fun <caret>propertyDelegated(property: KProperty<*>) { fun <caret>propertyDelegated(property: KProperty<*>) {
@@ -1 +1 @@
Property delegation 15 var p: String by Delegate() Property delegation 16 var p: String by Delegate()
+1 -1
View File
@@ -2,7 +2,7 @@
// OPTIONS: usages // OPTIONS: usages
class B(val n: Int) { class B(val n: Int) {
fun <caret>set(i: Int, a: B) {} operator fun <caret>set(i: Int, a: B) {}
} }
fun test() { fun test() {
@@ -4,8 +4,9 @@
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
class Delegate() { class Delegate() {
fun getValue(thisRef: Any?, property: KProperty<*>): String = ":)" operator fun getValue(thisRef: Any?, property: KProperty<*>): String = ":)"
fun <caret>setValue(thisRef: Any?, property: KProperty<*>, value: String) {
operator fun <caret>setValue(thisRef: Any?, property: KProperty<*>, value: String) {
} }
} }
@@ -1 +1 @@
Property delegation 13 var p: String by Delegate() Property delegation 14 var p: String by Delegate()