All operator usages are searched with new searcher
This commit is contained in:
@@ -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<Call, OverloadResolutionResults<FunctionDescriptor>> 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<FunctionDescriptor> functionResults = resolutionResult.getSecond();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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? {
|
||||
|
||||
@@ -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<KtToken> = ImmutableSet
|
||||
.builder<KtToken>()
|
||||
.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()),
|
||||
|
||||
+5
-8
@@ -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<PsiReference, ReferencesSearc
|
||||
|
||||
val unwrappedElement = element.namedUnwrappedElement ?: return
|
||||
|
||||
val specialSymbols = unwrappedElement.getSpecialNamesToSearch(kotlinOptions)
|
||||
val words = (specialSymbols?.first ?: emptyList()) + unwrappedElement.getClassNameForCompanionObject().singletonOrEmptyList()
|
||||
|
||||
val elements = if (unwrappedElement is KtDeclaration) unwrappedElement.toLightElements() else listOf(unwrappedElement)
|
||||
val effectiveSearchScope = elements.fold(queryParameters.effectiveSearchScope) { scope, e ->
|
||||
scope.unionSafe(queryParameters.effectiveSearchScope(e))
|
||||
@@ -104,7 +99,6 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
|
||||
|
||||
val refFilter: (PsiReference) -> 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<PsiReference, ReferencesSearc
|
||||
name, effectiveSearchScope, UsageSearchContext.IN_CODE, true, unwrappedElement, resultProcessor)
|
||||
}
|
||||
}
|
||||
words.forEach { word ->
|
||||
|
||||
|
||||
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) {
|
||||
|
||||
-28
@@ -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) }
|
||||
}
|
||||
|
||||
+1
-1
@@ -183,7 +183,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
|
||||
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 ->
|
||||
|
||||
@@ -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<KtToken> = ImmutableSet
|
||||
.builder<KtToken>()
|
||||
.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<Set<KtToken>, Class<*>>? {
|
||||
when (this) {
|
||||
DelegatedPropertyResolver.PROPERTY_DELEGATED_FUNCTION_NAME -> return setOf(KtTokens.BY_KEYWORD) to KtPropertyDelegationMethodsReference::class.java
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -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<List<String>, 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
|
||||
|
||||
|
||||
+7
-27
@@ -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<PsiReference, MethodReferencesSearch.SearchParameters>(true) {
|
||||
override fun processQuery(queryParameters: MethodReferencesSearch.SearchParameters, consumer: Processor<PsiReference>) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ class Delegate() {
|
||||
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
|
||||
}
|
||||
|
||||
fun <caret>propertyDelegated(property: KProperty<*>) {
|
||||
operator fun <caret>propertyDelegated(property: KProperty<*>) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
Resolved by Delegate()
|
||||
Searched references to Delegate
|
||||
Used plain search of Delegate.propertyDelegated(property: KProperty<*>) in LocalSearchScope:
|
||||
CLASS:Delegate
|
||||
Reference in New Issue
Block a user