Fixed operator references search for functions declared in Java

This commit is contained in:
Valentin Kipyatkov
2016-09-02 20:46:22 +03:00
parent f6fbd0b623
commit 0158ff46f3
14 changed files with 161 additions and 91 deletions
@@ -18,8 +18,10 @@ package org.jetbrains.kotlin.caches.resolve
import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache
interface KotlinCacheService { interface KotlinCacheService {
@@ -28,6 +30,7 @@ interface KotlinCacheService {
} }
fun getResolutionFacade(elements: List<KtElement>): ResolutionFacade fun getResolutionFacade(elements: List<KtElement>): ResolutionFacade
fun getResolutionFacadeByFile(file: PsiFile, platform: TargetPlatform): ResolutionFacade
fun getSuppressionCache(): KotlinSuppressCache fun getSuppressionCache(): KotlinSuppressCache
} }
@@ -21,6 +21,8 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.ProjectRootModificationTracker import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.openapi.util.ModificationTracker import com.intellij.openapi.util.ModificationTracker
import com.intellij.psi.PsiCodeFragment
import com.intellij.psi.PsiFile
import com.intellij.psi.util.CachedValue import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.CachedValuesManager
@@ -48,8 +50,9 @@ import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import org.jetbrains.kotlin.utils.addToStdlib.sumByLong import org.jetbrains.kotlin.utils.addToStdlib.sumByLong
import java.lang.AssertionError
import java.lang.IllegalStateException
internal val LOG = Logger.getInstance(KotlinCacheService::class.java) internal val LOG = Logger.getInstance(KotlinCacheService::class.java)
@@ -309,12 +312,25 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
val syntheticFiles = findSyntheticFiles(files) val syntheticFiles = findSyntheticFiles(files)
val file = files.first() val file = files.first()
val moduleInfo = file.getModuleInfo() val moduleInfo = file.getModuleInfo()
val projectFacade = if (syntheticFiles.isNotEmpty()) { if (syntheticFiles.isNotEmpty()) {
getFacadeForSyntheticFiles(syntheticFiles) val projectFacade = getFacadeForSyntheticFiles(syntheticFiles)
return ResolutionFacadeImpl(projectFacade, moduleInfo)
} }
else { else {
globalFacade(TargetPlatformDetector.getPlatform(file), moduleInfo.sdk) val platform = TargetPlatformDetector.getPlatform(file)
return getResolutionFacadeByModuleInfo(moduleInfo, platform)
} }
}
override fun getResolutionFacadeByFile(file: PsiFile, platform: TargetPlatform): ResolutionFacade {
assert(file !is PsiCodeFragment)
assert(ProjectRootsUtil.isInProjectSource(file))
val moduleInfo = file.getModuleInfo()
return getResolutionFacadeByModuleInfo(moduleInfo, platform)
}
private fun getResolutionFacadeByModuleInfo(moduleInfo: IdeaModuleInfo, platform: TargetPlatform): ResolutionFacade {
val projectFacade = globalFacade(platform, moduleInfo.sdk)
return ResolutionFacadeImpl(projectFacade, moduleInfo) return ResolutionFacadeImpl(projectFacade, moduleInfo)
} }
@@ -120,9 +120,8 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
searchLightElements(queryParameters, element, consumer) searchLightElements(queryParameters, element, consumer)
} }
//TODO: operator functions from Java if (element is KtFunction || element is PsiMethod) {
if (element is KtFunction) { val referenceSearcher = OperatorReferenceSearcher.create(
val referenceSearcher = OperatorReferenceSearcher.createForKtFunction(
element, effectiveSearchScope, consumer, queryParameters.optimizer, kotlinOptions) element, effectiveSearchScope, consumer, queryParameters.optimizer, kotlinOptions)
referenceSearcher?.run() referenceSearcher?.run()
} }
@@ -247,7 +246,7 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
} }
if (componentFunction != null) { if (componentFunction != null) {
searchNamedElement(queryParameters, componentFunction) searchNamedElement(queryParameters, componentFunction)
val searcher = OperatorReferenceSearcher.createForPsiMethod( val searcher = OperatorReferenceSearcher.create(
componentFunction, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer, kotlinOptions) componentFunction, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer, kotlinOptions)
searcher!!.run() searcher!!.run()
} }
@@ -25,11 +25,10 @@ import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.lexer.KtSingleValueToken import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpression
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 BinaryOperatorReferenceSearcher( class BinaryOperatorReferenceSearcher(
targetFunction: KtFunction, targetFunction: PsiElement,
private val operationTokens: List<KtSingleValueToken>, private val operationTokens: List<KtSingleValueToken>,
searchScope: SearchScope, searchScope: SearchScope,
consumer: Processor<PsiReference>, consumer: Processor<PsiReference>,
@@ -23,11 +23,14 @@ import com.intellij.psi.search.SearchScope
import com.intellij.util.Processor import com.intellij.util.Processor
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtOperationReferenceExpression
import org.jetbrains.kotlin.psi.KtWhenConditionInRange
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
class ContainsOperatorReferenceSearcher( class ContainsOperatorReferenceSearcher(
targetFunction: KtFunction, targetFunction: PsiElement,
searchScope: SearchScope, searchScope: SearchScope,
consumer: Processor<PsiReference>, consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector optimizer: SearchRequestCollector
@@ -22,18 +22,20 @@ 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.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
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
class DestructuringDeclarationReferenceSearcher( class DestructuringDeclarationReferenceSearcher(
targetDeclaration: KtDeclaration, targetDeclaration: PsiElement,
searchScope: SearchScope, searchScope: SearchScope,
consumer: Processor<PsiReference>, consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector optimizer: SearchRequestCollector
) : OperatorReferenceSearcher<KtDestructuringDeclaration>(targetDeclaration, searchScope, consumer, optimizer, wordsToSearch = listOf("(")) { ) : OperatorReferenceSearcher<KtDestructuringDeclaration>(targetDeclaration, searchScope, consumer, optimizer, wordsToSearch = listOf("(")) {
//TODO
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) }
is KtFunction -> targetDeclaration.name?.let { getComponentIndex(it) } is KtFunction -> targetDeclaration.name?.let { getComponentIndex(it) }
@@ -41,6 +43,15 @@ class DestructuringDeclarationReferenceSearcher(
else -> null else -> null
} }
override fun resolveTargetToDescriptor(): FunctionDescriptor? {
if (targetDeclaration is KtParameter) {
return targetDeclaration.dataClassComponentFunction()
}
else {
return super.resolveTargetToDescriptor()
}
}
override fun run() { override fun run() {
if (componentIndex == null) return if (componentIndex == null) return
super.run() super.run()
@@ -20,6 +20,8 @@ import com.intellij.ide.highlighter.JavaFileType
import com.intellij.lang.java.JavaLanguage import com.intellij.lang.java.JavaLanguage
import com.intellij.lang.xml.XMLLanguage import com.intellij.lang.xml.XMLLanguage
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.LocalSearchScope
@@ -30,6 +32,7 @@ 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.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
@@ -39,7 +42,6 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
@@ -51,6 +53,7 @@ import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
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.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import java.util.* import java.util.*
@@ -59,9 +62,9 @@ import java.util.*
class ExpressionsOfTypeProcessor( class ExpressionsOfTypeProcessor(
private val typeToSearch: FuzzyType, private val typeToSearch: FuzzyType,
private val searchScope: SearchScope, private val searchScope: SearchScope,
private val project: Project,
private val suspiciousExpressionHandler: (KtExpression) -> Unit, private val suspiciousExpressionHandler: (KtExpression) -> Unit,
private val suspiciousScopeHandler: (SearchScope) -> Unit, private val suspiciousScopeHandler: (SearchScope) -> Unit
private val resolutionFacade: ResolutionFacade
) { ) {
enum class Mode { enum class Mode {
ALWAYS_SMART, ALWAYS_SMART,
@@ -89,9 +92,20 @@ class ExpressionsOfTypeProcessor(
else -> fqName else -> fqName
} }
} }
}
private val project = resolutionFacade.project private fun SearchScope.isEmpty(): Boolean {
when (this) {
GlobalSearchScope.EMPTY_SCOPE -> return true
is GlobalSearchScope -> {
val rootManager = ProjectRootManager.getInstance(project!!)
return rootManager.fileIndex.iterateContent { it.isDirectory || it !in this }
}
else -> return (this as LocalSearchScope).scope.isEmpty()
}
}
}
// note: a Task must define equals & hashCode! // note: a Task must define equals & hashCode!
private interface Task { private interface Task {
@@ -104,6 +118,8 @@ class ExpressionsOfTypeProcessor(
private val scopesToUsePlainSearch = LinkedHashMap<KtFile, ArrayList<PsiElement>>() private val scopesToUsePlainSearch = LinkedHashMap<KtFile, ArrayList<PsiElement>>()
fun run() { fun run() {
if (searchScope.restrictToKotlinSources().isEmpty()) return // optimization
val classDescriptor = typeToSearch.type.constructor.declarationDescriptor ?: return val classDescriptor = typeToSearch.type.constructor.declarationDescriptor ?: return
val classDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, classDescriptor) val classDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, classDescriptor)
val psiClass = when (classDeclaration) { val psiClass = when (classDeclaration) {
@@ -123,7 +139,9 @@ class ExpressionsOfTypeProcessor(
processTasks() processTasks()
val scopeElements = scopesToUsePlainSearch.values.flatMap { it }.toTypedArray() val scopeElements = scopesToUsePlainSearch.values.flatMap { it }.toTypedArray()
suspiciousScopeHandler(LocalSearchScope(scopeElements)) if (scopeElements.isNotEmpty()) {
suspiciousScopeHandler(LocalSearchScope(scopeElements))
}
} }
private fun addTask(task: Task) { private fun addTask(task: Task) {
@@ -439,6 +457,7 @@ class ExpressionsOfTypeProcessor(
if (psiClass != null) { if (psiClass != null) {
testLog?.add("Resolved java class to descriptor: ${psiClass.qualifiedName}") testLog?.add("Resolved java class to descriptor: ${psiClass.qualifiedName}")
val resolutionFacade = KotlinCacheService.getInstance(project).getResolutionFacadeByFile(psiClass.containingFile, JvmPlatform)
val classDescriptor = psiClass.resolveToDescriptor(resolutionFacade) val classDescriptor = psiClass.resolveToDescriptor(resolutionFacade)
if (classDescriptor != null && SingleAbstractMethodUtils.getSingleAbstractMethodOrNull(classDescriptor) != null) { if (classDescriptor != null && SingleAbstractMethodUtils.getSingleAbstractMethodOrNull(classDescriptor) != null) {
addSamInterfaceToProcess(psiClass) addSamInterfaceToProcess(psiClass)
@@ -541,18 +560,23 @@ class ExpressionsOfTypeProcessor(
private fun usePlainSearch(scope: KtElement) { private fun usePlainSearch(scope: KtElement) {
val file = scope.getContainingKtFile() val file = scope.getContainingKtFile()
val restricted = LocalSearchScope(scope).intersectWith(searchScope) as LocalSearchScope val restricted = LocalSearchScope(scope).intersectWith(searchScope)
ScopeLoop@ if (restricted is LocalSearchScope) {
for (element in restricted.scope) { ScopeLoop@
val prevElements = scopesToUsePlainSearch.getOrPut(file) { ArrayList() } for (element in restricted.scope) {
for ((index, prevElement) in prevElements.withIndex()) { val prevElements = scopesToUsePlainSearch.getOrPut(file) { ArrayList() }
if (prevElement.isAncestor(element, strict = false)) continue@ScopeLoop for ((index, prevElement) in prevElements.withIndex()) {
if (element.isAncestor(prevElement)) { if (prevElement.isAncestor(element, strict = false)) continue@ScopeLoop
prevElements[index] = element if (element.isAncestor(prevElement)) {
continue@ScopeLoop prevElements[index] = element
continue@ScopeLoop
}
} }
prevElements.add(element)
} }
prevElements.add(element) }
else {
assert(restricted == GlobalSearchScope.EMPTY_SCOPE)
} }
} }
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
class IndexingOperatorReferenceSearcher( class IndexingOperatorReferenceSearcher(
targetFunction: KtFunction, targetFunction: PsiElement,
searchScope: SearchScope, searchScope: SearchScope,
consumer: Processor<PsiReference>, consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector, optimizer: SearchRequestCollector,
@@ -17,38 +17,22 @@
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.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.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(
targetFunction: KtFunction, targetFunction: PsiElement,
searchScope: SearchScope, searchScope: SearchScope,
consumer: Processor<PsiReference>, consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector optimizer: SearchRequestCollector
) : OperatorReferenceSearcher<KtCallExpression>(targetFunction, searchScope, consumer, optimizer, wordsToSearch = emptyList()) { ) : OperatorReferenceSearcher<KtCallExpression>(targetFunction, searchScope, consumer, optimizer, wordsToSearch = emptyList()) {
companion object {
fun runForPsiMethod(
invokeFunction: PsiMethod,
scope: SearchScope,
consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector
) {
if (invokeFunction !is KtLightMethod) return //TODO
val ktFunction = invokeFunction.kotlinOrigin as? KtFunction ?: return //TODO?
InvokeOperatorReferenceSearcher(ktFunction, scope, consumer, optimizer).run()
}
}
override fun processSuspiciousExpression(expression: KtExpression) { override fun processSuspiciousExpression(expression: KtExpression) {
val callExpression = expression.parent as? KtCallExpression ?: return val callExpression = expression.parent as? KtCallExpression ?: return
processReferenceElement(callExpression) processReferenceElement(callExpression)
@@ -22,10 +22,9 @@ 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.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.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.getJavaOrKotlinMemberDescriptor
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.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinRequestResultProcessor import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinRequestResultProcessor
@@ -44,7 +43,7 @@ import org.jetbrains.kotlin.util.isValidOperator
import java.util.* import java.util.*
abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>( abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
private val targetDeclaration: KtDeclaration, protected val targetDeclaration: PsiElement,
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,
@@ -70,47 +69,46 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
} }
companion object { companion object {
fun createForKtFunction( fun create(
function: KtFunction, declaration: PsiElement,
searchScope: SearchScope, searchScope: SearchScope,
consumer: Processor<PsiReference>, consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector, optimizer: SearchRequestCollector,
options: KotlinReferencesSearchOptions options: KotlinReferencesSearchOptions
): OperatorReferenceSearcher<*>? { ): OperatorReferenceSearcher<*>? {
val name = function.name ?: return null val functionName = when (declaration) {
return create(function, name, searchScope, consumer, optimizer, options) is KtNamedFunction -> declaration.name
} is PsiMethod -> declaration.name
else -> null
} ?: return null
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 if (!Name.isValidIdentifier(functionName)) return null
val name = Name.identifier(functionName) val name = Name.identifier(functionName)
val declarationToUse = if (declaration is KtLightMethod) {
declaration.kotlinOrigin ?: return null
}
else {
declaration
}
return create(declarationToUse, name, consumer, optimizer, options, searchScope)
}
private fun create(
declaration: PsiElement,
name: Name,
consumer: Processor<PsiReference>,
optimizer: SearchRequestCollector,
options: KotlinReferencesSearchOptions,
searchScope: SearchScope
): OperatorReferenceSearcher<*>? {
if (isComponentLike(name)) { if (isComponentLike(name)) {
if (!options.searchForComponentConventions) return null if (!options.searchForComponentConventions) return null
return DestructuringDeclarationReferenceSearcher(declaration, searchScope, consumer, optimizer) return DestructuringDeclarationReferenceSearcher(declaration, searchScope, consumer, optimizer)
} }
if (!options.searchForOperatorConventions) return null if (!options.searchForOperatorConventions) return null
if (declaration !is KtFunction) return null
if (name == OperatorNameConventions.INVOKE) { if (name == OperatorNameConventions.INVOKE) {
return InvokeOperatorReferenceSearcher(declaration, searchScope, consumer, optimizer) return InvokeOperatorReferenceSearcher(declaration, searchScope, consumer, optimizer)
@@ -148,16 +146,28 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
return null return null
} }
private object SearchesInProgress : ThreadLocal<HashSet<KtDeclaration>>() { //TODO: check no light elements here
override fun initialValue() = HashSet<KtDeclaration>() private object SearchesInProgress : ThreadLocal<HashSet<PsiElement>>() {
override fun initialValue() = HashSet<PsiElement>()
} }
} }
open protected fun resolveTargetToDescriptor(): FunctionDescriptor? {
return when (targetDeclaration) {
is KtDeclaration -> targetDeclaration.resolveToDescriptor()
is PsiMember -> targetDeclaration.getJavaOrKotlinMemberDescriptor()
else -> null
} as? FunctionDescriptor
}
open fun run() { open fun run() {
val inProgress = SearchesInProgress.get() val inProgress = SearchesInProgress.get()
if (!inProgress.add(targetDeclaration)) return //TODO: it's not quite correct if (!inProgress.add(targetDeclaration)) return //TODO: it's not quite correct
try { try {
val descriptor = resolveTargetToDescriptor() ?: return
if (!descriptor.isValidOperator()) return
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
@@ -168,9 +178,6 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
return return
} }
val descriptor = targetDeclaration.resolveToDescriptor() as? CallableDescriptor ?: return
if (descriptor is FunctionDescriptor && !descriptor.isValidOperator()) return
val dataType = if (descriptor.isExtension) { val dataType = if (descriptor.isExtension) {
descriptor.fuzzyExtensionReceiverType()!! descriptor.fuzzyExtensionReceiverType()!!
} }
@@ -182,9 +189,9 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
ExpressionsOfTypeProcessor( ExpressionsOfTypeProcessor(
dataType, dataType,
searchScope, searchScope,
project,
suspiciousExpressionHandler = { expression -> processSuspiciousExpression(expression) }, suspiciousExpressionHandler = { expression -> processSuspiciousExpression(expression) },
suspiciousScopeHandler = { searchScope -> doPlainSearch(searchScope) }, suspiciousScopeHandler = { searchScope -> doPlainSearch(searchScope) }
resolutionFacade = targetDeclaration.getResolutionFacade()
).run() ).run()
} }
finally { finally {
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.psi.KtUnaryExpression
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
class UnaryOperatorReferenceSearcher( class UnaryOperatorReferenceSearcher(
targetFunction: KtFunction, targetFunction: PsiElement,
private val operationToken: KtSingleValueToken, private val operationToken: KtSingleValueToken,
searchScope: SearchScope, searchScope: SearchScope,
consumer: Processor<PsiReference>, consumer: Processor<PsiReference>,
@@ -22,8 +22,11 @@ import com.intellij.find.findUsages.AbstractFindUsagesDialog
import com.intellij.find.findUsages.FindUsagesOptions import com.intellij.find.findUsages.FindUsagesOptions
import com.intellij.find.impl.FindManagerImpl import com.intellij.find.impl.FindManagerImpl
import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.fileTypes.FileTypeManager
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference import com.intellij.psi.PsiReference
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.SearchScope import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.searches.MethodReferencesSearch import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.psi.search.searches.ReferencesSearch
@@ -32,6 +35,7 @@ import com.intellij.util.*
import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.findUsages.KotlinCallableFindUsagesOptions import org.jetbrains.kotlin.idea.findUsages.KotlinCallableFindUsagesOptions
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory
@@ -44,11 +48,10 @@ import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDetector import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDetector
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
import org.jetbrains.kotlin.idea.search.usagesSearch.dataClassComponentFunction
import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.KtCallableDeclaration import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors
import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.resolve.source.getPsi
@@ -131,9 +134,7 @@ 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 searchForOperatorConventions for ReferencesSearch because they will be searched by MethodReferencesSearch
val kotlinSearchOptions = createKotlinReferencesSearchOptions(options) val kotlinSearchOptions = createKotlinReferencesSearchOptions(options)
.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))) {
@@ -141,7 +142,12 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration>
} }
for (psiMethod in runReadAction { element.toLightMethods() }) { for (psiMethod in runReadAction { element.toLightMethods() }) {
with(applyQueryFilters(element, options, MethodReferencesSearch.search(psiMethod, options.searchScope, true))) { var searchScope = options.searchScope
// TODO: very bad code!! ReferencesSearch does not work correctly for constructors and annotation parameters
if (element is KtNamedFunction || (element is KtParameter && element.dataClassComponentFunction() != null)) {
searchScope = searchScope.excludeKotlinSources()
}
with(applyQueryFilters(element, options, MethodReferencesSearch.search(psiMethod, searchScope, true))) {
if (!forEach(referenceProcessor)) return false if (!forEach(referenceProcessor)) return false
} }
} }
@@ -156,6 +162,21 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration>
return true return true
} }
private fun SearchScope.excludeKotlinSources(): SearchScope {
if (this is GlobalSearchScope) {
val fileTypes = FileTypeManager.getInstance().registeredFileTypes.filter { it != KotlinFileType.INSTANCE }.toTypedArray()
return GlobalSearchScope.getScopeRestrictedByFileTypes(this, *fileTypes)
}
else {
this as LocalSearchScope
val filteredElements = scope.filter { it.containingFile !is KtFile }
return if (filteredElements.isNotEmpty())
LocalSearchScope(filteredElements.toTypedArray())
else
GlobalSearchScope.EMPTY_SCOPE
}
}
protected abstract fun createKotlinReferencesSearchOptions(options: FindUsagesOptions): KotlinReferencesSearchOptions protected abstract fun createKotlinReferencesSearchOptions(options: FindUsagesOptions): KotlinReferencesSearchOptions
protected abstract fun applyQueryFilters(element: PsiElement, protected abstract fun applyQueryFilters(element: PsiElement,
@@ -35,7 +35,7 @@ class KotlinConventionMethodReferencesSearcher() : QueryExecutorBase<PsiReferenc
if (!Name.isValidIdentifier(name)) return if (!Name.isValidIdentifier(name)) return
val identifier = Name.identifier(name) val identifier = Name.identifier(name)
val operatorSearcher = OperatorReferenceSearcher.createForPsiMethod( val operatorSearcher = OperatorReferenceSearcher.create(
method, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer, KotlinReferencesSearchOptions.Empty) method, queryParameters.effectiveSearchScope, consumer, queryParameters.optimizer, KotlinReferencesSearchOptions.Empty)
if (operatorSearcher != null) { if (operatorSearcher != null) {
operatorSearcher.run() operatorSearcher.run()
@@ -0,0 +1,3 @@
Resolved in
Searched references to Small
Searched references to parameter small of some(small: Small) in Kotlin files