diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java index 66e6e36ea8d..f2260c2238f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java @@ -58,9 +58,8 @@ import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE; import static org.jetbrains.kotlin.types.TypeUtils.noExpectedType; import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.createFakeExpressionOfType; +//TODO: check for 'operator' modifier! public class DelegatedPropertyResolver { - public static final Name PROPERTY_DELEGATED_FUNCTION_NAME = Name.identifier("propertyDelegated"); - private final KotlinBuiltIns builtIns; private final FakeCallResolver fakeCallResolver; private final ExpressionTypingServices expressionTypingServices; @@ -198,7 +197,7 @@ public class DelegatedPropertyResolver { ExpressionReceiver receiver = ExpressionReceiver.Companion.create(delegateExpression, delegateType, trace.getBindingContext()); Pair> resolutionResult = - fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, PROPERTY_DELEGATED_FUNCTION_NAME, delegateExpression); + fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, OperatorNameConventions.PROPERTY_DELEGATED, delegateExpression); Call call = resolutionResult.getFirst(); OverloadResolutionResults functionResults = resolutionResult.getSecond(); diff --git a/core/descriptors/src/org/jetbrains/kotlin/util/OperatorNameConventions.kt b/core/descriptors/src/org/jetbrains/kotlin/util/OperatorNameConventions.kt index 3c33a2394cd..9be51504707 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/util/OperatorNameConventions.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/util/OperatorNameConventions.kt @@ -59,6 +59,8 @@ object OperatorNameConventions { @JvmField val COROUTINE_HANDLE_RESULT = Name.identifier("handleResult") @JvmField val COROUTINE_HANDLE_EXCEPTION = Name.identifier("handleException") + @JvmField val PROPERTY_DELEGATED = Name.identifier("propertyDelegated") + // If you add new unary, binary or assignment operators, add it to OperatorConventions as well @JvmField diff --git a/core/descriptors/src/org/jetbrains/kotlin/util/modifierChecks.kt b/core/descriptors/src/org/jetbrains/kotlin/util/modifierChecks.kt index e53c04543fe..446d7e57e00 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/util/modifierChecks.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/util/modifierChecks.kt @@ -46,6 +46,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions.INC import org.jetbrains.kotlin.util.OperatorNameConventions.INVOKE import org.jetbrains.kotlin.util.OperatorNameConventions.ITERATOR import org.jetbrains.kotlin.util.OperatorNameConventions.NEXT +import org.jetbrains.kotlin.util.OperatorNameConventions.PROPERTY_DELEGATED import org.jetbrains.kotlin.util.OperatorNameConventions.RANGE_TO import org.jetbrains.kotlin.util.OperatorNameConventions.SET import org.jetbrains.kotlin.util.OperatorNameConventions.SET_VALUE @@ -215,7 +216,8 @@ object OperatorChecks : AbstractModifierChecks() { ?: ensure(valueParameters[0].type.isThrowable()) { "First parameter should be 'Throwable'" } - } + }, + Checks(PROPERTY_DELEGATED, Member, ValueParameterCountCheck.Equals(1)) //TODO: more checks required! ) private fun FunctionDescriptor.checkHandleSecondParameter(): String? { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/KotlinIndexers.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/KotlinIndexers.kt index afa4589b2c4..16d46f0f750 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/KotlinIndexers.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/KotlinIndexers.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.idea.search +import com.google.common.collect.ImmutableSet import com.intellij.lexer.Lexer import com.intellij.psi.TokenType import com.intellij.psi.impl.cache.impl.BaseFilterLexer @@ -26,14 +27,27 @@ import com.intellij.psi.impl.cache.impl.todo.LexerBasedTodoIndexer import com.intellij.psi.search.UsageSearchContext import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.TokenSet -import org.jetbrains.kotlin.idea.search.usagesSearch.ALL_SEARCHABLE_OPERATIONS import org.jetbrains.kotlin.kdoc.lexer.KDocTokens import org.jetbrains.kotlin.lexer.KotlinLexer +import org.jetbrains.kotlin.lexer.KtToken import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.types.expressions.OperatorConventions import java.util.* val KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT: Short = 0x20 +private val ALL_SEARCHABLE_OPERATIONS: ImmutableSet = ImmutableSet + .builder() + .addAll(OperatorConventions.UNARY_OPERATION_NAMES.keys) + .addAll(OperatorConventions.BINARY_OPERATION_NAMES.keys) + .addAll(OperatorConventions.ASSIGNMENT_OPERATIONS.keys) + .addAll(OperatorConventions.COMPARISON_OPERATIONS) + .addAll(OperatorConventions.EQUALS_OPERATIONS) + .addAll(OperatorConventions.IN_OPERATIONS) + .add(KtTokens.LBRACKET) + .add(KtTokens.BY_KEYWORD) + .build() + class KotlinFilterLexer(private val occurrenceConsumer: OccurrenceConsumer): BaseFilterLexer(KotlinLexer(), occurrenceConsumer) { private val codeTokens = TokenSet.orSet( TokenSet.create(*ALL_SEARCHABLE_OPERATIONS.toTypedArray()), 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 e2d9a90d196..3c520dc9ae1 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 @@ -39,13 +39,11 @@ import org.jetbrains.kotlin.idea.search.unionSafe 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.utils.singletonOrEmptyList import java.util.* data class KotlinReferencesSearchOptions(val acceptCallableOverrides: Boolean = false, @@ -94,9 +92,6 @@ class KotlinReferencesSearcher : QueryExecutorBase scope.unionSafe(queryParameters.effectiveSearchScope(e)) @@ -104,7 +99,6 @@ class KotlinReferencesSearcher : QueryExecutorBase Boolean = when { unwrappedElement is KtParameter -> ({ ref: PsiReference -> !ref.isNamedArgumentReference()/* they are processed later*/ }) - specialSymbols != null -> { ref -> ref.javaClass == specialSymbols.second } else -> ({true}) } @@ -117,9 +111,12 @@ class KotlinReferencesSearcher : QueryExecutorBase + + + val classNameForCompanionObject = unwrappedElement.getClassNameForCompanionObject() + if (classNameForCompanionObject != null) { queryParameters.optimizer.searchWord( - word, effectiveSearchScope, UsageSearchContext.ANY, true, unwrappedElement, resultProcessor) + classNameForCompanionObject, effectiveSearchScope, UsageSearchContext.ANY, true, unwrappedElement, resultProcessor) } if (unwrappedElement is KtParameter && kotlinOptions.searchNamedArguments) { 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 0a466a51367..46379a848d1 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 @@ -31,11 +31,9 @@ import com.intellij.util.Processor import org.jetbrains.annotations.TestOnly 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.caches.resolve.KotlinCacheService import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.diagnostics.DiagnosticUtils import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinLanguage @@ -53,9 +51,7 @@ import org.jetbrains.kotlin.idea.util.FuzzyType import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.idea.util.application.runReadAction 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.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform @@ -207,11 +203,6 @@ class ExpressionsOfTypeProcessor( } private fun addCallableDeclarationToProcess(declaration: PsiElement, scope: SearchScope, processMethod: (PsiReference) -> Boolean) { - if (declaration.isOperatorExpensiveToSearch()) { // cancel all tasks and use plain search - downShiftToPlainSearch() - return - } - data class ProcessCallableUsagesTask(val declaration: PsiElement, val processMethod: (PsiReference) -> Boolean) : Task { override fun perform() { testLog?.add("Searched references to ${logPresentation(declaration)} in non-Java files") @@ -661,25 +652,6 @@ class ExpressionsOfTypeProcessor( private fun PsiModifierListOwner.isLocal() = parents.any { it is PsiCodeBlock } - private fun PsiElement.isOperatorExpensiveToSearch(): Boolean { - when (this) { - is KtFunction -> { - val isOperator = hasModifier(KtTokens.OPERATOR_KEYWORD) - || hasModifier(KtTokens.OVERRIDE_KEYWORD) && (resolveToDescriptorIfAny() as? FunctionDescriptor)?.isOperator == true - val name = name - return isOperator && name != null && Name.isValidIdentifier(name) && Name.identifier(name).getOperationSymbolsToSearch() != null - } - - is KtLightMethod -> { - return kotlinOrigin?.isOperatorExpensiveToSearch() == true - } - - else -> { - return false - } - } - } - private fun KotlinType.containsTypeOrDerivedInside(type: FuzzyType): Boolean { return type.checkIsSuperTypeOf(this) != null || arguments.any { it.type.containsTypeOrDerivedInside(type) } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/OperatorReferenceSearcher.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/OperatorReferenceSearcher.kt index 831f4514ebb..32d0cada491 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/OperatorReferenceSearcher.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/OperatorReferenceSearcher.kt @@ -183,7 +183,7 @@ abstract class OperatorReferenceSearcher( name == OperatorNameConventions.ITERATOR -> return IteratorOperatorReferenceSearcher(declaration, searchScope, consumer, optimizer, options) - name == OperatorNameConventions.GET_VALUE || name == OperatorNameConventions.SET_VALUE -> + name == OperatorNameConventions.GET_VALUE || name == OperatorNameConventions.SET_VALUE || name == OperatorNameConventions.PROPERTY_DELEGATED -> return PropertyDelegationOperatorReferenceSearcher(declaration, searchScope, consumer, optimizer, options) else -> 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 deleted file mode 100644 index 63c563102a5..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/conventions.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2010-2015 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.google.common.collect.ImmutableSet -import org.jetbrains.kotlin.idea.references.KtPropertyDelegationMethodsReference -import org.jetbrains.kotlin.lexer.KtToken -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.DelegatedPropertyResolver -import org.jetbrains.kotlin.types.expressions.OperatorConventions.* - -val ALL_SEARCHABLE_OPERATIONS: ImmutableSet = ImmutableSet - .builder() - .addAll(UNARY_OPERATION_NAMES.keys) - .addAll(BINARY_OPERATION_NAMES.keys) - .addAll(ASSIGNMENT_OPERATIONS.keys) - .addAll(COMPARISON_OPERATIONS) - .addAll(EQUALS_OPERATIONS) - .addAll(IN_OPERATIONS) - .add(KtTokens.LBRACKET) - .add(KtTokens.BY_KEYWORD) - .build() - -fun Name.getOperationSymbolsToSearch(): Pair, Class<*>>? { - when (this) { - DelegatedPropertyResolver.PROPERTY_DELEGATED_FUNCTION_NAME -> return setOf(KtTokens.BY_KEYWORD) to KtPropertyDelegationMethodsReference::class.java - } - - return null -} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/searchHelpers.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/searchHelpers.kt index 4d4a6d280a9..795b620ab04 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/searchHelpers.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/searchHelpers.kt @@ -22,9 +22,6 @@ import org.jetbrains.kotlin.asJava.LightClassUtil.PropertyAccessorsPsiMethods import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze -import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions -import org.jetbrains.kotlin.lexer.KtSingleValueToken -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.resolve.BindingContext @@ -63,18 +60,6 @@ fun PsiNamedElement.getClassNameForCompanionObject(): String? { } } -fun PsiNamedElement.getSpecialNamesToSearch(options: KotlinReferencesSearchOptions): Pair, Class<*>>? { - val name = name - when { - name == null || !Name.isValidIdentifier(name) -> return null - - else -> { - val operationSymbolsToSearch = Name.identifier(name).getOperationSymbolsToSearch() ?: return null - return operationSymbolsToSearch.first.map { (it as KtSingleValueToken).value } to operationSymbolsToSearch.second - } - } -} - fun KtParameter.dataClassComponentFunction(): FunctionDescriptor? { if (!hasValOrVar()) return null 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 37edad8f4db..d6afba455ab 100644 --- a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinConventionMethodReferencesSearcher.kt +++ b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinConventionMethodReferencesSearcher.kt @@ -18,39 +18,19 @@ package org.jetbrains.kotlin.idea.search.ideaExtensions import com.intellij.openapi.application.QueryExecutorBase import com.intellij.psi.PsiReference -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.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 class KotlinConventionMethodReferencesSearcher() : QueryExecutorBase(true) { override fun processQuery(queryParameters: MethodReferencesSearch.SearchParameters, consumer: Processor) { - val method = queryParameters.method - val name = runReadAction { method.name } - if (!Name.isValidIdentifier(name)) return - val identifier = Name.identifier(name) - val operatorSearcher = OperatorReferenceSearcher.create( - method, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer, KotlinReferencesSearchOptions(acceptCallableOverrides = true)) - if (operatorSearcher != null) { - operatorSearcher.run() - } - else { - val operationSymbolsToSearch = identifier.getOperationSymbolsToSearch() ?: return - val wordsToSearch = operationSymbolsToSearch.first.map { (it as KtSingleValueToken).value } - val resultProcessor = KotlinRequestResultProcessor(method, - filter = { ref -> ref.javaClass == operationSymbolsToSearch.second }) - - wordsToSearch.forEach { word -> - queryParameters.optimizer.searchWord(word, queryParameters.effectiveSearchScope.restrictToKotlinSources(), - UsageSearchContext.IN_CODE, true, method, - resultProcessor) - } - } + queryParameters.method, + queryParameters.effectiveSearchScope, + consumer, + queryParameters.optimizer, + KotlinReferencesSearchOptions(acceptCallableOverrides = true) + ) + operatorSearcher?.run() } } diff --git a/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.0.kt b/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.0.kt index 00e1050f010..ff92f3f1297 100644 --- a/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.0.kt +++ b/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.0.kt @@ -9,7 +9,7 @@ class Delegate() { operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { } - fun propertyDelegated(property: KProperty<*>) { + operator fun propertyDelegated(property: KProperty<*>) { } } diff --git a/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.log b/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.log new file mode 100644 index 00000000000..58f49f01c90 --- /dev/null +++ b/idea/testData/findUsages/kotlin/conventions/propertyDelegatedFunction.log @@ -0,0 +1,4 @@ +Resolved by Delegate() +Searched references to Delegate +Used plain search of Delegate.propertyDelegated(property: KProperty<*>) in LocalSearchScope: + CLASS:Delegate