ReferenceSearch searches references to parameters using optimized way too

#KT-8625 Fixed
This commit is contained in:
Valentin Kipyatkov
2015-07-31 16:50:34 +03:00
parent d6f724c55d
commit 397e48a11d
7 changed files with 74 additions and 88 deletions
@@ -20,7 +20,6 @@ import com.intellij.lang.ASTNode;
import com.intellij.navigation.ItemPresentation;
import com.intellij.navigation.ItemPresentationProviders;
import com.intellij.psi.PsiElement;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -176,21 +175,6 @@ public class JetParameter extends JetNamedDeclarationStub<KotlinParameterStub> i
return Collections.emptyList();
}
@NotNull
@Override
public SearchScope getUseScope() {
JetDeclaration function = getOwnerFunction();
if (function != null && !(function instanceof JetFunctionLiteral)) {
return function.getUseScope();
}
return super.getUseScope();
}
@NotNull
public SearchScope getUseScopeExceptNamedArguments() {
return super.getUseScope();
}
@Nullable
public JetFunction getOwnerFunction() {
PsiElement parent = getParent();
@@ -19,9 +19,8 @@ package org.jetbrains.kotlin.idea.search.ideaExtensions
import com.intellij.openapi.application.QueryExecutorBase
import com.intellij.openapi.progress.ProgressManager
import com.intellij.psi.*
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.RequestResultProcessor
import com.intellij.psi.search.SearchScope
import com.intellij.psi.impl.cache.CacheManager
import com.intellij.psi.search.*
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.Processor
@@ -29,8 +28,11 @@ import org.jetbrains.kotlin.asJava.KotlinLightMethod
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.idea.JetFileType
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference
import org.jetbrains.kotlin.idea.search.KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT
import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchLocation
import org.jetbrains.kotlin.idea.search.usagesSearch.getSpecialNamesToSearch
import org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.*
@@ -45,28 +47,16 @@ public class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, Referenc
val words = unwrappedElement.getSpecialNamesToSearch()
val resultProcessor = object : RequestResultProcessor() {
private val referenceService = PsiReferenceService.getService()
override fun processTextOccurrence(element: PsiElement, offsetInElement: Int, consumer: Processor<PsiReference>): Boolean {
return referenceService.getReferences(element, PsiReferenceService.Hints.NO_HINTS).all { ref ->
ProgressManager.checkCanceled()
when {
!ReferenceRange.containsOffsetInElement(ref, offsetInElement) -> true
!ref.isReferenceTo(unwrappedElement) -> true
else -> consumer.process(ref)
}
}
}
}
val effectiveSearchScope = runReadAction { queryParameters.effectiveSearchScope }
words.forEach { word ->
queryParameters.getOptimizer().searchWord(word, effectiveSearchScope,
UsagesSearchLocation.EVERYWHERE.searchContext, true, unwrappedElement,
resultProcessor)
queryParameters.optimizer.searchWord(word, effectiveSearchScope,
UsagesSearchLocation.EVERYWHERE.searchContext, true, unwrappedElement,
MyRequestResultProcessor(unwrappedElement) { !it.isNamedArgumentReference()/* they are processed later*/ })
}
if (unwrappedElement is JetParameter) {
runReadAction { searchNamedArguments(unwrappedElement, queryParameters) }
}
if (!(unwrappedElement is JetElement && isOnlyKotlinSearch(effectiveSearchScope))) {
@@ -74,6 +64,52 @@ public class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, Referenc
}
}
private fun searchNamedArguments(parameter: JetParameter, queryParameters: ReferencesSearch.SearchParameters) {
val function = parameter.ownerFunction ?: return
if (function.nameAsName?.isSpecial ?: true) return
val project = function.project
var namedArgsScope = function.useScope.intersectWith(queryParameters.scopeDeterminedByUser)
if (namedArgsScope is GlobalSearchScope) {
namedArgsScope = JetSourceFilterScope.kotlinSources(namedArgsScope, project)
val filesWithFunctionName = CacheManager.SERVICE.getInstance(project).getVirtualFilesWithWord(
function.name!!, UsageSearchContext.IN_CODE, namedArgsScope, true)
namedArgsScope = GlobalSearchScope.filesScope(project, filesWithFunctionName.asList())
}
queryParameters.optimizer.searchWord(parameter.name!!,
namedArgsScope,
KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT,
true,
parameter,
MyRequestResultProcessor(parameter) { it.isNamedArgumentReference() })
}
private fun PsiReference.isNamedArgumentReference(): Boolean {
return this is JetSimpleNameReference && expression.parent is JetValueArgumentName
}
private class MyRequestResultProcessor(
private val unwrappedElement: PsiElement,
private val filter: (PsiReference) -> Boolean
) : RequestResultProcessor() {
private val referenceService = PsiReferenceService.getService()
override fun processTextOccurrence(element: PsiElement, offsetInElement: Int, consumer: Processor<PsiReference>): Boolean {
return referenceService.getReferences(element, PsiReferenceService.Hints.NO_HINTS).all { ref ->
ProgressManager.checkCanceled()
when {
!filter(ref) -> true
!ReferenceRange.containsOffsetInElement(ref, offsetInElement) -> true
!ref.isReferenceTo(unwrappedElement) -> true
else -> consumer.process(ref)
}
}
}
}
companion object {
public fun processJetClassOrObject(element: JetClassOrObject, queryParameters: ReferencesSearch.SearchParameters) {
val className = element.getName()
@@ -251,8 +251,8 @@ class PropertyUsagesSearchHelper(
override fun makeItemList(target: UsagesSearchTarget<JetNamedDeclaration>): List<UsagesSearchRequestItem> {
val element = target.element
if (element is JetParameter) {
val realUsagesScope = element.useScopeExceptNamedArguments
val realUsagesTarget = target.withScope(realUsagesScope and target.effectiveScope)
val realUsagesScope = element.useScope and target.effectiveScope
val realUsagesTarget = target.withScope(realUsagesScope)
val realUsagesFilter = makeFilter(target) and !(PsiReference::isNamedArgumentUsage).searchFilter
val realUsagesRequest = UsagesSearchRequestItem(realUsagesTarget, makeWordList(target), realUsagesFilter, makeAdditionalSearchDelegate(target.element))
@@ -266,7 +266,7 @@ class PropertyUsagesSearchHelper(
return listOf(realUsagesRequest)
}
var scope = target.effectiveScope
var scope = function.useScope and target.effectiveScope
if (scope is GlobalSearchScope) {
scope = JetSourceFilterScope.kotlinSources(scope, element.project)
}
@@ -96,7 +96,7 @@ public class UsagesSearchRequestItem(
val additionalFileFilters: Collection<AdditionalFileFilter> = emptyList()
)
public data class AdditionalFileFilter(
public class AdditionalFileFilter(
val word: String,
val searchContext: Short,
val caseSensitively: Boolean
@@ -19,13 +19,8 @@ package org.jetbrains.kotlin.idea.findUsages.handlers
import com.intellij.find.findUsages.AbstractFindUsagesDialog
import com.intellij.find.findUsages.FindUsagesOptions
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Computable
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiReference
import com.intellij.psi.search.PsiElementProcessor
import com.intellij.psi.search.PsiElementProcessorAdapter
import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.usageView.UsageInfo
import com.intellij.util.CommonProcessors
@@ -35,14 +30,15 @@ import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.idea.findUsages.*
import org.jetbrains.kotlin.idea.findUsages.dialogs.KotlinFindFunctionUsagesDialog
import org.jetbrains.kotlin.idea.findUsages.dialogs.KotlinFindPropertyUsagesDialog
import org.jetbrains.kotlin.idea.search.declarationsSearch.*
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders
import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearch
import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchHelper
import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchRequest
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.*
import java.util.Collections
import org.jetbrains.kotlin.psi.JetConstructor
import org.jetbrains.kotlin.psi.JetFunction
import org.jetbrains.kotlin.psi.JetNamedDeclaration
import org.jetbrains.kotlin.psi.JetParameter
public abstract class KotlinFindMemberUsagesHandler<T : JetNamedDeclaration>
protected constructor(declaration: T, elementsToSearch: Collection<PsiElement>, factory: KotlinFindUsagesHandlerFactory)
@@ -89,7 +85,12 @@ public abstract class KotlinFindMemberUsagesHandler<T : JetNamedDeclaration>
val request = runReadAction {
@suppress("UNCHECKED_CAST")
getSearchHelper(kotlinOptions).newRequest(options.toSearchTarget<T>(element as T, true))
val searchTarget = if (element is JetParameter)
options.toSearchTarget<T>(element as T, restrictByTarget = false) // named argument usages are outside getUseScope for JetParameter
else
options.toSearchTarget<T>(element as T, restrictByTarget = true)
getSearchHelper(kotlinOptions).newRequest(searchTarget)
}
val uniqueProcessor = CommonProcessors.UniqueProcessor(processor)
@@ -303,7 +303,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
String oldParamName = oldParam.getName();
if (parameterInfo == newReceiverInfo || (oldParamName != null && !oldParamName.equals(parameterInfo.getName()))) {
for (PsiReference reference : ChangeSignaturePackage.findParameterUsages(oldParam)) {
for (PsiReference reference : ReferencesSearch.search(oldParam, oldParam.getUseScope())) {
PsiElement element = reference.getElement();
if ((element instanceof JetSimpleNameExpression || element instanceof KDocName) &&
@@ -1,35 +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.refactoring.changeSignature
import com.intellij.psi.PsiReference
import com.intellij.usageView.UsageInfo
import com.intellij.util.CommonProcessors
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory
import org.jetbrains.kotlin.idea.findUsages.KotlinPropertyFindUsagesOptions
import org.jetbrains.kotlin.psi.JetParameter
// searching parameter usages via ReferenceSearch is currently too slow (uses non-optimized search for named arguments),
// that's why we use KotlinFindUsagesHandler
fun findParameterUsages(parameter: JetParameter): Collection<PsiReference> {
val project = parameter.project
val findUsagesHandler = KotlinFindUsagesHandlerFactory(project).createFindUsagesHandlerNoQuestions(parameter)
val processor = CommonProcessors.CollectProcessor<UsageInfo>()
val options = KotlinPropertyFindUsagesOptions(project)
findUsagesHandler.processElementUsages(parameter, processor, options)
return processor.results.map { it.reference }.filterNotNull()
}