From 1ca698cfc435aa3df4dc02838a61c1ba58df3076 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 2 Sep 2016 14:07:21 +0300 Subject: [PATCH] Implemented fast search for binary operators --- .../KotlinReferencesSearcher.kt | 38 ++++----- .../BinaryOperatorReferenceSearcher.kt | 55 ++++++++++++ ...structuringDeclarationReferenceSearcher.kt | 19 +---- .../ExpressionsOfTypeProcessor.kt | 7 +- .../InvokeOperatorReferenceSearcher.kt | 10 +-- .../usagesSearch/OperatorReferenceSearch.kt | 84 ++++++++++++++++--- .../idea/search/usagesSearch/conventions.kt | 2 + .../handlers/KotlinFindMemberUsagesHandler.kt | 4 +- ...otlinConventionMethodReferencesSearcher.kt | 14 ++-- .../kotlin/conventions/compareTo.0.kt | 4 +- .../conventions/components/operators.log | 11 ++- .../kotlin/conventions/contains.0.kt | 2 +- .../findUsages/kotlin/conventions/equals.0.kt | 2 +- .../kotlin/conventions/equals.results.txt | 2 +- .../kotlin/conventions/forIteration.0.kt | 4 +- .../findUsages/kotlin/conventions/get.0.kt | 2 +- .../conventions/getAsPropertyDelegate.0.kt | 2 +- .../findUsages/kotlin/conventions/inc.0.kt | 2 +- .../findUsages/kotlin/conventions/plus.0.kt | 4 +- .../findUsages/kotlin/conventions/plus.log | 28 +++++++ .../kotlin/conventions/plus.results.txt | 2 +- .../kotlin/conventions/plusAssign.0.kt | 4 +- .../propertyDelegatedFunction.0.kt | 5 +- .../propertyDelegatedFunction.results.txt | 2 +- .../findUsages/kotlin/conventions/set.0.kt | 2 +- .../conventions/setAsPropertyDelegate.0.kt | 5 +- .../setAsPropertyDelegate.results.txt | 2 +- 27 files changed, 225 insertions(+), 93 deletions(-) create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/BinaryOperatorReferenceSearcher.kt create mode 100644 idea/testData/findUsages/kotlin/conventions/plus.log diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.kt index d1008b333ca..796723e7ec3 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReferencesSearcher.kt @@ -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.effectiveSearchScope 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.util.application.runReadAction import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.parents -import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike -import org.jetbrains.kotlin.util.OperatorNameConventions data class KotlinReferencesSearchOptions(val acceptCallableOverrides: Boolean = false, val acceptOverloads: Boolean = false, val acceptExtensionsOfDeclarationClass: Boolean = false, val acceptCompanionObjectMembers: Boolean = false, val searchForComponentConventions: Boolean = true, - val searchInvokeOperator: Boolean = true, + val searchForOperatorConventions: Boolean = true, val searchNamedArguments: Boolean = true) { fun anyEnabled(): Boolean = acceptCallableOverrides || acceptOverloads || acceptExtensionsOfDeclarationClass @@ -119,35 +120,31 @@ class KotlinReferencesSearcher : QueryExecutorBase { - if (name != null && isComponentLike(name)) { - DestructuringDeclarationReferenceSearcher(element, effectiveSearchScope, consumer, queryParameters.optimizer).run() - } - } - is KtParameter -> { val componentFunctionDescriptor = runReadAction { element.dataClassComponentFunction() } if (componentFunctionDescriptor != null) { val containingClass = element.getStrictParentOfType()?.toLightClass() - searchDataClassComponentUsages(queryParameters, containingClass, componentFunctionDescriptor, consumer) + searchDataClassComponentUsages(queryParameters, containingClass, componentFunctionDescriptor, consumer, kotlinOptions) } } is KtLightParameter -> { val componentFunctionDescriptor = runReadAction { element.kotlinOrigin?.dataClassComponentFunction() } 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) { @@ -242,14 +239,17 @@ class KotlinReferencesSearcher : QueryExecutorBase + consumer: Processor, + kotlinOptions: KotlinReferencesSearchOptions ) { val componentFunction = containingClass?.methods?.find { it.name == componentFunctionDescriptor.name.asString() && it.parameterList.parametersCount == 0 } if (componentFunction != null) { searchNamedElement(queryParameters, componentFunction) - DestructuringDeclarationReferenceSearcher.runForPsiMethod(componentFunction, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer) + val searcher = OperatorReferenceSearcher.createForPsiMethod( + componentFunction, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer, kotlinOptions) + searcher!!.run() } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/BinaryOperatorReferenceSearcher.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/BinaryOperatorReferenceSearcher.kt new file mode 100644 index 00000000000..291bbff553c --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/BinaryOperatorReferenceSearcher.kt @@ -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, + searchScope: SearchScope, + consumer: Processor, + optimizer: SearchRequestCollector +) : OperatorReferenceSearcher(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() + } +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/DestructuringDeclarationReferenceSearcher.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/DestructuringDeclarationReferenceSearcher.kt index 6f129919f10..a6d6e7aa96d 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/DestructuringDeclarationReferenceSearcher.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/DestructuringDeclarationReferenceSearcher.kt @@ -17,16 +17,12 @@ 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 @@ -36,20 +32,7 @@ class DestructuringDeclarationReferenceSearcher( searchScope: SearchScope, consumer: Processor, optimizer: SearchRequestCollector -) : OperatorReferenceSearcher(targetDeclaration, searchScope, consumer, optimizer, wordToSearch = "(") { - - companion object { - fun runForPsiMethod( - componentFunction: PsiMethod, - scope: SearchScope, - consumer: Processor, - optimizer: SearchRequestCollector - ) { - if (componentFunction !is KtLightMethod) return //TODO - val ktDeclarationTarget = componentFunction.kotlinOrigin as? KtDeclaration ?: return //TODO? - DestructuringDeclarationReferenceSearcher(ktDeclarationTarget, scope, consumer, optimizer).run() - } - } +) : OperatorReferenceSearcher(targetDeclaration, searchScope, consumer, optimizer, wordsToSearch = listOf("(")) { private val componentIndex = when (targetDeclaration) { is KtParameter -> targetDeclaration.dataClassComponentFunction()?.name?.asString()?.let { getComponentIndex(it) } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/ExpressionsOfTypeProcessor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/ExpressionsOfTypeProcessor.kt index 4c1d1d3e5c9..bf6a18a8e6f 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/ExpressionsOfTypeProcessor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/ExpressionsOfTypeProcessor.kt @@ -28,10 +28,8 @@ import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.util.Processor import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.asJava.classes.KtLightClass -import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.diagnostics.DiagnosticUtils import org.jetbrains.kotlin.idea.KotlinLanguage 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.ProjectRootsUtil 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.psi.* import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.util.OperatorNameConventions import java.util.* //TODO: check if smart search is too expensive @@ -592,6 +588,8 @@ class ExpressionsOfTypeProcessor( } private fun PsiElement.isOperatorExpensiveToSearch(): Boolean { + return false //TODO +/* when (this) { is KtFunction -> { if (name?.startsWith("component") == true || name == OperatorNameConventions.INVOKE.asString()) return false @@ -607,6 +605,7 @@ class ExpressionsOfTypeProcessor( return false } } +*/ } private fun KotlinType.containsTypeOrDerivedInside(type: FuzzyType): Boolean { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/InvokeOperatorReferenceSearcher.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/InvokeOperatorReferenceSearcher.kt index 47c2fb4bb8a..062e2c4f32c 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/InvokeOperatorReferenceSearcher.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/InvokeOperatorReferenceSearcher.kt @@ -25,16 +25,16 @@ 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.psi.KtFunction import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance class InvokeOperatorReferenceSearcher( - targetDeclaration: KtDeclaration, + targetDeclaration: KtFunction, searchScope: SearchScope, consumer: Processor, optimizer: SearchRequestCollector -) : OperatorReferenceSearcher(targetDeclaration, searchScope, consumer, optimizer, wordToSearch = null) { +) : OperatorReferenceSearcher(targetDeclaration, searchScope, consumer, optimizer, wordsToSearch = emptyList()) { companion object { fun runForPsiMethod( @@ -44,8 +44,8 @@ class InvokeOperatorReferenceSearcher( optimizer: SearchRequestCollector ) { if (invokeFunction !is KtLightMethod) return //TODO - val ktDeclarationTarget = invokeFunction.kotlinOrigin as? KtDeclaration ?: return //TODO? - InvokeOperatorReferenceSearcher(ktDeclarationTarget, scope, consumer, optimizer).run() + val ktFunction = invokeFunction.kotlinOrigin as? KtFunction ?: return //TODO? + InvokeOperatorReferenceSearcher(ktFunction, scope, consumer, optimizer).run() } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/OperatorReferenceSearch.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/OperatorReferenceSearch.kt index 3e37fe55c84..d48522d1782 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/OperatorReferenceSearch.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/OperatorReferenceSearch.kt @@ -17,29 +17,29 @@ 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.* import com.intellij.psi.search.* import com.intellij.util.Processor +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.search.ideaExtensions.KotlinReferencesSearchOptions 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.name.Name +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike 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 java.util.* @@ -48,7 +48,7 @@ abstract class OperatorReferenceSearcher( private val searchScope: SearchScope, private val consumer: Processor, private val optimizer: SearchRequestCollector, - private val wordToSearch: String? + private val wordsToSearch: List ) { private val project = targetDeclaration.project @@ -70,6 +70,62 @@ abstract class OperatorReferenceSearcher( } companion object { + fun createForKtFunction( + function: KtFunction, + searchScope: SearchScope, + consumer: Processor, + 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, + 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, + 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>() { override fun initialValue() = HashSet() } @@ -77,9 +133,9 @@ abstract class OperatorReferenceSearcher( open fun run() { 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) { ExpressionsOfTypeProcessor.Mode.ALWAYS_SMART -> false ExpressionsOfTypeProcessor.Mode.ALWAYS_PLAIN -> true @@ -131,11 +187,13 @@ abstract class OperatorReferenceSearcher( } else { scope as GlobalSearchScope - if (wordToSearch != null) { + if (wordsToSearch.isNotEmpty()) { val unwrappedElement = targetDeclaration.namedUnwrappedElement ?: return val resultProcessor = KotlinRequestResultProcessor(unwrappedElement, 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 { val psiManager = PsiManager.getInstance(project) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/conventions.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/conventions.kt index cc2d48d9708..38b5afbab56 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/conventions.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/conventions.kt @@ -62,11 +62,13 @@ fun Name.getOperationSymbolsToSearch(): Pair, Class<*>?> { val unaryOp = UNARY_OPERATION_NAMES_WITH_DEPRECATED_INVERTED[this] if (unaryOp != null) return setOf(unaryOp) to KtSimpleNameReference::class.java +/* val binaryOp = BINARY_OPERATION_NAMES.inverse()[this] if (binaryOp != null) { val assignmentOp = ASSIGNMENT_OPERATION_COUNTERPARTS.inverse()[binaryOp] return (if (assignmentOp != null) setOf(binaryOp, assignmentOp) else setOf(binaryOp)) to KtSimpleNameReference::class.java } +*/ val assignmentOp = ASSIGNMENT_OPERATIONS.inverse()[this] if (assignmentOp != null) return setOf(assignmentOp) to KtSimpleNameReference::class.java diff --git a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindMemberUsagesHandler.kt b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindMemberUsagesHandler.kt index 163c7e9d3f3..25bd492e936 100644 --- a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindMemberUsagesHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/KotlinFindMemberUsagesHandler.kt @@ -131,9 +131,9 @@ abstract class KotlinFindMemberUsagesHandler val uniqueProcessor = CommonProcessors.UniqueProcessor(processor) 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) - .copy(searchForComponentConventions = false, searchInvokeOperator = false) + .copy(searchForComponentConventions = false, searchForOperatorConventions = false) val searchParameters = KotlinReferencesSearchParameters(element, options.searchScope, kotlinOptions = kotlinSearchOptions) with(applyQueryFilters(element, options, ReferencesSearch.search(searchParameters))) { diff --git a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinConventionMethodReferencesSearcher.kt b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinConventionMethodReferencesSearcher.kt index 4b7b53f0308..b351f4f75d3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinConventionMethodReferencesSearcher.kt +++ b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinConventionMethodReferencesSearcher.kt @@ -22,14 +22,11 @@ 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.DestructuringDeclarationReferenceSearcher -import org.jetbrains.kotlin.idea.search.usagesSearch.InvokeOperatorReferenceSearcher +import org.jetbrains.kotlin.idea.search.usagesSearch.OperatorReferenceSearcher import org.jetbrains.kotlin.idea.search.usagesSearch.getOperationSymbolsToSearch import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.lexer.KtSingleValueToken import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike -import org.jetbrains.kotlin.util.OperatorNameConventions class KotlinConventionMethodReferencesSearcher() : QueryExecutorBase(true) { override fun processQuery(queryParameters: MethodReferencesSearch.SearchParameters, consumer: Processor) { @@ -38,11 +35,10 @@ class KotlinConventionMethodReferencesSearcher() : QueryExecutorBasecompareTo(other: A): Int = compareTo(other.n) - fun compareTo(m: Int): Int = n.compareTo(m) + infix operator fun compareTo(other: A): Int = compareTo(other.n) + infix operator fun compareTo(m: Int): Int = n.compareTo(m) } fun test() { diff --git a/idea/testData/findUsages/kotlin/conventions/components/operators.log b/idea/testData/findUsages/kotlin/conventions/components/operators.log index 01b0311ec64..94f01ae03e6 100644 --- a/idea/testData/findUsages/kotlin/conventions/components/operators.log +++ b/idea/testData/findUsages/kotlin/conventions/components/operators.log @@ -1,4 +1,13 @@ +Resolved (x, y) +Resolved b1 + b2 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: CLASS:A -Used plain search in whole search scope +Used plain search in LocalSearchScope: + CLASS:B + FUN:plus \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/contains.0.kt b/idea/testData/findUsages/kotlin/conventions/contains.0.kt index f4469661bb0..48d83fc0a19 100644 --- a/idea/testData/findUsages/kotlin/conventions/contains.0.kt +++ b/idea/testData/findUsages/kotlin/conventions/contains.0.kt @@ -2,7 +2,7 @@ // OPTIONS: usages class A(val n: Int) { - fun contains(k: Int): Boolean = k <= n + infix operator fun contains(k: Int): Boolean = k <= n } fun test() { diff --git a/idea/testData/findUsages/kotlin/conventions/equals.0.kt b/idea/testData/findUsages/kotlin/conventions/equals.0.kt index 85aa6adf9ca..18403f97e96 100644 --- a/idea/testData/findUsages/kotlin/conventions/equals.0.kt +++ b/idea/testData/findUsages/kotlin/conventions/equals.0.kt @@ -3,7 +3,7 @@ // FIND_BY_REF class A(val n: Int) { - override fun equals(other: Any?): Boolean = other is A && other.n == n + infix override fun equals(other: Any?): Boolean = other is A && other.n == n } fun test() { diff --git a/idea/testData/findUsages/kotlin/conventions/equals.results.txt b/idea/testData/findUsages/kotlin/conventions/equals.results.txt index 0ddf42e4a1f..359019aa8a7 100644 --- a/idea/testData/findUsages/kotlin/conventions/equals.results.txt +++ b/idea/testData/findUsages/kotlin/conventions/equals.results.txt @@ -1,4 +1,4 @@ Function call 10 A(0) == A(1) Function call 11 A(0) != 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 \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/forIteration.0.kt b/idea/testData/findUsages/kotlin/conventions/forIteration.0.kt index 5a8ddb79709..f58a6e48bcd 100644 --- a/idea/testData/findUsages/kotlin/conventions/forIteration.0.kt +++ b/idea/testData/findUsages/kotlin/conventions/forIteration.0.kt @@ -2,11 +2,11 @@ // OPTIONS: usages class A { - public fun iterator(): Iterator = throw IllegalStateException("") + operator fun iterator(): Iterator = throw IllegalStateException("") } class B { - public fun iterator(): Iterator = throw IllegalStateException("") + operator fun iterator(): Iterator = throw IllegalStateException("") } fun test() { diff --git a/idea/testData/findUsages/kotlin/conventions/get.0.kt b/idea/testData/findUsages/kotlin/conventions/get.0.kt index 24b87bb7a12..3ef92ef3484 100644 --- a/idea/testData/findUsages/kotlin/conventions/get.0.kt +++ b/idea/testData/findUsages/kotlin/conventions/get.0.kt @@ -2,7 +2,7 @@ // OPTIONS: usages class B(val n: Int) { - fun get(i: Int): B = B(i) + operator fun get(i: Int): B = B(i) } fun test() { diff --git a/idea/testData/findUsages/kotlin/conventions/getAsPropertyDelegate.0.kt b/idea/testData/findUsages/kotlin/conventions/getAsPropertyDelegate.0.kt index d9ecd2a717d..bd2d0f42310 100644 --- a/idea/testData/findUsages/kotlin/conventions/getAsPropertyDelegate.0.kt +++ b/idea/testData/findUsages/kotlin/conventions/getAsPropertyDelegate.0.kt @@ -4,7 +4,7 @@ import kotlin.reflect.KProperty class Delegate() { - fun getValue(thisRef: Any?, property: KProperty<*>): String = ":)" + operator fun getValue(thisRef: Any?, property: KProperty<*>): String = ":)" } val p: String by Delegate() diff --git a/idea/testData/findUsages/kotlin/conventions/inc.0.kt b/idea/testData/findUsages/kotlin/conventions/inc.0.kt index de8b9f1d35f..3a52b22628a 100644 --- a/idea/testData/findUsages/kotlin/conventions/inc.0.kt +++ b/idea/testData/findUsages/kotlin/conventions/inc.0.kt @@ -2,7 +2,7 @@ // OPTIONS: usages class A(val n: Int) { - fun inc(): A = A(n + 1) + operator fun inc(): A = A(n + 1) } fun test() { diff --git a/idea/testData/findUsages/kotlin/conventions/plus.0.kt b/idea/testData/findUsages/kotlin/conventions/plus.0.kt index 78f3dfd1a48..c8ced1b27d8 100644 --- a/idea/testData/findUsages/kotlin/conventions/plus.0.kt +++ b/idea/testData/findUsages/kotlin/conventions/plus.0.kt @@ -2,8 +2,8 @@ // OPTIONS: usages class A(val n: Int) { - fun plus(m: Int): A = A(n + m) - fun plus(a: A): A = this + a.n + operator fun plus(m: Int): A = A(n + m) + operator fun plus(a: A): A = this + a.n } fun test() { diff --git a/idea/testData/findUsages/kotlin/conventions/plus.log b/idea/testData/findUsages/kotlin/conventions/plus.log new file mode 100644 index 00000000000..a468dcb6760 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/plus.log @@ -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 \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/plus.results.txt b/idea/testData/findUsages/kotlin/conventions/plus.results.txt index 0d0cf18c482..c910488b8ec 100644 --- a/idea/testData/findUsages/kotlin/conventions/plus.results.txt +++ b/idea/testData/findUsages/kotlin/conventions/plus.results.txt @@ -2,4 +2,4 @@ Function call 10 A(0) + A(1) + 2 Function call 11 A(0) plus A(1) plus 2 Function call 12 A(0).plus(A(1).plus(2)) 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 \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/plusAssign.0.kt b/idea/testData/findUsages/kotlin/conventions/plusAssign.0.kt index 15ccb0d1313..cad736d88b4 100644 --- a/idea/testData/findUsages/kotlin/conventions/plusAssign.0.kt +++ b/idea/testData/findUsages/kotlin/conventions/plusAssign.0.kt @@ -2,11 +2,11 @@ // OPTIONS: usages class A(var n: Int) { - fun plusAssign(m: Int) { + operator fun plusAssign(m: Int) { n += m } - fun plusAssign(a: A) { + operator fun plusAssign(a: A) { this += a.n } } diff --git a/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.0.kt b/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.0.kt index 4ff0b2a1b35..00e1050f010 100644 --- a/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.0.kt +++ b/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.0.kt @@ -4,8 +4,9 @@ import kotlin.reflect.KProperty class Delegate() { - fun getValue(thisRef: Any?, property: KProperty<*>): String = ":)" - fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { + operator fun getValue(thisRef: Any?, property: KProperty<*>): String = ":)" + + operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { } fun propertyDelegated(property: KProperty<*>) { diff --git a/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.results.txt b/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.results.txt index 95ef811697f..51d6c96ddd4 100644 --- a/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.results.txt +++ b/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.results.txt @@ -1 +1 @@ -Property delegation 15 var p: String by Delegate() +Property delegation 16 var p: String by Delegate() \ No newline at end of file diff --git a/idea/testData/findUsages/kotlin/conventions/set.0.kt b/idea/testData/findUsages/kotlin/conventions/set.0.kt index fcea8f04ed0..111b0ed623d 100644 --- a/idea/testData/findUsages/kotlin/conventions/set.0.kt +++ b/idea/testData/findUsages/kotlin/conventions/set.0.kt @@ -2,7 +2,7 @@ // OPTIONS: usages class B(val n: Int) { - fun set(i: Int, a: B) {} + operator fun set(i: Int, a: B) {} } fun test() { diff --git a/idea/testData/findUsages/kotlin/conventions/setAsPropertyDelegate.0.kt b/idea/testData/findUsages/kotlin/conventions/setAsPropertyDelegate.0.kt index 4df21687b6f..cc158f0246e 100644 --- a/idea/testData/findUsages/kotlin/conventions/setAsPropertyDelegate.0.kt +++ b/idea/testData/findUsages/kotlin/conventions/setAsPropertyDelegate.0.kt @@ -4,8 +4,9 @@ import kotlin.reflect.KProperty class Delegate() { - fun getValue(thisRef: Any?, property: KProperty<*>): String = ":)" - fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { + operator fun getValue(thisRef: Any?, property: KProperty<*>): String = ":)" + + operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { } } diff --git a/idea/testData/findUsages/kotlin/conventions/setAsPropertyDelegate.results.txt b/idea/testData/findUsages/kotlin/conventions/setAsPropertyDelegate.results.txt index fed791db40b..f75a86919b4 100644 --- a/idea/testData/findUsages/kotlin/conventions/setAsPropertyDelegate.results.txt +++ b/idea/testData/findUsages/kotlin/conventions/setAsPropertyDelegate.results.txt @@ -1 +1 @@ -Property delegation 13 var p: String by Delegate() +Property delegation 14 var p: String by Delegate() \ No newline at end of file