[FIR IDE] Separate find usages logic from descriptors

This commit is contained in:
Igor Yakovlev
2020-08-21 01:04:35 +03:00
parent b102042dd8
commit e30f09d513
76 changed files with 1422 additions and 661 deletions
@@ -79,7 +79,6 @@ wrapped.into.a.reference.object.to.be.modified.when.captured.in.a.closure=Wrappe
smart.cast.to.0.for.1.call=Smart cast to {0} (for {1} call)
smart.cast.to.0=Smart cast to {0}
replace.overloaded.operator.with.function.call=Replace overloaded operator with function call
searching.for.implicit.usages=Searching for implicit usages...
class.initializer=<class initializer>
object.0=object{0}
show.non.public=Show non-public
@@ -16,14 +16,14 @@
package org.jetbrains.kotlin.idea.search.usagesSearch
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNamedElement
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.LightClassUtil.PropertyAccessorsPsiMethods
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.caches.resolve.resolveToParameterDescriptorIfAny
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -31,6 +31,11 @@ import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.resolve.source.getPsi
import java.util.*
fun PsiNamedElement.getAccessorNames(readable: Boolean = true, writable: Boolean = true): List<String> {
@@ -87,3 +92,26 @@ fun KtParameter.isDataClassProperty(): Boolean {
return this.containingClassOrObject?.hasModifier(KtTokens.DATA_KEYWORD) ?: false
}
fun getTopMostOverriddenElementsToHighlight(target: PsiElement): List<PsiElement> {
val callableDescriptor = (target as? KtCallableDeclaration)?.resolveToDescriptorIfAny() as? CallableDescriptor
val descriptorsToHighlight = if (callableDescriptor is ParameterDescriptor)
listOf(callableDescriptor)
else
callableDescriptor?.findOriginalTopMostOverriddenDescriptors() ?: emptyList()
return descriptorsToHighlight.mapNotNull { it.source.getPsi() }.filter { it != target }
}
val KtDeclaration.descriptor: DeclarationDescriptor?
get() = if (this is KtParameter) this.descriptor else this.resolveToDescriptorIfAny(BodyResolveMode.FULL)
val KtParameter.descriptor: ValueParameterDescriptor?
get() = this.resolveToParameterDescriptorIfAny(BodyResolveMode.FULL)
fun isCallReceiverRefersToCompanionObject(element: KtElement, companionObject: KtObjectDeclaration): Boolean {
val companionObjectDescriptor = companionObject.descriptor
val bindingContext = element.analyze()
val resolvedCall = bindingContext[BindingContext.CALL, element]?.getResolvedCall(bindingContext) ?: return false
return (resolvedCall.dispatchReceiver as? ImplicitClassReceiver)?.declarationDescriptor == companionObjectDescriptor ||
(resolvedCall.extensionReceiver as? ImplicitClassReceiver)?.declarationDescriptor == companionObjectDescriptor
}
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.idea.core.extension.KotlinIndicesHelperExtension
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.search.excludeKotlinSources
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.idea.stubindex.*
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
@@ -18,6 +18,7 @@ dependencies {
compileOnly(project(":kotlin-reflect-api"))
compileOnly(intellijCoreDep())
compileOnly(intellijDep())
compileOnly(project(":compiler:light-classes"))
Platform[191].orLower {
compileOnly(intellijDep()) { includeJars("java-api", "java-impl") }
@@ -29,8 +30,14 @@ dependencies {
}
sourceSets {
"main" { projectDefault() }
"main" {
projectDefault()
resources.srcDirs(
"resources-en"
)
}
"test" { projectDefault() }
}
testsJar()
@@ -0,0 +1,40 @@
find.declaration.implementing.methods.checkbox=&Implementing functions
find.declaration.overriding.methods.checkbox=Over&riding functions
find.declaration.implementing.properties.checkbox=&Implementing properties
find.declaration.overriding.properties.checkbox=Over&riding properties
find.declaration.property.readers.checkbox=Readers
find.declaration.property.writers.checkbox=Writers
find.declaration.include.overloaded.methods.checkbox=Include o&verloaded functions and extensions
find.declaration.functions.usages.checkbox=Usages of &functions
find.declaration.properties.usages.checkbox=Usages of &properties
find.declaration.constructor.usages.checkbox=Usages of &constructor
find.declaration.derived.classes.checkbox=&Derived classes
find.declaration.derived.interfaces.checkbox=Derived &interfaces
find.usages.class=class
find.usages.companion.object=companion object
find.usages.constructor=constructor
find.usages.facade.class=facade class
find.usages.for.property={0} for property
find.usages.function=function
find.usages.getter=getter
find.usages.import.alias=import alias
find.usages.interface=interface
find.usages.label=label
find.usages.lambda=lambda
find.usages.object=object
find.usages.parameter=parameter
find.usages.property.accessor=property accessor
find.usages.property=property
find.usages.setter=setter
find.usages.type.alias=type alias
find.usages.type.parameter=type parameter
find.usages.variable=variable
find.usages.checkbox.name.expected.classes=Expected classes
find.usages.class.name.anonymous=Anonymous
find.usages.checkbox.name.expected.functions=Expected functions
find.usages.text.find.usages.for.data.class.components.and.destruction.declarations=<p>Find usages for data class components and destructuring declarations<br/>could be <a href="{0}">disabled once</a> or <a href="{1}">disabled for a project</a>.</p>
find.usages.tool.tip.text.disable.search.for.data.class.components.and.destruction.declarations.project.wide.setting=Disable search for data class components and destructuring declarations. (Project wide setting)
find.usages.checkbox.text.fast.data.class.component.search=Fast data class component search
find.usages.checkbox.name.expected.properties=Expected properties
find.usages.action.text.find.usages.of=find usages of
@@ -0,0 +1 @@
searching.for.implicit.usages=Searching for implicit usages...
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea
import com.intellij.DynamicBundle
abstract class AbstractKotlinBundleIndependent protected constructor(pathToBundle: String) : DynamicBundle(pathToBundle) {
protected fun String.withHtml(): String = "<html>$this</html>"
}
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea
import com.intellij.AbstractBundle
abstract class AbstractKotlinBundleIndependent protected constructor(pathToBundle: String) : AbstractBundle(pathToBundle) {
protected fun String.withHtml(): String = "<html>$this</html>"
}
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.PropertyKey
@NonNls
private const val BUNDLE = "messages.KotlinBundleIndependent"
//TODO Copy-pasted from KotlinBundle.kt
object KotlinBundleIndependent : AbstractKotlinBundleIndependent(BUNDLE) {
@JvmStatic
fun message(@NonNls @PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): String = getMessage(key, *params)
@JvmStatic
fun htmlMessage(@NonNls @PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): String =
getMessage(key, *params).withHtml()
@JvmStatic
fun lazyMessage(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): () -> String = { getMessage(key, *params) }
}
@@ -0,0 +1,23 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.PropertyKey
@NonNls
private const val BUNDLE = "messages.KotlinIdeaAnalysisBundleIndependent"
object KotlinIdeaAnalysisBundleIndependent : AbstractKotlinBundleIndependent(BUNDLE) {
@JvmStatic
fun message(@NonNls @PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): String = getMessage(key, *params)
@JvmStatic
fun htmlMessage(@NonNls @PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): String =
getMessage(key, *params).withHtml()
@JvmStatic
fun lazyMessage(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): () -> String = { getMessage(key, *params) }
}
@@ -0,0 +1,93 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.asJava
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.impl.light.AbstractLightClass
import com.intellij.psi.impl.light.LightMethod
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
interface LightClassProvider {
fun getLightFieldForCompanionObject(companionObject: KtClassOrObject): PsiField?
fun getLightClassMethods(function: KtFunction): List<PsiMethod>
//getLightClassPropertyMethods.allDeclarations
fun getLightClassParameterDeclarations(parameter: KtParameter): List<PsiNamedElement>
//getLightClassPropertyMethods.allDeclarations
fun getLightClassPropertyDeclarations(property: KtProperty): List<PsiNamedElement>
fun toLightClassWithBuiltinMapping(classOrObject: KtClassOrObject): PsiClass?
fun toLightMethods(psiElement: PsiElement): List<PsiMethod>
fun toLightClass(classOrObject: KtClassOrObject): KtLightClass?
fun toLightElements(ktElement: KtElement): List<PsiNamedElement>
fun createKtFakeLightClass(kotlinOrigin: KtClassOrObject): PsiClass
fun getRepresentativeLightMethod(psiElement: PsiElement): PsiMethod?
fun isKtFakeLightClass(psiClass: PsiClass): Boolean
fun createKtFakeLightMethod(ktDeclaration: KtNamedDeclaration): PsiMethod?
companion object {
fun getInstance(project: Project): LightClassProvider {
return ServiceManager.getService(project, LightClassProvider::class.java)
}
fun providedGetLightFieldForCompanionObject(companionObject: KtClassOrObject): PsiField? =
getInstance(companionObject.project).getLightFieldForCompanionObject(companionObject)
fun providedGetLightClassMethods(function: KtFunction): List<PsiMethod> =
getInstance(function.project).getLightClassMethods(function)
//getLightClassPropertyMethods.allDeclarations
fun providedGetLightClassParameterDeclarations(parameter: KtParameter): List<PsiNamedElement> =
getInstance(parameter.project).getLightClassParameterDeclarations(parameter)
//getLightClassPropertyMethods.allDeclarations
fun providedGetLightClassPropertyDeclarations(property: KtProperty): List<PsiNamedElement> =
getInstance(property.project).getLightClassPropertyDeclarations(property)
fun KtClassOrObject.providedToLightClassWithBuiltinMapping(): PsiClass? =
getInstance(project).toLightClassWithBuiltinMapping(this)
fun PsiElement.providedToLightMethods(): List<PsiMethod> =
getInstance(project).toLightMethods(this)
fun KtClassOrObject.providedToLightClass(): KtLightClass? =
getInstance(project).toLightClass(this)
fun KtElement.providedToLightElements(): List<PsiNamedElement> =
getInstance(project).toLightElements(this)
fun providedCreateKtFakeLightClass(kotlinOrigin: KtClassOrObject): PsiClass? =
getInstance(kotlinOrigin.project).createKtFakeLightClass(kotlinOrigin)
fun PsiClass.providedIsKtFakeLightClass(): Boolean =
getInstance(project).isKtFakeLightClass(this)
fun providedCreateKtFakeLightMethod(ktDeclaration: KtNamedDeclaration): PsiMethod? =
getInstance(ktDeclaration.project).createKtFakeLightMethod(ktDeclaration)
fun PsiElement.providedGetRepresentativeLightMethod(): PsiMethod? =
getInstance(project).getRepresentativeLightMethod(this)
}
}
@@ -0,0 +1,229 @@
/*
* 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.findUsages
import com.intellij.codeInsight.highlighting.HighlightUsagesDescriptionLocation
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.ElementDescriptionLocation
import com.intellij.psi.ElementDescriptionProvider
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNamedElement
import com.intellij.refactoring.util.CommonRefactoringUtil
import com.intellij.refactoring.util.RefactoringDescriptionLocation
import com.intellij.usageView.UsageViewLongNameLocation
import com.intellij.usageView.UsageViewShortNameLocation
import com.intellij.usageView.UsageViewTypeLocation
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.idea.KotlinBundleIndependent
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
open class KotlinElementDescriptionProviderBase : ElementDescriptionProvider {
private tailrec fun KtNamedDeclaration.parentForFqName(): KtNamedDeclaration? {
val parent = getStrictParentOfType<KtNamedDeclaration>() ?: return null
if (parent is KtProperty && parent.isLocal) return parent.parentForFqName()
return parent
}
private fun KtNamedDeclaration.name() = nameAsName ?: Name.special("<no name provided>")
private fun KtNamedDeclaration.fqName(): FqNameUnsafe {
containingClassOrObject?.let {
if (it is KtObjectDeclaration && it.isCompanion()) {
return it.fqName().child(name())
}
return FqNameUnsafe("${it.name()}.${name()}")
}
val internalSegments = generateSequence(this) { it.parentForFqName() }
.filterIsInstance<KtNamedDeclaration>()
.map { it.name ?: "<no name provided>" }
.toList()
.asReversed()
val packageSegments = containingKtFile.packageFqName.pathSegments()
return FqNameUnsafe((packageSegments + internalSegments).joinToString("."))
}
private fun KtTypeReference.renderShort(): String {
return accept(
object : KtVisitor<String, Unit>() {
private val visitor get() = this
override fun visitTypeReference(typeReference: KtTypeReference, data: Unit): String {
val typeText = typeReference.typeElement?.accept(this, data) ?: "???"
return if (typeReference.hasParentheses()) "($typeText)" else typeText
}
override fun visitDynamicType(type: KtDynamicType, data: Unit) = type.text
override fun visitFunctionType(type: KtFunctionType, data: Unit): String {
return buildString {
type.receiverTypeReference?.let { append(it.accept(visitor, data)).append('.') }
type.parameters.joinTo(this, prefix = "(", postfix = ")") { it.accept(visitor, data) }
append(" -> ")
append(type.returnTypeReference?.accept(visitor, data) ?: "???")
}
}
override fun visitNullableType(nullableType: KtNullableType, data: Unit): String {
val innerTypeText = nullableType.innerType?.accept(this, data) ?: return "???"
return "$innerTypeText?"
}
override fun visitSelfType(type: KtSelfType, data: Unit) = type.text
override fun visitUserType(type: KtUserType, data: Unit): String {
return buildString {
append(type.referencedName ?: "???")
val arguments = type.typeArguments
if (arguments.isNotEmpty()) {
arguments.joinTo(this, prefix = "<", postfix = ">") {
it.typeReference?.accept(visitor, data) ?: it.text
}
}
}
}
override fun visitParameter(parameter: KtParameter, data: Unit) = parameter.typeReference?.accept(this, data) ?: "???"
},
Unit
)
}
//TODO Copied from stringUtil.kt
private fun String.collapseSpaces(): String {
val builder = StringBuilder()
var haveSpaces = false
for (c in this) {
if (c.isWhitespace()) {
haveSpaces = true
} else {
if (haveSpaces) {
builder.append(" ")
haveSpaces = false
}
builder.append(c)
}
}
return builder.toString()
}
//TODO: Implement in FIR
protected open val PsiElement.isRenameJavaSyntheticPropertyHandler get() = false
protected open val PsiElement.isRenameKotlinPropertyProcessor get() = false
override fun getElementDescription(element: PsiElement, location: ElementDescriptionLocation): String? {
val shouldUnwrap = location !is UsageViewShortNameLocation && location !is UsageViewLongNameLocation
val targetElement = if (shouldUnwrap) element.unwrapped ?: element else element
fun elementKind() = when (targetElement) {
is KtClass -> if (targetElement.isInterface())
KotlinBundleIndependent.message("find.usages.interface")
else
KotlinBundleIndependent.message("find.usages.class")
is KtObjectDeclaration -> if (targetElement.isCompanion())
KotlinBundleIndependent.message("find.usages.companion.object")
else
KotlinBundleIndependent.message("find.usages.object")
is KtNamedFunction -> KotlinBundleIndependent.message("find.usages.function")
is KtPropertyAccessor -> KotlinBundleIndependent.message(
"find.usages.for.property",
(if (targetElement.isGetter)
KotlinBundleIndependent.message("find.usages.getter")
else
KotlinBundleIndependent.message("find.usages.setter"))
) + " "
is KtFunctionLiteral -> KotlinBundleIndependent.message("find.usages.lambda")
is KtPrimaryConstructor, is KtSecondaryConstructor -> KotlinBundleIndependent.message("find.usages.constructor")
is KtProperty -> if (targetElement.isLocal)
KotlinBundleIndependent.message("find.usages.variable")
else
KotlinBundleIndependent.message("find.usages.property")
is KtTypeParameter -> KotlinBundleIndependent.message("find.usages.type.parameter")
is KtParameter -> KotlinBundleIndependent.message("find.usages.parameter")
is KtDestructuringDeclarationEntry -> KotlinBundleIndependent.message("find.usages.variable")
is KtTypeAlias -> KotlinBundleIndependent.message("find.usages.type.alias")
is KtLabeledExpression -> KotlinBundleIndependent.message("find.usages.label")
is KtImportAlias -> KotlinBundleIndependent.message("find.usages.import.alias")
is KtLightClassForFacade -> KotlinBundleIndependent.message("find.usages.facade.class")
else -> {
//TODO Implement in FIR
when {
targetElement.isRenameJavaSyntheticPropertyHandler -> KotlinBundleIndependent.message("find.usages.property")
targetElement.isRenameKotlinPropertyProcessor -> KotlinBundleIndependent.message("find.usages.property.accessor")
else -> null
}
}
}
val namedElement = if (targetElement is KtPropertyAccessor) {
targetElement.parent as? KtProperty
} else targetElement as? PsiNamedElement
@Suppress("FoldInitializerAndIfToElvis")
if (namedElement == null) {
return if (targetElement is KtElement) "'" + StringUtil.shortenTextWithEllipsis(
targetElement.text.collapseSpaces(),
53,
0
) + "'" else null
}
if (namedElement.language != KotlinLanguage.INSTANCE) return null
return when (location) {
is UsageViewTypeLocation -> elementKind()
is UsageViewShortNameLocation, is UsageViewLongNameLocation -> namedElement.name
is RefactoringDescriptionLocation -> {
val kind = elementKind() ?: return null
if (namedElement !is KtNamedDeclaration) return null
val renderFqName = location.includeParent() &&
namedElement !is KtTypeParameter &&
namedElement !is KtParameter &&
namedElement !is KtConstructor<*>
val desc = when (namedElement) {
is KtFunction -> {
val baseText = buildString {
append(namedElement.name ?: "")
namedElement.valueParameters.joinTo(this, prefix = "(", postfix = ")") {
(if (it.isVarArg) "vararg " else "") + (it.typeReference?.renderShort() ?: "")
}
namedElement.receiverTypeReference?.let { append(" on ").append(it.renderShort()) }
}
val parentFqName = if (renderFqName) namedElement.fqName().parent() else null
if (parentFqName?.isRoot != false) baseText else "${parentFqName.asString()}.$baseText"
}
else -> (if (renderFqName) namedElement.fqName().asString() else namedElement.name) ?: ""
}
"$kind ${CommonRefactoringUtil.htmlEmphasize(desc)}"
}
is HighlightUsagesDescriptionLocation -> {
val kind = elementKind() ?: return null
if (namedElement !is KtNamedDeclaration) return null
"$kind ${namedElement.name}"
}
else -> null
}
}
}
@@ -27,15 +27,15 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.psi.PsiElement
import com.intellij.psi.search.searches.OverridingMethodsSearch
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightMethods
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.core.isOverridable
import org.jetbrains.kotlin.idea.KotlinBundleIndependent
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesSupport.Companion.checkSuperMethods
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.isOverridable
import org.jetbrains.kotlin.idea.findUsages.handlers.DelegatingFindMemberUsagesHandler
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindMemberUsagesHandler
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinTypeParameterFindUsagesHandler
import org.jetbrains.kotlin.idea.refactoring.checkSuperMethods
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
@@ -85,14 +85,14 @@ class KotlinFindUsagesHandlerFactory(project: Project) : FindUsagesHandlerFactor
val declarationsToSearch = checkSuperMethods(
element,
null,
KotlinBundle.message("find.usages.action.text.find.usages.of")
KotlinBundleIndependent.message("find.usages.action.text.find.usages.of")
)
return handlerForMultiple(element, declarationsToSearch)
}
val function = element.ownerFunction
if (function != null && function.isOverridable()) {
val psiMethod = function.toLightMethods().singleOrNull()
val psiMethod = function.providedToLightMethods().singleOrNull()
if (psiMethod != null) {
val hasOverridden = OverridingMethodsSearch.search(psiMethod).any()
if (hasOverridden && askWhetherShouldSearchForParameterInOverridingMethods(element)) {
@@ -122,7 +122,7 @@ class KotlinFindUsagesHandlerFactory(project: Project) : FindUsagesHandlerFactor
val declarationsToSearch = checkSuperMethods(
declaration,
null,
KotlinBundle.message("find.usages.action.text.find.usages.of")
KotlinBundleIndependent.message("find.usages.action.text.find.usages.of")
)
return handlerForMultiple(declaration, declarationsToSearch)
@@ -0,0 +1,81 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.findUsages
import com.intellij.lang.cacheBuilder.WordsScanner
import com.intellij.lang.findUsages.FindUsagesProvider
import com.intellij.lang.java.JavaFindUsagesProvider
import com.intellij.psi.*
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.idea.KotlinBundleIndependent
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter
open class KotlinFindUsagesProviderBase : FindUsagesProvider {
private val javaProvider by lazy { JavaFindUsagesProvider() }
override fun canFindUsagesFor(psiElement: PsiElement): Boolean =
psiElement is KtNamedDeclaration
override fun getWordsScanner(): WordsScanner? = KotlinWordsScanner()
override fun getHelpId(psiElement: PsiElement): String? = null
override fun getType(element: PsiElement): String {
return when (element) {
is KtNamedFunction -> KotlinBundleIndependent.message("find.usages.function")
is KtClass -> KotlinBundleIndependent.message("find.usages.class")
is KtParameter -> KotlinBundleIndependent.message("find.usages.parameter")
is KtProperty -> if (element.isLocal)
KotlinBundleIndependent.message("find.usages.variable")
else
KotlinBundleIndependent.message("find.usages.property")
is KtDestructuringDeclarationEntry -> KotlinBundleIndependent.message("find.usages.variable")
is KtTypeParameter -> KotlinBundleIndependent.message("find.usages.type.parameter")
is KtSecondaryConstructor -> KotlinBundleIndependent.message("find.usages.constructor")
is KtObjectDeclaration -> KotlinBundleIndependent.message("find.usages.object")
else -> ""
}
}
protected val KtDeclaration.containerDescription: String?
get() {
containingClassOrObject?.let { return getDescriptiveName(it) }
(parent as? KtFile)?.parent?.let { return getDescriptiveName(it) }
return null
}
override fun getDescriptiveName(element: PsiElement): String {
return when (element) {
is PsiDirectory, is PsiPackage, is PsiFile -> javaProvider.getDescriptiveName(element)
is KtClassOrObject -> {
if (element is KtObjectDeclaration && element.isObjectLiteral()) return "<unnamed>"
element.fqName?.asString() ?: element.name ?: "<unnamed>"
}
is KtProperty -> (element.name ?: "") + (element.containerDescription?.let { " of $it" } ?: "")
is KtFunction -> {
//TODO: Correct FIR implementation
return element.name?.let { "$it(...)" } ?: ""
}
is KtLabeledExpression -> element.getLabelName() ?: ""
is KtImportAlias -> element.name ?: ""
is KtLightElement<*, *> -> element.kotlinOrigin?.let { getDescriptiveName(it) } ?: ""
is KtParameter -> {
if (element.isPropertyParameter()) {
(element.name ?: "") + (element.containerDescription?.let { " of $it" } ?: "")
} else {
element.name ?: ""
}
}
is PsiNamedElement -> element.name ?: ""
else -> ""
}
}
override fun getNodeText(element: PsiElement, useFullName: Boolean): String =
getDescriptiveName(element)
}
@@ -0,0 +1,65 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.findUsages
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.annotations.Nls
import org.jetbrains.kotlin.psi.*
interface KotlinFindUsagesSupport {
companion object {
fun getInstance(project: Project): KotlinFindUsagesSupport {
return ServiceManager.getService(project, KotlinFindUsagesSupport::class.java)
}
val KtParameter.isDataClassComponentFunction: Boolean
get() = getInstance(project).isDataClassComponentFunction(this)
fun KtElement.isCallReceiverRefersToCompanionObject(companionObject: KtObjectDeclaration): Boolean =
getInstance(project).isCallReceiverRefersToCompanionObject(this, companionObject)
fun getTopMostOverriddenElementsToHighlight(target: PsiElement): List<PsiElement> =
getInstance(target.project).getTopMostOverriddenElementsToHighlight(target)
fun tryRenderDeclarationCompactStyle(declaration: KtDeclaration): String? =
getInstance(declaration.project).tryRenderDeclarationCompactStyle(declaration)
fun PsiReference.isConstructorUsage(ktClassOrObject: KtClassOrObject): Boolean =
getInstance(ktClassOrObject.project).isConstructorUsage(this, ktClassOrObject)
fun checkSuperMethods(
declaration: KtDeclaration,
ignore: Collection<PsiElement>?,
@Nls actionString: String
): List<PsiElement> = getInstance(declaration.project).checkSuperMethods(declaration, ignore, actionString)
fun sourcesAndLibraries(delegate: GlobalSearchScope, project: Project): GlobalSearchScope =
getInstance(project).sourcesAndLibraries(delegate, project)
}
fun isCallReceiverRefersToCompanionObject(element: KtElement, companionObject: KtObjectDeclaration): Boolean
fun isDataClassComponentFunction(element: KtParameter): Boolean
fun getTopMostOverriddenElementsToHighlight(target: PsiElement): List<PsiElement>
fun tryRenderDeclarationCompactStyle(declaration: KtDeclaration): String?
fun isConstructorUsage(psiReference: PsiReference, ktClassOrObject: KtClassOrObject): Boolean
fun checkSuperMethods(
declaration: KtDeclaration,
ignore: Collection<PsiElement>?,
@Nls actionString: String
): List<PsiElement>
fun sourcesAndLibraries(delegate: GlobalSearchScope, project: Project): GlobalSearchScope
}
@@ -31,19 +31,17 @@ import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.StateRestoringCheckBox;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.asJava.LightClassProvider;
import org.jetbrains.kotlin.asJava.LightClassUtilsKt;
import org.jetbrains.kotlin.idea.KotlinBundle;
import org.jetbrains.kotlin.idea.core.PsiModificationUtilsKt;
import org.jetbrains.kotlin.idea.KotlinBundleIndependent;
import org.jetbrains.kotlin.idea.findUsages.KotlinClassFindUsagesOptions;
import org.jetbrains.kotlin.idea.refactoring.RenderingUtilsKt;
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport;
import org.jetbrains.kotlin.psi.KtClass;
import org.jetbrains.kotlin.psi.KtClassOrObject;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import javax.swing.*;
import static org.jetbrains.kotlin.asJava.LightClassUtilsKt.toLightClass;
public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
private StateRestoringCheckBox constructorUsages;
private StateRestoringCheckBox derivedClasses;
@@ -66,7 +64,7 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
@NotNull
private static PsiClass getRepresentingPsiClass(@NotNull KtClassOrObject classOrObject) {
PsiClass lightClass = toLightClass(classOrObject);
PsiClass lightClass = LightClassProvider.Companion.providedToLightClass(classOrObject);
if (lightClass != null) return lightClass;
// TODO: Remove this code when light classes are generated for builtins
@@ -74,7 +72,7 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
String name = classOrObject.getName();
if (name == null || name.isEmpty()) {
name = KotlinBundle.message("find.usages.class.name.anonymous");
name = KotlinBundleIndependent.message("find.usages.class.name.anonymous");
}
PsiClass javaClass;
@@ -93,7 +91,7 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
//noinspection ConstantConditions
javaClass.getModifierList().setModifierProperty(
PsiModifier.FINAL,
!(classOrObject instanceof KtClass && PsiModificationUtilsKt.isInheritable((KtClass) classOrObject))
!(classOrObject instanceof KtClass && KotlinSearchUsagesSupport.Companion.isInheritable((KtClass) classOrObject))
);
javaClass.putUserData(ORIGINAL_CLASS, classOrObject);
@@ -109,31 +107,31 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
Utils.renameCheckbox(
findWhatPanel,
FindBundle.message("find.what.methods.usages.checkbox"),
KotlinBundle.message("find.declaration.functions.usages.checkbox")
KotlinBundleIndependent.message("find.declaration.functions.usages.checkbox")
);
Utils.renameCheckbox(
findWhatPanel,
FindBundle.message("find.what.fields.usages.checkbox"),
KotlinBundle.message("find.declaration.properties.usages.checkbox")
KotlinBundleIndependent.message("find.declaration.properties.usages.checkbox")
);
Utils.removeCheckbox(findWhatPanel, FindBundle.message("find.what.implementing.classes.checkbox"));
Utils.removeCheckbox(findWhatPanel, FindBundle.message("find.what.derived.interfaces.checkbox"));
Utils.removeCheckbox(findWhatPanel, FindBundle.message("find.what.derived.classes.checkbox"));
derivedClasses = addCheckboxToPanel(
KotlinBundle.message("find.declaration.derived.classes.checkbox"),
KotlinBundleIndependent.message("find.declaration.derived.classes.checkbox"),
getFindUsagesOptions().isDerivedClasses,
findWhatPanel,
true
);
derivedTraits = addCheckboxToPanel(
KotlinBundle.message("find.declaration.derived.interfaces.checkbox"),
KotlinBundleIndependent.message("find.declaration.derived.interfaces.checkbox"),
getFindUsagesOptions().isDerivedInterfaces,
findWhatPanel,
true
);
constructorUsages = addCheckboxToPanel(
KotlinBundle.message("find.declaration.constructor.usages.checkbox"),
KotlinBundleIndependent.message("find.declaration.constructor.usages.checkbox"),
getFindUsagesOptions().getSearchConstructorUsages(),
findWhatPanel,
true
@@ -165,7 +163,7 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
KotlinClassFindUsagesOptions options = getFindUsagesOptions();
if (isActual) {
expectedUsages = addCheckboxToPanel(
KotlinBundle.message("find.usages.checkbox.name.expected.classes"),
KotlinBundleIndependent.message("find.usages.checkbox.name.expected.classes"),
options.getSearchExpected(),
optionsPanel,
false
@@ -177,7 +175,7 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
public void configureLabelComponent(@NotNull SimpleColoredComponent coloredComponent) {
KtClassOrObject originalClass = getOriginalClass();
if (originalClass != null) {
coloredComponent.append(RenderingUtilsKt.formatClass(originalClass));
coloredComponent.append(KotlinSearchUsagesSupport.Companion.formatClass(originalClass));
}
}
@@ -29,9 +29,9 @@ import com.intellij.ui.StateRestoringCheckBox;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.asJava.LightClassUtilsKt;
import org.jetbrains.kotlin.asJava.elements.KtLightMethod;
import org.jetbrains.kotlin.idea.KotlinBundle;
import org.jetbrains.kotlin.idea.KotlinBundleIndependent;
import org.jetbrains.kotlin.idea.findUsages.KotlinFunctionFindUsagesOptions;
import org.jetbrains.kotlin.idea.refactoring.RenderingUtilsKt;
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport;
import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.kotlin.psi.KtNamedDeclaration;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
@@ -61,7 +61,7 @@ public class KotlinFindFunctionUsagesDialog extends FindMethodUsagesDialog {
@Override
public void configureLabelComponent(@NotNull SimpleColoredComponent coloredComponent) {
coloredComponent.append(RenderingUtilsKt.formatJavaOrLightMethod((PsiMethod) myPsiElement));
coloredComponent.append(KotlinSearchUsagesSupport.Companion.formatJavaOrLightMethod((PsiMethod) myPsiElement));
}
@Override
@@ -72,12 +72,12 @@ public class KotlinFindFunctionUsagesDialog extends FindMethodUsagesDialog {
Utils.renameCheckbox(
findWhatPanel,
FindBundle.message("find.what.implementing.methods.checkbox"),
KotlinBundle.message("find.declaration.implementing.methods.checkbox")
KotlinBundleIndependent.message("find.declaration.implementing.methods.checkbox")
);
Utils.renameCheckbox(
findWhatPanel,
FindBundle.message("find.what.overriding.methods.checkbox"),
KotlinBundle.message("find.declaration.overriding.methods.checkbox")
KotlinBundleIndependent.message("find.declaration.overriding.methods.checkbox")
);
}
@@ -91,10 +91,10 @@ public class KotlinFindFunctionUsagesDialog extends FindMethodUsagesDialog {
if (!Utils.renameCheckbox(
optionsPanel,
FindBundle.message("find.options.include.overloaded.methods.checkbox"),
KotlinBundle.message("find.declaration.include.overloaded.methods.checkbox")
KotlinBundleIndependent.message("find.declaration.include.overloaded.methods.checkbox")
)) {
addCheckboxToPanel(
KotlinBundle.message("find.declaration.include.overloaded.methods.checkbox"),
KotlinBundleIndependent.message("find.declaration.include.overloaded.methods.checkbox"),
FindSettings.getInstance().isSearchOverloadedMethods(),
optionsPanel,
false
@@ -110,7 +110,7 @@ public class KotlinFindFunctionUsagesDialog extends FindMethodUsagesDialog {
KotlinFunctionFindUsagesOptions options = getFindUsagesOptions();
if (isActual) {
expectedUsages = addCheckboxToPanel(
KotlinBundle.message("find.usages.checkbox.name.expected.functions"),
KotlinBundleIndependent.message("find.usages.checkbox.name.expected.functions"),
options.getSearchExpected(),
optionsPanel,
false
@@ -27,7 +27,7 @@ import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.StateRestoringCheckBox;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.KotlinBundle;
import org.jetbrains.kotlin.idea.KotlinBundleIndependent;
import org.jetbrains.kotlin.idea.findUsages.KotlinPropertyFindUsagesOptions;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*;
@@ -85,13 +85,13 @@ public class KotlinFindPropertyUsagesDialog extends JavaFindUsagesDialog<KotlinP
KotlinPropertyFindUsagesOptions options = getFindUsagesOptions();
readAccesses = addCheckboxToPanel(
KotlinBundle.message("find.declaration.property.readers.checkbox"),
KotlinBundleIndependent.message("find.declaration.property.readers.checkbox"),
options.isReadAccess,
findWhatPanel,
true
);
writeAccesses = addCheckboxToPanel(
KotlinBundle.message("find.declaration.property.writers.checkbox"),
KotlinBundleIndependent.message("find.declaration.property.writers.checkbox"),
options.isWriteAccess,
findWhatPanel,
true
@@ -116,8 +116,8 @@ public class KotlinFindPropertyUsagesDialog extends JavaFindUsagesDialog<KotlinP
if (isOpen || isAbstract) {
overrideUsages = addCheckboxToPanel(
isAbstract
? KotlinBundle.message("find.declaration.implementing.properties.checkbox")
: KotlinBundle.message("find.declaration.overriding.properties.checkbox"),
? KotlinBundleIndependent.message("find.declaration.implementing.properties.checkbox")
: KotlinBundleIndependent.message("find.declaration.overriding.properties.checkbox"),
FindSettings.getInstance().isSearchOverloadedMethods(),
optionsPanel,
false
@@ -127,7 +127,7 @@ public class KotlinFindPropertyUsagesDialog extends JavaFindUsagesDialog<KotlinP
KotlinPropertyFindUsagesOptions options = getFindUsagesOptions();
if (isActual) {
expectedUsages = addCheckboxToPanel(
KotlinBundle.message("find.usages.checkbox.name.expected.properties"),
KotlinBundleIndependent.message("find.usages.checkbox.name.expected.properties"),
options.getSearchExpected(),
optionsPanel,
false
@@ -136,8 +136,8 @@ public class KotlinFindPropertyUsagesDialog extends JavaFindUsagesDialog<KotlinP
if (isDataClassConstructorProperty(property)) {
JCheckBox dataClassComponentCheckBox =
new JCheckBox(KotlinBundle.message("find.usages.checkbox.text.fast.data.class.component.search"));
dataClassComponentCheckBox.setToolTipText(KotlinBundle.message(
new JCheckBox(KotlinBundleIndependent.message("find.usages.checkbox.text.fast.data.class.component.search"));
dataClassComponentCheckBox.setToolTipText(KotlinBundleIndependent.message(
"find.usages.tool.tip.text.disable.search.for.data.class.components.and.destruction.declarations.project.wide.setting"));
Project project = property.getProject();
dataClassComponentCheckBox.setSelected(getDisableComponentAndDestructionSearch(project));
@@ -18,10 +18,8 @@ package org.jetbrains.kotlin.idea.findUsages.dialogs;
import com.intellij.ui.SimpleColoredComponent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.idea.search.usagesSearch.UtilsKt;
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesSupport;
import org.jetbrains.kotlin.psi.KtNamedDeclaration;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import javax.swing.*;
import java.awt.*;
@@ -34,9 +32,9 @@ class Utils {
@NotNull SimpleColoredComponent coloredComponent,
@NotNull KtNamedDeclaration declaration
) {
DeclarationDescriptor descriptor = UtilsKt.getDescriptor(declaration);
if (descriptor != null) {
coloredComponent.append(DescriptorRenderer.COMPACT.render(descriptor));
String renderedDeclaration = KotlinFindUsagesSupport.Companion.tryRenderDeclarationCompactStyle(declaration);
if (renderedDeclaration != null) {
coloredComponent.append(renderedDeclaration);
}
}
@@ -27,8 +27,8 @@ import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.usageView.UsageInfo
import com.intellij.usages.UsageViewManager
import com.intellij.util.Query
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.asJava.toLightElements
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightClass
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightElements
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.psi.KtConstructor
import org.jetbrains.kotlin.psi.KtDeclaration
@@ -44,9 +44,9 @@ fun KtDeclaration.processAllExactUsages(
if (reference is KtReference) return listOf(this)
return SmartList<PsiElement>().also { list ->
list += this
list += toLightElements()
list += providedToLightElements()
if (this is KtConstructor<*>) {
list.addIfNotNull(getContainingClassOrObject().toLightClass())
list.addIfNotNull(getContainingClassOrObject().providedToLightClass())
}
}
}
@@ -28,28 +28,24 @@ import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.util.FilteredQuery
import com.intellij.util.Processor
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.findUsages.KotlinClassFindUsagesOptions
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesSupport.Companion.isCallReceiverRefersToCompanionObject
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesSupport.Companion.isConstructorUsage
import org.jetbrains.kotlin.idea.findUsages.dialogs.KotlinFindClassUsagesDialog
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.idea.search.usagesSearch.isConstructorUsage
import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
import org.jetbrains.kotlin.idea.search.isImportUsage
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.contains
import org.jetbrains.kotlin.psi.psiUtil.effectiveDeclarations
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import java.util.*
class KotlinFindClassUsagesHandler(
@@ -97,7 +93,7 @@ class KotlinFindClassUsagesHandler(
}
if (kotlinOptions.searchConstructorUsages) {
classOrObject.toLightClass()?.constructors?.filterIsInstance<KtLightMethod>()?.forEach { constructor ->
classOrObject.providedToLightClass()?.constructors?.filterIsInstance<KtLightMethod>()?.forEach { constructor ->
val scope = constructor.useScope.intersectWith(options.searchScope)
var query = MethodReferencesSearch.search(constructor, scope, true)
if (kotlinOptions.isSkipImportStatements) {
@@ -161,18 +157,11 @@ class KotlinFindClassUsagesHandler(
private fun processCompanionObjectInternalReferences(companionObject: KtObjectDeclaration): Boolean {
val klass = companionObject.getStrictParentOfType<KtClass>() ?: return true
val companionObjectDescriptor = companionObject.descriptor
return !klass.anyDescendantOfType(fun(element: KtElement): Boolean {
if (element == companionObject) return false // skip companion object itself
val bindingContext = element.analyze()
val resolvedCall = bindingContext[BindingContext.CALL, element]?.getResolvedCall(bindingContext) ?: return false
if ((resolvedCall.dispatchReceiver as? ImplicitClassReceiver)?.declarationDescriptor == companionObjectDescriptor
|| (resolvedCall.extensionReceiver as? ImplicitClassReceiver)?.declarationDescriptor == companionObjectDescriptor
) {
return element.references.any { !referenceProcessor.process(it) }
}
return false
return if (element.isCallReceiverRefersToCompanionObject(companionObject)) {
element.references.any { !referenceProcessor.process(it) }
} else false
})
}
@@ -190,7 +179,7 @@ class KotlinFindClassUsagesHandler(
override fun getStringsToSearch(element: PsiElement): Collection<String> {
val psiClass = when (element) {
is PsiClass -> element
is KtClassOrObject -> getElement().toLightClass()
is KtClassOrObject -> getElement().providedToLightClass()
else -> null
} ?: return Collections.emptyList()
@@ -1,17 +1,6 @@
/*
* 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.
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.findUsages.handlers
@@ -40,13 +29,12 @@ import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.util.*
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.debugger.readAction
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightMethods
import org.jetbrains.kotlin.idea.KotlinBundleIndependent
import org.jetbrains.kotlin.idea.findUsages.*
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesSupport.Companion.getTopMostOverriddenElementsToHighlight
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesSupport.Companion.isDataClassComponentFunction
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.filterDataClassComponentsIfDisabled
import org.jetbrains.kotlin.idea.findUsages.dialogs.KotlinFindFunctionUsagesDialog
import org.jetbrains.kotlin.idea.findUsages.dialogs.KotlinFindPropertyUsagesDialog
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
@@ -55,14 +43,10 @@ import org.jetbrains.kotlin.idea.search.excludeKotlinSources
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDetector
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
import org.jetbrains.kotlin.idea.search.isImportUsage
import org.jetbrains.kotlin.idea.search.isOnlyKotlinSearch
import org.jetbrains.kotlin.idea.search.usagesSearch.dataClassComponentFunction
import org.jetbrains.kotlin.idea.search.usagesSearch.filterDataClassComponentsIfDisabled
import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors
import org.jetbrains.kotlin.resolve.source.getPsi
import javax.swing.event.HyperlinkEvent
import javax.swing.event.HyperlinkListener
@@ -86,7 +70,7 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration> protected c
mustOpenInNewTab: Boolean
): AbstractFindUsagesDialog {
val options = factory.findFunctionOptions
val lightMethod = getElement().toLightMethods().firstOrNull()
val lightMethod = getElement().providedToLightMethods().firstOrNull()
if (lightMethod != null) {
return KotlinFindFunctionUsagesDialog(lightMethod, project, options, toShowInNewTab, mustOpenInNewTab, isSingleFile, this)
}
@@ -134,7 +118,7 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration> protected c
}
}
private val isPropertyOfDataClass = readAction {
private val isPropertyOfDataClass = runReadAction {
propertyDeclaration.parent is KtParameterList &&
propertyDeclaration.parent.parent is KtPrimaryConstructor &&
propertyDeclaration.parent.parent.parent.let { it is KtClass && it.isData() }
@@ -238,12 +222,12 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration> protected c
if (element is KtElement && !isOnlyKotlinSearch(options.searchScope)) {
// TODO: very bad code!! ReferencesSearch does not work correctly for constructors and annotation parameters
val psiMethodScopeSearch = when {
element is KtParameter && element.dataClassComponentFunction() != null ->
element is KtParameter && element.isDataClassComponentFunction ->
options.searchScope.excludeKotlinSources()
else -> options.searchScope
}
for (psiMethod in element.toLightMethods().filterDataClassComponentsIfDisabled(kotlinSearchOptions)) {
for (psiMethod in element.providedToLightMethods().filterDataClassComponentsIfDisabled(kotlinSearchOptions)) {
addTask {
applyQueryFilters(
element,
@@ -284,13 +268,8 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration> protected c
!isSingleFile && psiElement !is KtParameter
override fun findReferencesToHighlight(target: PsiElement, searchScope: SearchScope): Collection<PsiReference> {
val callableDescriptor = (target as? KtCallableDeclaration)?.resolveToDescriptorIfAny() as? CallableDescriptor
val descriptorsToHighlight = if (callableDescriptor is ParameterDescriptor)
listOf(callableDescriptor)
else
callableDescriptor?.findOriginalTopMostOverriddenDescriptors() ?: emptyList()
val baseDeclarations = descriptorsToHighlight.map { it.source.getPsi() }.filter { it != null && it != target }
val baseDeclarations = getTopMostOverriddenElementsToHighlight(target)
return if (baseDeclarations.isNotEmpty()) {
baseDeclarations.flatMap {
@@ -311,7 +290,7 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration> protected c
private const val DISABLE_ONCE = "DISABLE_ONCE"
private const val DISABLE = "DISABLE"
private val DISABLE_COMPONENT_AND_DESTRUCTION_SEARCH_TEXT = KotlinBundle.message(
private val DISABLE_COMPONENT_AND_DESTRUCTION_SEARCH_TEXT = KotlinBundleIndependent.message(
"find.usages.text.find.usages.for.data.class.components.and.destruction.declarations",
DISABLE_ONCE,
DISABLE
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory
import org.jetbrains.kotlin.idea.findUsages.KotlinReferencePreservingUsageInfo
import org.jetbrains.kotlin.idea.findUsages.KotlinReferenceUsageInfo
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.runReadActionInSmartMode
import org.jetbrains.kotlin.idea.util.application.runReadActionInSmartMode
import java.util.*
abstract class KotlinFindUsagesHandler<T : PsiElement>(
@@ -0,0 +1,152 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.search
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.SearchScope
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.ImportPath
interface KotlinSearchUsagesSupport {
companion object {
fun getInstance(project: Project): KotlinSearchUsagesSupport {
return ServiceManager.getService(project, KotlinSearchUsagesSupport::class.java)
}
val KtParameter.dataClassComponentMethodName: String?
get() = getInstance(project).dataClassComponentMethodName(this)
val KtExpression.hasType: Boolean
get() = getInstance(project).hasType(this)
val PsiClass.isSamInterface: Boolean
get() = getInstance(project).isSamInterface(this)
fun <T : PsiNamedElement> List<T>.filterDataClassComponentsIfDisabled(kotlinOptions: KotlinReferencesSearchOptions): List<T> =
firstOrNull()?.let {
getInstance(it.project).filterDataClassComponentsIfDisabled(this, kotlinOptions)
} ?: this
fun PsiReference.isCallableOverrideUsage(declaration: KtNamedDeclaration): Boolean =
getInstance(declaration.project).isCallableOverrideUsage(this, declaration)
fun PsiReference.isUsageInContainingDeclaration(declaration: KtNamedDeclaration): Boolean =
getInstance(declaration.project).isUsageInContainingDeclaration(this, declaration)
fun PsiReference.isExtensionOfDeclarationClassUsage(declaration: KtNamedDeclaration): Boolean =
getInstance(declaration.project).isExtensionOfDeclarationClassUsage(this, declaration)
fun PsiElement.getReceiverTypeSearcherInfo(isDestructionDeclarationSearch: Boolean): ReceiverTypeSearcherInfo? =
getInstance(project).getReceiverTypeSearcherInfo(this, isDestructionDeclarationSearch)
fun KtFile.forceResolveReferences(elements: List<KtElement>) =
getInstance(project).forceResolveReferences(this, elements)
fun PsiFile.scriptDefinitionExists(): Boolean =
getInstance(project).scriptDefinitionExists(this)
fun KtFile.getDefaultImports(): List<ImportPath> =
getInstance(project).getDefaultImports(this)
fun forEachKotlinOverride(
ktClass: KtClass,
members: List<KtNamedDeclaration>,
scope: SearchScope,
processor: (superMember: PsiElement, overridingMember: PsiElement) -> Boolean
): Boolean = getInstance(ktClass.project).forEachKotlinOverride(ktClass, members, scope, processor)
fun PsiMethod.forEachOverridingMethod(
scope: SearchScope = runReadAction { useScope },
processor: (PsiMethod) -> Boolean
): Boolean = getInstance(project).forEachOverridingMethod(this, scope, processor)
fun findDeepestSuperMethodsNoWrapping(method: PsiElement): List<PsiElement> =
getInstance(method.project).findDeepestSuperMethodsNoWrapping(method)
fun findTypeAliasByShortName(shortName: String, project: Project, scope: GlobalSearchScope): Collection<KtTypeAlias> =
getInstance(project).findTypeAliasByShortName(shortName, project, scope)
fun isInProjectSource(element: PsiElement, includeScriptsOutsideSourceRoots: Boolean = false): Boolean =
getInstance(element.project).isInProjectSource(element, includeScriptsOutsideSourceRoots)
fun KtDeclaration.isOverridable(): Boolean =
getInstance(project).isOverridable(this)
fun KtClass.isInheritable(): Boolean =
getInstance(project).isInheritable(this)
fun formatJavaOrLightMethod(method: PsiMethod): String =
getInstance(method.project).formatJavaOrLightMethod(method)
fun formatClass(classOrObject: KtClassOrObject): String =
getInstance(classOrObject.project).formatClass(classOrObject)
fun KtDeclaration.expectedDeclarationIfAny(): KtDeclaration? =
getInstance(project).expectedDeclarationIfAny(this)
fun KtDeclaration.isExpectDeclaration(): Boolean =
getInstance(project).isExpectDeclaration(this)
}
fun dataClassComponentMethodName(element: KtParameter): String?
fun hasType(element: KtExpression): Boolean
fun isSamInterface(psiClass: PsiClass): Boolean
fun <T : PsiNamedElement> filterDataClassComponentsIfDisabled(elements: List<T>, kotlinOptions: KotlinReferencesSearchOptions): List<T>
fun isCallableOverrideUsage(reference: PsiReference, declaration: KtNamedDeclaration): Boolean
fun isUsageInContainingDeclaration(reference: PsiReference, declaration: KtNamedDeclaration): Boolean
fun isExtensionOfDeclarationClassUsage(reference: PsiReference, declaration: KtNamedDeclaration): Boolean
fun getReceiverTypeSearcherInfo(psiElement: PsiElement, isDestructionDeclarationSearch: Boolean): ReceiverTypeSearcherInfo?
fun forceResolveReferences(file: KtFile, elements: List<KtElement>)
fun scriptDefinitionExists(file: PsiFile): Boolean
fun getDefaultImports(file: KtFile): List<ImportPath>
fun forEachKotlinOverride(
ktClass: KtClass,
members: List<KtNamedDeclaration>,
scope: SearchScope,
processor: (superMember: PsiElement, overridingMember: PsiElement) -> Boolean
): Boolean
fun forEachOverridingMethod(
method: PsiMethod,
scope: SearchScope,
processor: (PsiMethod) -> Boolean
): Boolean
fun findDeepestSuperMethodsNoWrapping(method: PsiElement): List<PsiElement>
fun findTypeAliasByShortName(shortName: String, project: Project, scope: GlobalSearchScope): Collection<KtTypeAlias>
fun isInProjectSource(element: PsiElement, includeScriptsOutsideSourceRoots: Boolean = false): Boolean
fun isOverridable(declaration: KtDeclaration): Boolean
fun isInheritable(ktClass: KtClass): Boolean
fun formatJavaOrLightMethod(method: PsiMethod): String
fun formatClass(classOrObject: KtClassOrObject): String
fun expectedDeclarationIfAny(declaration: KtDeclaration): KtDeclaration?
fun isExpectDeclaration(declaration: KtDeclaration): Boolean
}
@@ -15,19 +15,15 @@ import com.intellij.psi.util.CachedValuesManager
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult.*
import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo
import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener
import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.project.findAnalyzerServices
import org.jetbrains.kotlin.idea.stubindex.KotlinTypeAliasShortNameIndex
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.findTypeAliasByShortName
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.getDefaultImports
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.ImportPath
import java.util.concurrent.atomic.AtomicInteger
/**
@@ -35,6 +31,7 @@ import java.util.concurrent.atomic.AtomicInteger
* with the given qualified name.
*/
class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName: String) {
private val targetShortName = targetClassFqName.substringAfterLast('.')
private val targetPackage = targetClassFqName.substringBeforeLast('.', "")
@@ -125,7 +122,7 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
}
private fun findPotentialTypeAliasConflicts(target: PsiClass) {
val candidates = KotlinTypeAliasShortNameIndex.getInstance().get(targetShortName, target.project, target.project.allScope())
val candidates = findTypeAliasByShortName(targetShortName, target.project, target.project.allScope())
for (candidate in candidates) {
packagesWithTypeAliases.add(candidate.containingKtFile.packageFqName.asString())
}
@@ -244,12 +241,4 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
}
return Result.Ambiguity
}
}
private fun KtFile.getDefaultImports(): List<ImportPath> {
val moduleInfo = getNullableModuleInfo() ?: return emptyList()
return TargetPlatformDetector.getPlatform(this).findAnalyzerServices(project).getDefaultImports(
IDELanguageSettingsProvider.getLanguageVersionSettings(moduleInfo, project),
includeLowPriorityImports = true
)
}
}
@@ -22,14 +22,14 @@ import com.intellij.psi.PsiModifier
import com.intellij.psi.search.searches.ClassInheritorsSearch
import com.intellij.util.EmptyQuery
import com.intellij.util.Query
import org.jetbrains.kotlin.asJava.toLightClassWithBuiltinMapping
import org.jetbrains.kotlin.idea.caches.lightClasses.KtFakeLightClass
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedCreateKtFakeLightClass
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightClassWithBuiltinMapping
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.KtClassOrObject
fun HierarchySearchRequest<*>.searchInheritors(): Query<PsiClass> {
val psiClass: PsiClass = when (originalElement) {
is KtClassOrObject -> runReadAction { originalElement.toLightClassWithBuiltinMapping() ?: KtFakeLightClass(originalElement) }
is KtClassOrObject -> runReadAction { originalElement.providedToLightClassWithBuiltinMapping() ?: providedCreateKtFakeLightClass(originalElement) }
is PsiClass -> originalElement
else -> null
} ?: return EmptyQuery.getEmptyQuery()
@@ -18,27 +18,20 @@ import com.intellij.util.EmptyQuery
import com.intellij.util.MergeQuery
import com.intellij.util.Processor
import com.intellij.util.Query
import org.jetbrains.kotlin.asJava.getRepresentativeLightMethod
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.isOverridable
import org.jetbrains.kotlin.idea.caches.lightClasses.KtFakeLightClass
import org.jetbrains.kotlin.idea.caches.lightClasses.KtFakeLightMethod
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.getDeepestSuperDeclarations
import org.jetbrains.kotlin.idea.core.isOverridable
import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedCreateKtFakeLightMethod
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedGetRepresentativeLightMethod
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedIsKtFakeLightClass
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightMethods
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.findDeepestSuperMethodsNoWrapping
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.forEachKotlinOverride
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.forEachOverridingMethod
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.isOverridable
import org.jetbrains.kotlin.idea.search.allScope
import org.jetbrains.kotlin.idea.search.excludeKotlinSources
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.substitutions.getTypeSubstitutor
import org.jetbrains.kotlin.util.findCallableMemberBySignature
import java.util.*
fun PsiElement.isOverridableElement(): Boolean = when (this) {
@@ -48,7 +41,7 @@ fun PsiElement.isOverridableElement(): Boolean = when (this) {
}
fun HierarchySearchRequest<*>.searchOverriders(): Query<PsiMethod> {
val psiMethods = runReadAction { originalElement.toLightMethods() }
val psiMethods = runReadAction { originalElement.providedToLightMethods() }
if (psiMethods.isEmpty()) return EmptyQuery.getEmptyQuery()
return psiMethods
@@ -111,44 +104,10 @@ fun PsiElement.toPossiblyFakeLightMethods(): List<PsiMethod> {
val element = unwrapped ?: return emptyList()
val lightMethods = element.toLightMethods()
val lightMethods = element.providedToLightMethods()
if (lightMethods.isNotEmpty()) return lightMethods
return if (element is KtNamedDeclaration) listOfNotNull(KtFakeLightMethod.get(element)) else emptyList()
}
private fun forEachKotlinOverride(
ktClass: KtClass,
members: List<KtNamedDeclaration>,
scope: SearchScope,
processor: (superMember: PsiElement, overridingMember: PsiElement) -> Boolean
): Boolean {
val baseClassDescriptor = runReadAction { ktClass.unsafeResolveToDescriptor() as ClassDescriptor }
val baseDescriptors =
runReadAction { members.mapNotNull { it.unsafeResolveToDescriptor() as? CallableMemberDescriptor }.filter { it.isOverridable } }
if (baseDescriptors.isEmpty()) return true
HierarchySearchRequest(ktClass, scope, true).searchInheritors().forEach(Processor { psiClass ->
val inheritor = psiClass.unwrapped as? KtClassOrObject ?: return@Processor true
runReadAction {
val inheritorDescriptor = inheritor.unsafeResolveToDescriptor() as ClassDescriptor
val substitutor =
getTypeSubstitutor(baseClassDescriptor.defaultType, inheritorDescriptor.defaultType) ?: return@runReadAction true
baseDescriptors.forEach {
val superMember = it.source.getPsi()!!
val overridingDescriptor = (it.substitute(substitutor) as? CallableMemberDescriptor)?.let { memberDescriptor ->
inheritorDescriptor.findCallableMemberBySignature(memberDescriptor)
}
val overridingMember = overridingDescriptor?.source?.getPsi()
if (overridingMember != null) {
if (!processor(superMember, overridingMember)) return@runReadAction false
}
}
true
}
})
return true
return if (element is KtNamedDeclaration) listOfNotNull(providedCreateKtFakeLightMethod(element)) else emptyList()
}
fun KtNamedDeclaration.forEachOverridingElement(
@@ -157,29 +116,13 @@ fun KtNamedDeclaration.forEachOverridingElement(
): Boolean {
val ktClass = runReadAction { containingClassOrObject as? KtClass } ?: return true
toLightMethods().forEach { baseMethod ->
providedToLightMethods().forEach { baseMethod ->
if (!OverridingMethodsSearch.search(baseMethod, scope.excludeKotlinSources(), true).all { processor(baseMethod, it) }) return false
}
return forEachKotlinOverride(ktClass, listOf(this), scope) { baseElement, overrider -> processor(baseElement, overrider) }
}
fun PsiMethod.forEachOverridingMethod(
scope: SearchScope = runReadAction { useScope },
processor: (PsiMethod) -> Boolean
): Boolean {
if (this !is KtFakeLightMethod) {
if (!OverridingMethodsSearch.search(this, scope.excludeKotlinSources(), true).forEach(processor)) return false
}
val ktMember = this.unwrapped as? KtNamedDeclaration ?: return true
val ktClass = runReadAction { ktMember.containingClassOrObject as? KtClass } ?: return true
return forEachKotlinOverride(ktClass, listOf(ktMember), scope) { _, overrider ->
val lightMethods = runReadAction { overrider.toPossiblyFakeLightMethods().distinctBy { it.unwrapped } }
lightMethods.all { processor(it) }
}
}
fun PsiMethod.forEachImplementation(
scope: SearchScope = runReadAction { useScope },
processor: (PsiElement) -> Boolean
@@ -191,7 +134,7 @@ fun PsiMethod.forEachImplementation(
fun PsiClass.forEachDeclaredMemberOverride(processor: (superMember: PsiElement, overridingMember: PsiElement) -> Boolean) {
val scope = runReadAction { useScope }
if (this !is KtFakeLightClass) {
if (!providedIsKtFakeLightClass()) {
AllOverridingMethodsSearch.search(this, scope.excludeKotlinSources()).all { processor(it.first, it.second) }
}
@@ -201,19 +144,5 @@ fun PsiClass.forEachDeclaredMemberOverride(processor: (superMember: PsiElement,
forEachKotlinOverride(ktClass, members, scope, processor)
}
fun findDeepestSuperMethodsNoWrapping(method: PsiElement): List<PsiElement> {
val element = method.unwrapped
return when (element) {
is PsiMethod -> element.findDeepestSuperMethods().toList()
is KtCallableDeclaration -> {
val descriptor = element.resolveToDescriptorIfAny() as? CallableMemberDescriptor ?: return emptyList()
descriptor.getDeepestSuperDeclarations(false).mapNotNull {
it.source.getPsi() ?: DescriptorToSourceUtilsIde.getAnyDeclaration(element.project, it)
}
}
else -> emptyList()
}
}
fun findDeepestSuperMethodsKotlinAware(method: PsiElement) =
findDeepestSuperMethodsNoWrapping(method).mapNotNull { it.getRepresentativeLightMethod() }
findDeepestSuperMethodsNoWrapping(method).mapNotNull { it.providedGetRepresentativeLightMethod() }
@@ -25,33 +25,31 @@ import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.util.Processor
import com.intellij.util.containers.nullize
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedGetLightClassMethods
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedGetLightClassParameterDeclarations
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedGetLightClassPropertyDeclarations
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedGetLightFieldForCompanionObject
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightClass
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightElements
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightMember
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.elements.KtLightParameter
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.asJava.toLightElements
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesSupport.Companion.sourcesAndLibraries
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.dataClassComponentMethodName
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.expectedDeclarationIfAny
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.filterDataClassComponentsIfDisabled
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.isExpectDeclaration
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.search.*
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions.Companion.Empty
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions.Companion.calculateEffectiveScope
import org.jetbrains.kotlin.idea.search.usagesSearch.dataClassComponentFunction
import org.jetbrains.kotlin.idea.search.usagesSearch.filterDataClassComponentsIfDisabled
import org.jetbrains.kotlin.idea.search.usagesSearch.getClassNameForCompanionObject
import org.jetbrains.kotlin.idea.search.usagesSearch.operators.OperatorReferenceSearcher
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.expectedDeclarationIfAny
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.psi.psiUtil.*
import java.util.*
data class KotlinReferencesSearchOptions(
@@ -76,7 +74,7 @@ data class KotlinReferencesSearchOptions(
): SearchScope {
val kotlinOptions = (parameters as? KotlinAwareReferencesSearchParameters)?.kotlinOptions ?: Empty
val elements = if (elementToSearch is KtDeclaration && !isOnlyKotlinSearch(parameters.scopeDeterminedByUser)) {
elementToSearch.toLightElements().filterDataClassComponentsIfDisabled(kotlinOptions).nullize()
elementToSearch.providedToLightElements().filterDataClassComponentsIfDisabled(kotlinOptions).nullize()
} else {
null
} ?: listOf(elementToSearch)
@@ -194,7 +192,6 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
}
}
val classNameForCompanionObject = elementToSearch.getClassNameForCompanionObject()
if (classNameForCompanionObject != null) {
queryParameters.optimizer.searchWord(
@@ -220,25 +217,14 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
}
if (kotlinOptions.searchForComponentConventions) {
when (element) {
is KtParameter -> {
val componentFunctionDescriptor = element.dataClassComponentFunction()
if (componentFunctionDescriptor != null) {
val containingClass = element.getStrictParentOfType<KtClassOrObject>()?.toLightClass()
searchDataClassComponentUsages(containingClass, componentFunctionDescriptor, kotlinOptions)
}
}
is KtLightParameter -> {
val componentFunctionDescriptor = element.kotlinOrigin?.dataClassComponentFunction()
if (componentFunctionDescriptor != null) {
searchDataClassComponentUsages(element.method.containingClass, componentFunctionDescriptor, kotlinOptions)
}
}
}
searchForComponentConventions(element)
}
}
private fun PsiNamedElement.getClassNameForCompanionObject(): String? =
(this is KtObjectDeclaration && this.isCompanion())
.ifTrue { getNonStrictParentOfType<KtClass>()?.name }
private fun searchNamedArguments(parameter: KtParameter) {
val parameterName = parameter.name ?: return
val function = parameter.ownerFunction as? KtFunction ?: return
@@ -247,7 +233,7 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
var namedArgsScope = function.useScope.intersectWith(queryParameters.scopeDeterminedByUser)
if (namedArgsScope is GlobalSearchScope) {
namedArgsScope = KotlinSourceFilterScope.sourcesAndLibraries(namedArgsScope, project)
namedArgsScope = sourcesAndLibraries(namedArgsScope, project)
val filesWithFunctionName = CacheManager.SERVICE.getInstance(project).getVirtualFilesWithWord(
function.name!!, UsageSearchContext.IN_CODE, namedArgsScope, true
@@ -275,7 +261,7 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
is KtNamedFunction, is KtSecondaryConstructor -> {
val name = (element as KtFunction).name
if (name != null) {
val methods = LightClassUtil.getLightClassMethods(element)
val methods = providedGetLightClassMethods(element)
for (method in methods) {
searchNamedElement(method)
}
@@ -285,8 +271,8 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
}
is KtProperty -> {
val propertyMethods = LightClassUtil.getLightClassPropertyMethods(element)
propertyMethods.allDeclarations.forEach { searchNamedElement(it) }
val propertyDeclarations = providedGetLightClassPropertyDeclarations(element)
propertyDeclarations.forEach { searchNamedElement(it) }
processStaticsFromCompanionObject(element)
}
@@ -294,8 +280,8 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
searchPropertyAccessorMethods(element)
if (element.getStrictParentOfType<KtPrimaryConstructor>() != null) {
// Simple parameters without val and var shouldn't be processed here because of local search scope
val methods = LightClassUtil.getLightClassPropertyMethods(element)
methods.allDeclarations.filterDataClassComponentsIfDisabled(kotlinOptions).forEach { searchNamedElement(it) }
val parameterDeclarations = providedGetLightClassParameterDeclarations(element)
parameterDeclarations.filterDataClassComponentsIfDisabled(kotlinOptions).forEach { searchNamedElement(it) }
}
}
@@ -323,19 +309,19 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
}
private fun searchPropertyAccessorMethods(origin: KtParameter) {
origin.toLightElements().filterDataClassComponentsIfDisabled(kotlinOptions).forEach { searchNamedElement(it) }
origin.providedToLightElements().filterDataClassComponentsIfDisabled(kotlinOptions).forEach { searchNamedElement(it) }
}
private fun processKtClassOrObject(element: KtClassOrObject) {
val className = element.name ?: return
val lightClass = element.toLightClass() ?: return
val lightClass = element.providedToLightClass() ?: return
searchNamedElement(lightClass, className)
if (element is KtObjectDeclaration && element.isCompanion()) {
LightClassUtil.getLightFieldForCompanionObject(element)?.let { searchNamedElement(it) }
providedGetLightFieldForCompanionObject(element)?.let { searchNamedElement(it) }
if (kotlinOptions.acceptCompanionObjectMembers) {
val originLightClass = element.getStrictParentOfType<KtClass>()?.toLightClass()
val originLightClass = element.getStrictParentOfType<KtClass>()?.providedToLightClass()
if (originLightClass != null) {
val lightDeclarations: List<KtLightMember<*>?> =
originLightClass.methods.map { it as? KtLightMethod } + originLightClass.fields.map { it as? KtLightField }
@@ -350,13 +336,40 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
}
}
private fun searchForComponentConventions(element: PsiElement) {
when (element) {
is KtParameter -> {
val componentMethodName = element.dataClassComponentMethodName
if (componentMethodName != null) {
val containingClass = element.getStrictParentOfType<KtClassOrObject>()?.providedToLightClass()
searchDataClassComponentUsages(
containingClass = containingClass,
componentMethodName = componentMethodName,
kotlinOptions = kotlinOptions
)
}
}
is KtLightParameter -> {
val componentMethodName = element.kotlinOrigin?.dataClassComponentMethodName
if (componentMethodName != null) {
searchDataClassComponentUsages(
containingClass = element.method.containingClass,
componentMethodName = componentMethodName,
kotlinOptions = kotlinOptions
)
}
}
}
}
private fun searchDataClassComponentUsages(
containingClass: PsiClass?,
componentFunctionDescriptor: FunctionDescriptor,
componentMethodName: String,
kotlinOptions: KotlinReferencesSearchOptions
) {
val componentFunction = containingClass?.methods?.firstOrNull {
it.name == componentFunctionDescriptor.name.asString() && it.parameterList.parametersCount == 0
it.name == componentMethodName && it.parameterList.parametersCount == 0
}
if (componentFunction != null) {
searchNamedElement(componentFunction)
@@ -378,7 +391,7 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
.firstOrNull() as? KtObjectDeclaration ?: return emptyList()
if (!originObject.isCompanion()) return emptyList()
val originClass = originObject.getStrictParentOfType<KtClass>()
val originLightClass = originClass?.toLightClass() ?: return emptyList()
val originLightClass = originClass?.providedToLightClass() ?: return emptyList()
val allMethods = originLightClass.allMethods
return allMethods.filter { it is KtLightMethod && it.kotlinOrigin == declaration }
}
@@ -23,10 +23,10 @@ import com.intellij.psi.PsiReferenceService
import com.intellij.psi.ReferenceRange
import com.intellij.psi.search.RequestResultProcessor
import com.intellij.util.Processor
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.isCallableOverrideUsage
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.isExtensionOfDeclarationClassUsage
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.isUsageInContainingDeclaration
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
import org.jetbrains.kotlin.idea.search.usagesSearch.isCallableOverrideUsage
import org.jetbrains.kotlin.idea.search.usagesSearch.isExtensionOfDeclarationClassUsage
import org.jetbrains.kotlin.idea.search.usagesSearch.isUsageInContainingDeclaration
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtNamedDeclaration
@@ -21,9 +21,7 @@ import com.intellij.openapi.fileTypes.FileTypeRegistry
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.*
import com.intellij.psi.impl.cache.impl.id.IdIndex
import com.intellij.psi.impl.cache.impl.id.IdIndexEntry
import com.intellij.psi.search.GlobalSearchScope
@@ -33,12 +31,17 @@ import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.util.CommonProcessors
import com.intellij.util.indexing.FileBasedIndex
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.scriptDefinitionExists
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import java.util.*
@@ -141,6 +144,28 @@ fun findScriptsWithUsages(declaration: KtNamedDeclaration): List<KtFile> {
}
return collector.results
.mapNotNull { PsiManager.getInstance(project).findFile(it) as? KtFile }
.filter { it.findScriptDefinition() != null }
.filter { it.scriptDefinitionExists() }
.toList()
}
inline fun <T> Boolean.ifTrue(body: () -> T?): T? = if (this) body() else null
data class ReceiverTypeSearcherInfo(
val psiClass: PsiClass?,
val containsTypeOrDerivedInside: ((KtDeclaration) -> Boolean)
)
fun PsiReference.isImportUsage(): Boolean =
element.getNonStrictParentOfType<KtImportDirective>() != null
//TODO: Copied from fqNameUtil.kt
fun PsiElement.getKotlinFqName(): FqName? = when (val element = namedUnwrappedElement) {
is PsiPackage -> FqName(element.qualifiedName)
is PsiClass -> element.qualifiedName?.let(::FqName)
is PsiMember -> element.getName()?.let { name ->
val prefix = element.containingClass?.qualifiedName
FqName(if (prefix != null) "$prefix.$name" else name)
}
is KtNamedDeclaration -> element.fqName
else -> null
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.search.usagesSearch
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.ide.highlighter.XmlFileType
import com.intellij.ide.projectView.impl.ProjectRootsUtil
import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger
@@ -22,37 +23,30 @@ import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.util.Processor
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightClass
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMemberDescriptor
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.hasType
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.isInProjectSource
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.isSamInterface
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
import org.jetbrains.kotlin.idea.search.excludeFileTypes
import org.jetbrains.kotlin.idea.search.getKotlinFqName
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
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.idea.util.application.runReadAction
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.sam.getSingleAbstractMethodOrNull
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
//TODO: check if smart search is too expensive
class ExpressionsOfTypeProcessor(
private val typeToSearch: FuzzyType,
private val containsTypeOrDerivedInside: (KtDeclaration) -> Boolean,
private val classToSearch: PsiClass?,
private val searchScope: SearchScope,
private val project: Project,
@@ -132,7 +126,7 @@ class ExpressionsOfTypeProcessor(
}) return
// for class from library always use plain search because we cannot search usages in compiled code (we could though)
if (!runReadAction { classToSearch.isValid && ProjectRootsUtil.isInProjectSource(classToSearch) }) {
if (!runReadAction { classToSearch.isValid && isInProjectSource(classToSearch) }) {
possibleMatchesInScopeHandler(searchScope)
return
}
@@ -535,9 +529,7 @@ class ExpressionsOfTypeProcessor(
if (element.getStrictParentOfType<KtImportDirective>() != null) return true // ignore usage in import
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
val hasType = bindingContext.getType(element) != null
if (hasType) { // access to object or companion object
if (element.hasType) { // access to object or companion object
processSuspiciousExpression(element)
return true
}
@@ -590,7 +582,7 @@ class ExpressionsOfTypeProcessor(
val parent = typeRefParent.parent
if (parent is KtSuperTypeCallEntry) {
val classOrObject = (parent.parent as KtSuperTypeList).parent as KtClassOrObject
val psiClass = classOrObject.toLightClass()
val psiClass = classOrObject.providedToLightClass()
psiClass?.let { addClassToProcess(it) }
return true
}
@@ -599,7 +591,7 @@ class ExpressionsOfTypeProcessor(
is KtSuperTypeListEntry -> { // super-interface name in the list of bases
if (typeRef == typeRefParent.typeReference) {
val classOrObject = (typeRefParent.parent as KtSuperTypeList).parent as KtClassOrObject
val psiClass = classOrObject.toLightClass()
val psiClass = classOrObject.providedToLightClass()
psiClass?.let { addClassToProcess(it) }
return true
}
@@ -762,8 +754,7 @@ class ExpressionsOfTypeProcessor(
if (psiClass != null) {
testLog { "Resolved java class to descriptor: ${psiClass.qualifiedName}" }
val classDescriptor = psiClass.getJavaMemberDescriptor() as? JavaClassDescriptor
if (classDescriptor != null && getSingleAbstractMethodOrNull(classDescriptor) != null) {
if (psiClass.isSamInterface) {
addSamInterfaceToProcess(psiClass)
return true
}
@@ -838,9 +829,7 @@ class ExpressionsOfTypeProcessor(
testLog { "Checked type of ${logPresentation(declaration)}" }
val descriptor = declaration.resolveToDescriptorIfAny() as? CallableDescriptor ?: return
val type = descriptor.returnType
if (type != null && type.containsTypeOrDerivedInside(typeToSearch)) {
if (containsTypeOrDerivedInside(declaration)) {
addCallableDeclarationOfOurType(declaration)
}
}
@@ -907,10 +896,6 @@ class ExpressionsOfTypeProcessor(
return true // we don't know
}
private fun KotlinType.containsTypeOrDerivedInside(type: FuzzyType): Boolean {
return type.checkIsSuperTypeOf(this) != null || arguments.any { !it.isStarProjection && it.type.containsTypeOrDerivedInside(type) }
}
private fun isImplicitlyTyped(declaration: KtDeclaration): Boolean {
return when (declaration) {
is KtFunction -> !declaration.hasDeclaredReturnType()
@@ -22,10 +22,8 @@ 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.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.usagesSearch.dataClassComponentFunction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
@@ -44,15 +42,6 @@ class DestructuringDeclarationReferenceSearcher(
options,
wordsToSearch = listOf("(")
) {
override fun resolveTargetToDescriptor(): FunctionDescriptor? {
return if (targetDeclaration is KtParameter) {
targetDeclaration.dataClassComponentFunction()
} else {
super.resolveTargetToDescriptor()
}
}
override fun extractReference(element: KtElement): PsiReference? {
val destructuringDeclaration = element as? KtDestructuringDeclaration ?: return null
val entries = destructuringDeclaration.entries
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.idea.search.usagesSearch.operators
import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.progress.ProgressIndicatorProvider
import com.intellij.openapi.progress.util.ProgressWrapper
import com.intellij.psi.*
@@ -13,36 +12,25 @@ 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.asJava.toLightClass
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaOrKotlinMemberDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.util.hasJavaResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundleIndependent
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.forceResolveReferences
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.getReceiverTypeSearcherInfo
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinRequestResultProcessor
import org.jetbrains.kotlin.idea.search.ifTrue
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor
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.FuzzyType
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType
import org.jetbrains.kotlin.idea.util.toFuzzyType
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.util.isValidOperator
import java.util.*
abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
@@ -89,10 +77,9 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
options: KotlinReferencesSearchOptions
): OperatorReferenceSearcher<*>? {
return runReadAction {
if (declaration.isValid)
declaration.isValid.ifTrue {
createInReadAction(declaration, searchScope, consumer, optimizer, options)
else
null
}
}
}
@@ -203,18 +190,10 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
}
}
protected open fun resolveTargetToDescriptor(): FunctionDescriptor? {
return when {
targetDeclaration is KtDeclaration -> targetDeclaration.resolveToDescriptorIfAny(BodyResolveMode.FULL)
targetDeclaration is PsiMember && targetDeclaration.hasJavaResolutionFacade() ->
targetDeclaration.getJavaOrKotlinMemberDescriptor()
else -> null
} as? FunctionDescriptor
}
fun run() {
val receiverType = runReadAction { extractReceiverType() } ?: return
val psiClass = runReadAction { receiverType.toPsiClass() }
val (psiClass, containsTypeOrDerivedInside) =
targetDeclaration.getReceiverTypeSearcherInfo(this is DestructuringDeclarationReferenceSearcher) ?: return
val inProgress = SearchesInProgress.get()
if (psiClass != null) {
@@ -235,7 +214,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
try {
ExpressionsOfTypeProcessor(
receiverType,
containsTypeOrDerivedInside,
psiClass,
searchScope,
project,
@@ -247,27 +226,6 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
}
}
private fun FuzzyType.toPsiClass(): PsiClass? {
val classDescriptor = type.constructor.declarationDescriptor ?: return null
val classDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, classDescriptor)
return when (classDeclaration) {
is PsiClass -> classDeclaration
is KtClassOrObject -> classDeclaration.toLightClass()
else -> null
}
}
private fun extractReceiverType(): FuzzyType? {
val descriptor = resolveTargetToDescriptor()?.takeIf { it.isValidOperator() } ?: return null
return if (descriptor.isExtension) {
descriptor.fuzzyExtensionReceiverType()!!
} else {
val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return null
classDescriptor.defaultType.toFuzzyType(classDescriptor.typeConstructor.parameters)
}
}
private fun doPlainSearch(scope: SearchScope) {
testLog { "Used plain search of ${logPresentation(targetDeclaration)} in ${scope.logPresentation()}" }
@@ -284,7 +242,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
}
// resolve all references at once
(element.containingFile as KtFile).getResolutionFacade().analyze(elements, BodyResolveMode.PARTIAL)
(element.containingFile as? KtFile)?.forceResolveReferences(elements)
refs
.filter { it.isReferenceTo(targetDeclaration) }
@@ -317,7 +275,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
// we must unwrap progress indicator because ProgressWrapper does not do anything on changing text and fraction
val progress = ProgressWrapper.unwrap(ProgressIndicatorProvider.getGlobalProgressIndicator())
progress?.pushState()
progress?.text = KotlinIdeaAnalysisBundle.message("searching.for.implicit.usages")
progress?.text = KotlinIdeaAnalysisBundleIndependent.message("searching.for.implicit.usages")
try {
val files = runReadAction { FileTypeIndex.getFiles(KotlinFileType.INSTANCE, scope) }
@@ -9,6 +9,7 @@ import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.components.ComponentManager
import com.intellij.openapi.progress.impl.CancellationCheck
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
fun <T> runReadAction(action: () -> T): T {
@@ -55,3 +56,8 @@ inline fun isUnitTestMode(): Boolean = ApplicationManager.getApplication().isUni
inline fun <reified T : Any> ComponentManager.getServiceSafe(): T =
this.getService(T::class.java) ?: error("Unable to locate service ${T::class.java.name}")
fun <T> Project.runReadActionInSmartMode(action: () -> T): T {
if (ApplicationManager.getApplication().isReadAccessAllowed) return action()
return DumbService.getInstance(this).runReadActionInSmartMode<T>(action)
}
@@ -10,6 +10,7 @@ import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.components.ComponentManager
import com.intellij.openapi.project.Project
import org.jetbrains.annotations.Nls
import com.intellij.openapi.project.DumbService
fun <T> runReadAction(action: () -> T): T {
return ApplicationManager.getApplication().runReadAction<T>(action)
@@ -46,3 +47,8 @@ inline fun isUnitTestMode(): Boolean = ApplicationManager.getApplication().isUni
inline fun <reified T : Any> ComponentManager.getServiceSafe(): T =
this.getService(T::class.java) ?: error("Unable to locate service ${T::class.java.name}")
fun <T> Project.runReadActionInSmartMode(action: () -> T): T {
if (ApplicationManager.getApplication().isReadAccessAllowed) return action()
return DumbService.getInstance(this).runReadActionInSmartMode<T>(action)
}
@@ -24,6 +24,7 @@ import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressIndicatorProvider
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.DumbService
fun <T> runReadAction(action: () -> T): T {
return ApplicationManager.getApplication().runReadAction<T>(action)
@@ -62,4 +63,9 @@ inline fun <reified T : Any> ComponentManager.getServiceSafe(): T =
this.getService(T::class.java) ?: error("Unable to locate service ${T::class.java.name}")
fun <T> Project.getServiceIfCreated(serviceClass: Class<T>): T? =
ServiceManager.getServiceIfCreated(this, serviceClass)
ServiceManager.getServiceIfCreated(this, serviceClass)
fun <T> Project.runReadActionInSmartMode(action: () -> T): T {
if (ApplicationManager.getApplication().isReadAccessAllowed) return action()
return DumbService.getInstance(this).runReadActionInSmartMode<T>(action)
}
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.idea.debugger.DebuggerClassNameProvider.Companion.getRelevantElement
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches.ComputedClassNames
import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
import org.jetbrains.kotlin.idea.search.isImportUsage
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.application.runReadAction
@@ -214,19 +214,6 @@ override.declaration.choose.to.delete=Choose the ones you want to be deleted.
override.declaration.member=Member
override.declaration.delete.multiple.parameters={0} is a part of method hierarchy. Do you want to delete multiple parameters?
find.declaration.implementing.methods.checkbox=&Implementing functions
find.declaration.overriding.methods.checkbox=Over&riding functions
find.declaration.implementing.properties.checkbox=&Implementing properties
find.declaration.overriding.properties.checkbox=Over&riding properties
find.declaration.property.readers.checkbox=Readers
find.declaration.property.writers.checkbox=Writers
find.declaration.include.overloaded.methods.checkbox=Include o&verloaded functions and extensions
find.declaration.functions.usages.checkbox=Usages of &functions
find.declaration.properties.usages.checkbox=Usages of &properties
find.declaration.constructor.usages.checkbox=Usages of &constructor
find.declaration.derived.classes.checkbox=&Derived classes
find.declaration.derived.interfaces.checkbox=Derived &interfaces
hierarchy.legend.member.is.defined.in.class=Member is defined in the class
hierarchy.legend.member.defined.in.superclass=Member is not defined in the class but defined in superclass
hierarchy.legend.member.should.be.defined=Member should be defined since the class is not abstract
@@ -457,33 +444,6 @@ filters.text.inline.function.body=inline function body
filters.text.inline.function.call.site=inline function call site
filters.title.navigate.to=Navigate to
find.usages.class=class
find.usages.companion.object=companion object
find.usages.constructor=constructor
find.usages.facade.class=facade class
find.usages.for.property={0} for property
find.usages.function=function
find.usages.getter=getter
find.usages.import.alias=import alias
find.usages.interface=interface
find.usages.label=label
find.usages.lambda=lambda
find.usages.object=object
find.usages.parameter=parameter
find.usages.property.accessor=property accessor
find.usages.property=property
find.usages.setter=setter
find.usages.type.alias=type alias
find.usages.type.parameter=type parameter
find.usages.variable=variable
find.usages.checkbox.name.expected.classes=Expected classes
find.usages.class.name.anonymous=Anonymous
find.usages.checkbox.name.expected.functions=Expected functions
find.usages.text.find.usages.for.data.class.components.and.destruction.declarations=<p>Find usages for data class components and destructuring declarations<br/>could be <a href="{0}">disabled once</a> or <a href="{1}">disabled for a project</a>.</p>
find.usages.tool.tip.text.disable.search.for.data.class.components.and.destruction.declarations.project.wide.setting=Disable search for data class components and destructuring declarations. (Project wide setting)
find.usages.checkbox.text.fast.data.class.component.search=Fast data class component search
find.usages.checkbox.name.expected.properties=Expected properties
find.usages.action.text.find.usages.of=find usages of
find.usages.type.named.argument=Named argument
find.usages.type.type.alias=Type alias
find.usages.type.callable.reference=Callable reference
+6
View File
@@ -192,6 +192,12 @@ The Kotlin FIR plugin provides language support in IntelliJ IDEA and Android Stu
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Registrar"/>
<elementDescriptionProvider
implementation="org.jetbrains.kotlin.idea.findUsages.KotlinElementDescriptionProviderBase"
order="first"/>
<lang.findUsagesProvider language="kotlin" implementationClass="org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesProviderBase"/>
<fileType name="Kotlin"
implementationClass="org.jetbrains.kotlin.idea.KotlinFileType"
fieldName="INSTANCE"
@@ -211,6 +211,9 @@
<projectService serviceInterface="org.jetbrains.kotlin.asJava.KotlinAsJavaSupport"
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.IDEKotlinAsJavaSupport"/>
<projectService serviceInterface="org.jetbrains.kotlin.idea.asJava.LightClassProvider"
serviceImplementation="org.jetbrains.kotlin.idea.asJava.LightClassProviderImpl"/>
<projectService serviceInterface="org.jetbrains.kotlin.psi.KtFileClassProvider"
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.KtFileClassProviderImpl"/>
@@ -281,6 +284,12 @@
<projectService serviceInterface="org.jetbrains.kotlin.idea.debugger.coroutine.DebuggerListener"
serviceImplementation="org.jetbrains.kotlin.idea.debugger.coroutine.CoroutineDebuggerListener"/>
<projectService serviceInterface="org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesSupport"
serviceImplementation="org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesSupportImpl"/>
<projectService serviceInterface="org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport"
serviceImplementation="org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupportImpl"/>
<errorHandler implementation="org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter"/>
<registryKey
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.asJava
import com.intellij.psi.*
import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.idea.caches.lightClasses.KtFakeLightClass
import org.jetbrains.kotlin.idea.caches.lightClasses.KtFakeLightMethod
import org.jetbrains.kotlin.psi.*
class LightClassProviderImpl : LightClassProvider {
override fun getLightFieldForCompanionObject(companionObject: KtClassOrObject): PsiField? =
LightClassUtil.getLightFieldForCompanionObject(companionObject)
override fun getLightClassMethods(function: KtFunction): List<PsiMethod> =
LightClassUtil.getLightClassMethods(function)
override fun getLightClassParameterDeclarations(parameter: KtParameter): List<PsiNamedElement> =
LightClassUtil.getLightClassPropertyMethods(parameter).allDeclarations
override fun getLightClassPropertyDeclarations(property: KtProperty): List<PsiNamedElement> =
LightClassUtil.getLightClassPropertyMethods(property).allDeclarations
override fun toLightClassWithBuiltinMapping(classOrObject: KtClassOrObject): PsiClass? =
classOrObject.toLightClassWithBuiltinMapping()
override fun toLightMethods(psiElement: PsiElement): List<PsiMethod> =
psiElement.toLightMethods()
override fun toLightClass(classOrObject: KtClassOrObject): KtLightClass? =
classOrObject.toLightClass()
override fun toLightElements(ktElement: KtElement): List<PsiNamedElement> =
ktElement.toLightElements()
override fun createKtFakeLightClass(kotlinOrigin: KtClassOrObject): PsiClass =
KtFakeLightClass(kotlinOrigin)
override fun getRepresentativeLightMethod(psiElement: PsiElement): PsiMethod? =
psiElement.getRepresentativeLightMethod()
override fun isKtFakeLightClass(psiClass: PsiClass): Boolean =
psiClass is KtFakeLightClass
override fun createKtFakeLightMethod(ktDeclaration: KtNamedDeclaration): PsiMethod? =
KtFakeLightMethod.get(ktDeclaration)
}
@@ -16,190 +16,15 @@
package org.jetbrains.kotlin.idea.findUsages
import com.intellij.codeInsight.highlighting.HighlightUsagesDescriptionLocation
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.ElementDescriptionLocation
import com.intellij.psi.ElementDescriptionProvider
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNamedElement
import com.intellij.refactoring.util.CommonRefactoringUtil
import com.intellij.refactoring.util.RefactoringDescriptionLocation
import com.intellij.usageView.UsageViewLongNameLocation
import com.intellij.usageView.UsageViewShortNameLocation
import com.intellij.usageView.UsageViewTypeLocation
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.refactoring.rename.RenameJavaSyntheticPropertyHandler
import org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinPropertyProcessor
import org.jetbrains.kotlin.idea.util.string.collapseSpaces
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
class KotlinElementDescriptionProvider : ElementDescriptionProvider {
private tailrec fun KtNamedDeclaration.parentForFqName(): KtNamedDeclaration? {
val parent = getStrictParentOfType<KtNamedDeclaration>() ?: return null
if (parent is KtProperty && parent.isLocal) return parent.parentForFqName()
return parent
}
class KotlinElementDescriptionProvider : KotlinElementDescriptionProviderBase() {
private fun KtNamedDeclaration.name() = nameAsName ?: Name.special("<no name provided>")
override val PsiElement.isRenameJavaSyntheticPropertyHandler: Boolean
get() = this is RenameJavaSyntheticPropertyHandler.SyntheticPropertyWrapper
private fun KtNamedDeclaration.fqName(): FqNameUnsafe {
containingClassOrObject?.let {
if (it is KtObjectDeclaration && it.isCompanion()) {
return it.fqName().child(name())
}
return FqNameUnsafe("${it.name()}.${name()}")
}
val internalSegments = generateSequence(this) { it.parentForFqName() }
.filterIsInstance<KtNamedDeclaration>()
.map { it.name ?: "<no name provided>" }
.toList()
.asReversed()
val packageSegments = containingKtFile.packageFqName.pathSegments()
return FqNameUnsafe((packageSegments + internalSegments).joinToString("."))
}
private fun KtTypeReference.renderShort(): String {
return accept(
object : KtVisitor<String, Unit>() {
private val visitor get() = this
override fun visitTypeReference(typeReference: KtTypeReference, data: Unit): String {
val typeText = typeReference.typeElement?.accept(this, data) ?: "???"
return if (typeReference.hasParentheses()) "($typeText)" else typeText
}
override fun visitDynamicType(type: KtDynamicType, data: Unit) = type.text
override fun visitFunctionType(type: KtFunctionType, data: Unit): String {
return buildString {
type.receiverTypeReference?.let { append(it.accept(visitor, data)).append('.') }
type.parameters.joinTo(this, prefix = "(", postfix = ")") { it.accept(visitor, data) }
append(" -> ")
append(type.returnTypeReference?.accept(visitor, data) ?: "???")
}
}
override fun visitNullableType(nullableType: KtNullableType, data: Unit): String {
val innerTypeText = nullableType.innerType?.accept(this, data) ?: return "???"
return "$innerTypeText?"
}
override fun visitSelfType(type: KtSelfType, data: Unit) = type.text
override fun visitUserType(type: KtUserType, data: Unit): String {
return buildString {
append(type.referencedName ?: "???")
val arguments = type.typeArguments
if (arguments.isNotEmpty()) {
arguments.joinTo(this, prefix = "<", postfix = ">") {
it.typeReference?.accept(visitor, data) ?: it.text
}
}
}
}
override fun visitParameter(parameter: KtParameter, data: Unit) = parameter.typeReference?.accept(this, data) ?: "???"
},
Unit
)
}
override fun getElementDescription(element: PsiElement, location: ElementDescriptionLocation): String? {
val shouldUnwrap = location !is UsageViewShortNameLocation && location !is UsageViewLongNameLocation
val targetElement = if (shouldUnwrap) element.unwrapped ?: element else element
fun elementKind() = when (targetElement) {
is KtClass -> if (targetElement.isInterface())
KotlinBundle.message("find.usages.interface")
else
KotlinBundle.message("find.usages.class")
is KtObjectDeclaration -> if (targetElement.isCompanion())
KotlinBundle.message("find.usages.companion.object")
else
KotlinBundle.message("find.usages.object")
is KtNamedFunction -> KotlinBundle.message("find.usages.function")
is KtPropertyAccessor -> KotlinBundle.message(
"find.usages.for.property",
(if (targetElement.isGetter)
KotlinBundle.message("find.usages.getter")
else
KotlinBundle.message("find.usages.setter"))
) + " "
is KtFunctionLiteral -> KotlinBundle.message("find.usages.lambda")
is KtPrimaryConstructor, is KtSecondaryConstructor -> KotlinBundle.message("find.usages.constructor")
is KtProperty -> if (targetElement.isLocal)
KotlinBundle.message("find.usages.variable")
else
KotlinBundle.message("find.usages.property")
is KtTypeParameter -> KotlinBundle.message("find.usages.type.parameter")
is KtParameter -> KotlinBundle.message("find.usages.parameter")
is KtDestructuringDeclarationEntry -> KotlinBundle.message("find.usages.variable")
is KtTypeAlias -> KotlinBundle.message("find.usages.type.alias")
is KtLabeledExpression -> KotlinBundle.message("find.usages.label")
is KtImportAlias -> KotlinBundle.message("find.usages.import.alias")
is RenameJavaSyntheticPropertyHandler.SyntheticPropertyWrapper -> KotlinBundle.message("find.usages.property")
is KtLightClassForFacade -> KotlinBundle.message("find.usages.facade.class")
is RenameKotlinPropertyProcessor.PropertyMethodWrapper -> KotlinBundle.message("find.usages.property.accessor")
else -> null
}
val namedElement = if (targetElement is KtPropertyAccessor) {
targetElement.parent as? KtProperty
} else targetElement as? PsiNamedElement
@Suppress("FoldInitializerAndIfToElvis")
if (namedElement == null) {
return if (targetElement is KtElement) "'" + StringUtil.shortenTextWithEllipsis(
targetElement.text.collapseSpaces(),
53,
0
) + "'" else null
}
if (namedElement.language != KotlinLanguage.INSTANCE) return null
return when (location) {
is UsageViewTypeLocation -> elementKind()
is UsageViewShortNameLocation, is UsageViewLongNameLocation -> namedElement.name
is RefactoringDescriptionLocation -> {
val kind = elementKind() ?: return null
if (namedElement !is KtNamedDeclaration) return null
val renderFqName = location.includeParent() &&
namedElement !is KtTypeParameter &&
namedElement !is KtParameter &&
namedElement !is KtConstructor<*>
val desc = when (namedElement) {
is KtFunction -> {
val baseText = buildString {
append(namedElement.name ?: "")
namedElement.valueParameters.joinTo(this, prefix = "(", postfix = ")") {
(if (it.isVarArg) "vararg " else "") + (it.typeReference?.renderShort() ?: "")
}
namedElement.receiverTypeReference?.let { append(" on ").append(it.renderShort()) }
}
val parentFqName = if (renderFqName) namedElement.fqName().parent() else null
if (parentFqName?.isRoot != false) baseText else "${parentFqName.asString()}.$baseText"
}
else -> (if (renderFqName) namedElement.fqName().asString() else namedElement.name) ?: ""
}
"$kind ${CommonRefactoringUtil.htmlEmphasize(desc)}"
}
is HighlightUsagesDescriptionLocation -> {
val kind = elementKind() ?: return null
if (namedElement !is KtNamedDeclaration) return null
"$kind ${namedElement.name}"
}
else -> null
}
}
override val PsiElement.isRenameKotlinPropertyProcessor: Boolean
get() = this is RenameKotlinPropertyProcessor.PropertyMethodWrapper
}
@@ -19,72 +19,21 @@ import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter
import org.jetbrains.kotlin.types.typeUtil.isUnit
class KotlinFindUsagesProvider : FindUsagesProvider {
private val javaProvider by lazy { JavaFindUsagesProvider() }
override fun canFindUsagesFor(psiElement: PsiElement): Boolean =
psiElement is KtNamedDeclaration
override fun getWordsScanner(): WordsScanner? = KotlinWordsScanner()
override fun getHelpId(psiElement: PsiElement): String? = null
override fun getType(element: PsiElement): String {
return when (element) {
is KtNamedFunction -> KotlinBundle.message("find.usages.function")
is KtClass -> KotlinBundle.message("find.usages.class")
is KtParameter -> KotlinBundle.message("find.usages.parameter")
is KtProperty -> if (element.isLocal)
KotlinBundle.message("find.usages.variable")
else
KotlinBundle.message("find.usages.property")
is KtDestructuringDeclarationEntry -> KotlinBundle.message("find.usages.variable")
is KtTypeParameter -> KotlinBundle.message("find.usages.type.parameter")
is KtSecondaryConstructor -> KotlinBundle.message("find.usages.constructor")
is KtObjectDeclaration -> KotlinBundle.message("find.usages.object")
else -> ""
}
}
private val KtDeclaration.containerDescription: String?
get() {
containingClassOrObject?.let { return getDescriptiveName(it) }
(parent as? KtFile)?.parent?.let { return getDescriptiveName(it) }
return null
}
class KotlinFindUsagesProvider : KotlinFindUsagesProviderBase() {
override fun getDescriptiveName(element: PsiElement): String {
return when (element) {
is PsiDirectory, is PsiPackage, is PsiFile -> javaProvider.getDescriptiveName(element)
is KtClassOrObject -> {
if (element is KtObjectDeclaration && element.isObjectLiteral()) return "<unnamed>"
element.fqName?.asString() ?: element.name ?: "<unnamed>"
}
is KtProperty -> (element.name ?: "") + (element.containerDescription?.let { " of $it" } ?: "")
is KtFunction -> {
val name = element.name ?: ""
val descriptor = element.unsafeResolveToDescriptor() as FunctionDescriptor
val renderer = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS
val paramsDescription =
descriptor.valueParameters.joinToString(prefix = "(", postfix = ")") { renderer.renderType(it.type) }
val returnType = descriptor.returnType
val returnTypeDescription = if (returnType != null && !returnType.isUnit()) renderer.renderType(returnType) else null
val funDescription = "$name$paramsDescription" + (returnTypeDescription?.let { ": $it" } ?: "")
return funDescription + (element.containerDescription?.let { " of $it" } ?: "")
}
is KtLabeledExpression -> element.getLabelName() ?: ""
is KtImportAlias -> element.name ?: ""
is KtLightElement<*, *> -> element.kotlinOrigin?.let { getDescriptiveName(it) } ?: ""
is KtParameter -> {
if (element.isPropertyParameter()) {
(element.name ?: "") + (element.containerDescription?.let { " of $it" } ?: "")
} else {
element.name ?: ""
}
}
is PsiNamedElement -> element.name ?: ""
else -> ""
}
if (element !is KtFunction) return super.getDescriptiveName(element)
val name = element.name ?: ""
val descriptor = element.unsafeResolveToDescriptor() as FunctionDescriptor
val renderer = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS
val paramsDescription =
descriptor.valueParameters.joinToString(prefix = "(", postfix = ")") { renderer.renderType(it.type) }
val returnType = descriptor.returnType
val returnTypeDescription = if (returnType != null && !returnType.isUnit()) renderer.renderType(returnType) else null
val funDescription = "$name$paramsDescription" + (returnTypeDescription?.let { ": $it" } ?: "")
return funDescription + (element.containerDescription?.let { " of $it" } ?: "")
}
override fun getNodeText(element: PsiElement, useFullName: Boolean): String =
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.findUsages
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.idea.search.usagesSearch.dataClassComponentFunction
import org.jetbrains.kotlin.idea.search.usagesSearch.isConstructorUsage
import org.jetbrains.kotlin.psi.*
class KotlinFindUsagesSupportImpl : KotlinFindUsagesSupport {
override fun isCallReceiverRefersToCompanionObject(element: KtElement, companionObject: KtObjectDeclaration): Boolean =
org.jetbrains.kotlin.idea.search.usagesSearch.isCallReceiverRefersToCompanionObject(element, companionObject)
override fun isDataClassComponentFunction(element: KtParameter): Boolean =
element.dataClassComponentFunction() != null
override fun getTopMostOverriddenElementsToHighlight(target: PsiElement): List<PsiElement> =
org.jetbrains.kotlin.idea.search.usagesSearch.getTopMostOverriddenElementsToHighlight(target)
override fun tryRenderDeclarationCompactStyle(declaration: KtDeclaration): String? =
org.jetbrains.kotlin.idea.search.usagesSearch.tryRenderDeclarationCompactStyle(declaration)
override fun isConstructorUsage(psiReference: PsiReference, ktClassOrObject: KtClassOrObject): Boolean =
psiReference.isConstructorUsage(ktClassOrObject)
override fun checkSuperMethods(declaration: KtDeclaration, ignore: Collection<PsiElement>?, actionString: String): List<PsiElement> =
org.jetbrains.kotlin.idea.refactoring.checkSuperMethods(declaration, ignore, actionString)
override fun sourcesAndLibraries(delegate: GlobalSearchScope, project: Project): GlobalSearchScope =
org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope.sourcesAndLibraries(delegate, project)
}
@@ -46,7 +46,7 @@ import java.util.*
import com.intellij.codeInsight.daemon.impl.quickfix.ClassKind as IdeaClassKind
enum class ClassKind(@NonNls val keyword: String, @Nls val description: String) {
PLAIN_CLASS("class", KotlinBundle.message("find.usages.class")),
PLAIN_CLASS("class", KotlinBundle.message("text.class")),
ENUM_CLASS("enum class", KotlinBundle.message("text.enum")),
ENUM_ENTRY("", KotlinBundle.message("text.enum.constant")),
ANNOTATION_CLASS("annotation class", KotlinBundle.message("text.annotation")),
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.idea.references.findPsiDeclarations
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.idea.search.fileScope
import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
import org.jetbrains.kotlin.idea.search.isImportUsage
import org.jetbrains.kotlin.idea.util.ImportInsertHelperImpl
import org.jetbrains.kotlin.idea.util.getAllAccessibleFunctions
import org.jetbrains.kotlin.idea.util.getAllAccessibleVariables
@@ -136,7 +136,7 @@ private fun invokeRename(
private fun replaceUsages(usages: List<UsageContext>, newName: String) {
// case: inner element
for (usage in usages.asReversed()) {
val reference = usage.pointer.element?.safeAs<KtElement>()?.mainReference?.takeUnless(KtReference::isImportUsage) ?: continue
val reference = usage.pointer.element?.safeAs<KtElement>()?.mainReference?.takeUnless { it.isImportUsage() } ?: continue
val newExpression = reference.handleElementRename(newName) as? KtNameReferenceExpression ?: continue
if (usage.isExtension) {
newExpression.getQualifiedElementSelector()?.replace(newExpression)
@@ -0,0 +1,104 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.search
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.SearchScope
import org.jetbrains.kotlin.idea.core.isInheritable
import org.jetbrains.kotlin.idea.core.isOverridable
import org.jetbrains.kotlin.idea.search.declarationsSearch.forEachOverridingMethod
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.usagesSearch.*
import org.jetbrains.kotlin.idea.stubindex.KotlinTypeAliasShortNameIndex
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.expectedDeclarationIfAny
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.ImportPath
class KotlinSearchUsagesSupportImpl : KotlinSearchUsagesSupport {
override fun dataClassComponentMethodName(element: KtParameter): String? =
element.dataClassComponentFunction()?.name?.asString()
override fun hasType(element: KtExpression): Boolean =
org.jetbrains.kotlin.idea.search.usagesSearch.hasType(element)
override fun isSamInterface(psiClass: PsiClass): Boolean =
org.jetbrains.kotlin.idea.search.usagesSearch.isSamInterface(psiClass)
override fun <T : PsiNamedElement> filterDataClassComponentsIfDisabled(
elements: List<T>,
kotlinOptions: KotlinReferencesSearchOptions
): List<T> =
elements.filterDataClassComponentsIfDisabled(kotlinOptions)
override fun isCallableOverrideUsage(reference: PsiReference, declaration: KtNamedDeclaration): Boolean =
reference.isCallableOverrideUsage(declaration)
override fun isUsageInContainingDeclaration(reference: PsiReference, declaration: KtNamedDeclaration): Boolean =
reference.isUsageInContainingDeclaration(declaration)
override fun isExtensionOfDeclarationClassUsage(reference: PsiReference, declaration: KtNamedDeclaration): Boolean =
reference.isExtensionOfDeclarationClassUsage(declaration)
override fun getReceiverTypeSearcherInfo(psiElement: PsiElement, isDestructionDeclarationSearch: Boolean): ReceiverTypeSearcherInfo? =
psiElement.getReceiverTypeSearcherInfo(isDestructionDeclarationSearch)
override fun forceResolveReferences(file: KtFile, elements: List<KtElement>) =
file.forceResolveReferences(elements)
override fun scriptDefinitionExists(file: PsiFile): Boolean =
file.scriptDefinitionExists()
override fun getDefaultImports(file: KtFile): List<ImportPath> =
file.getDefaultImports()
override fun forEachKotlinOverride(
ktClass: KtClass,
members: List<KtNamedDeclaration>,
scope: SearchScope,
processor: (superMember: PsiElement, overridingMember: PsiElement) -> Boolean
): Boolean =
org.jetbrains.kotlin.idea.search.declarationsSearch.forEachKotlinOverride(
ktClass,
members,
scope,
processor
)
override fun forEachOverridingMethod(method: PsiMethod, scope: SearchScope, processor: (PsiMethod) -> Boolean): Boolean =
method.forEachOverridingMethod(scope, processor)
override fun findDeepestSuperMethodsNoWrapping(method: PsiElement): List<PsiElement> =
org.jetbrains.kotlin.idea.search.declarationsSearch.findDeepestSuperMethodsNoWrapping(method)
override fun findTypeAliasByShortName(shortName: String, project: Project, scope: GlobalSearchScope): Collection<KtTypeAlias> =
KotlinTypeAliasShortNameIndex.getInstance().get(shortName, project, scope)
override fun isInProjectSource(element: PsiElement, includeScriptsOutsideSourceRoots: Boolean): Boolean =
ProjectRootsUtil.isInProjectSource(element, includeScriptsOutsideSourceRoots)
override fun isOverridable(declaration: KtDeclaration): Boolean =
declaration.isOverridable()
override fun isInheritable(ktClass: KtClass): Boolean =
ktClass.isInheritable()
override fun formatJavaOrLightMethod(method: PsiMethod): String =
org.jetbrains.kotlin.idea.refactoring.formatJavaOrLightMethod(method)
override fun formatClass(classOrObject: KtClassOrObject): String =
org.jetbrains.kotlin.idea.refactoring.formatClass(classOrObject)
override fun expectedDeclarationIfAny(declaration: KtDeclaration): KtDeclaration? =
declaration.expectedDeclarationIfAny()
override fun isExpectDeclaration(declaration: KtDeclaration): Boolean =
declaration.isExpectDeclaration()
}
@@ -0,0 +1,92 @@
/*
* Copyright 2000-2017 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.search.declarationsSearch
import com.intellij.psi.*
import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.searches.OverridingMethodsSearch
import com.intellij.util.Processor
import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.isOverridable
import org.jetbrains.kotlin.idea.caches.lightClasses.KtFakeLightMethod
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.getDeepestSuperDeclarations
import org.jetbrains.kotlin.idea.search.excludeKotlinSources
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.substitutions.getTypeSubstitutor
import org.jetbrains.kotlin.util.findCallableMemberBySignature
import java.util.*
fun forEachKotlinOverride(
ktClass: KtClass,
members: List<KtNamedDeclaration>,
scope: SearchScope,
processor: (superMember: PsiElement, overridingMember: PsiElement) -> Boolean
): Boolean {
val baseClassDescriptor = runReadAction { ktClass.unsafeResolveToDescriptor() as ClassDescriptor }
val baseDescriptors =
runReadAction { members.mapNotNull { it.unsafeResolveToDescriptor() as? CallableMemberDescriptor }.filter { it.isOverridable } }
if (baseDescriptors.isEmpty()) return true
HierarchySearchRequest(ktClass, scope, true).searchInheritors().forEach(Processor { psiClass ->
val inheritor = psiClass.unwrapped as? KtClassOrObject ?: return@Processor true
runReadAction {
val inheritorDescriptor = inheritor.unsafeResolveToDescriptor() as ClassDescriptor
val substitutor =
getTypeSubstitutor(baseClassDescriptor.defaultType, inheritorDescriptor.defaultType) ?: return@runReadAction true
baseDescriptors.forEach {
val superMember = it.source.getPsi()!!
val overridingDescriptor = (it.substitute(substitutor) as? CallableMemberDescriptor)?.let { memberDescriptor ->
inheritorDescriptor.findCallableMemberBySignature(memberDescriptor)
}
val overridingMember = overridingDescriptor?.source?.getPsi()
if (overridingMember != null) {
if (!processor(superMember, overridingMember)) return@runReadAction false
}
}
true
}
})
return true
}
fun PsiMethod.forEachOverridingMethod(
scope: SearchScope = runReadAction { useScope },
processor: (PsiMethod) -> Boolean
): Boolean {
if (this !is KtFakeLightMethod) {
if (!OverridingMethodsSearch.search(this, scope.excludeKotlinSources(), true).forEach(processor)) return false
}
val ktMember = this.unwrapped as? KtNamedDeclaration ?: return true
val ktClass = runReadAction { ktMember.containingClassOrObject as? KtClass } ?: return true
return forEachKotlinOverride(ktClass, listOf(ktMember), scope) { _, overrider ->
val lightMethods = runReadAction { overrider.toPossiblyFakeLightMethods().distinctBy { it.unwrapped } }
lightMethods.all { processor(it) }
}
}
fun findDeepestSuperMethodsNoWrapping(method: PsiElement): List<PsiElement> {
val element = method.unwrapped
return when (element) {
is PsiMethod -> element.findDeepestSuperMethods().toList()
is KtCallableDeclaration -> {
val descriptor = element.resolveToDescriptorIfAny() as? CallableMemberDescriptor ?: return emptyList()
descriptor.getDeepestSuperDeclarations(false).mapNotNull {
it.source.getPsi() ?: DescriptorToSourceUtilsIde.getAnyDeclaration(element.project, it)
}
}
else -> emptyList()
}
}
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.search.usagesSearch
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.searches.MethodReferencesSearch
@@ -26,29 +27,59 @@ import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.project.NotUnderContentRootModuleInfo.project
import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.caches.resolve.resolveToParameterDescriptorIfAny
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMemberDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMethodDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaOrKotlinMemberDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.util.hasJavaResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.project.findAnalyzerServices
import org.jetbrains.kotlin.idea.references.unwrappedTargets
import org.jetbrains.kotlin.idea.search.ReceiverTypeSearcherInfo
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.util.FuzzyType
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType
import org.jetbrains.kotlin.idea.util.toFuzzyType
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.contains
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.descriptorUtil.isTypeRefinementEnabled
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.sam.getSingleAbstractMethodOrNull
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.isValidOperator
val KtDeclaration.descriptor: DeclarationDescriptor?
get() = if (this is KtParameter) this.descriptor else this.resolveToDescriptorIfAny(BodyResolveMode.FULL)
fun tryRenderDeclarationCompactStyle(declaration: KtDeclaration): String? =
declaration.descriptor?.let { DescriptorRenderer.COMPACT.render(it) }
fun isSamInterface(psiClass: PsiClass): Boolean {
val classDescriptor = psiClass.getJavaMemberDescriptor() as? JavaClassDescriptor
return classDescriptor != null && getSingleAbstractMethodOrNull(classDescriptor) != null
}
fun hasType(element: KtExpression): Boolean =
element.analyze(BodyResolveMode.PARTIAL).getType(element) != null
val KtDeclaration.constructor: ConstructorDescriptor?
get() {
@@ -60,9 +91,6 @@ val KtDeclaration.constructor: ConstructorDescriptor?
}
}
val KtParameter.descriptor: ValueParameterDescriptor?
get() = this.resolveToParameterDescriptorIfAny(BodyResolveMode.FULL)
val KtParameter.propertyDescriptor: PropertyDescriptor?
get() = this.resolveToDescriptorIfAny(BodyResolveMode.FULL) as? PropertyDescriptor
@@ -79,9 +107,6 @@ fun PsiReference.checkUsageVsOriginalDescriptor(
}
}
fun PsiReference.isImportUsage(): Boolean =
element.getNonStrictParentOfType<KtImportDirective>() != null
fun PsiReference.isConstructorUsage(ktClassOrObject: KtClassOrObject): Boolean = with(element) {
fun checkJavaUsage(): Boolean {
val call = getNonStrictParentOfType<PsiConstructorCall>()
@@ -306,4 +331,72 @@ fun <T : PsiNamedElement> List<T>.filterDataClassComponentsIfDisabled(kotlinOpti
}
return filter { !it.isComponentElement() }
}
}
fun KtFile.forceResolveReferences(elements: List<KtElement>) {
getResolutionFacade().analyze(elements, BodyResolveMode.PARTIAL)
}
private fun PsiElement.resolveTargetToDescriptor(isDestructionDeclarationSearch: Boolean): FunctionDescriptor? {
if (isDestructionDeclarationSearch && this is KtParameter) {
return dataClassComponentFunction()
}
return when {
this is KtDeclaration -> resolveToDescriptorIfAny(BodyResolveMode.FULL)
this is PsiMember && hasJavaResolutionFacade() ->
this.getJavaOrKotlinMemberDescriptor()
else -> null
} as? FunctionDescriptor
}
private fun containsTypeOrDerivedInside(declaration: KtDeclaration, typeToSearch: FuzzyType): Boolean {
fun KotlinType.containsTypeOrDerivedInside(type: FuzzyType): Boolean {
return type.checkIsSuperTypeOf(this) != null || arguments.any { !it.isStarProjection && it.type.containsTypeOrDerivedInside(type) }
}
val descriptor = declaration.resolveToDescriptorIfAny() as? CallableDescriptor
val type = descriptor?.returnType
return type != null && type.containsTypeOrDerivedInside(typeToSearch)
}
private fun FuzzyType.toPsiClass(project: Project): PsiClass? {
val classDescriptor = type.constructor.declarationDescriptor ?: return null
val classDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, classDescriptor)
return when (classDeclaration) {
is PsiClass -> classDeclaration
is KtClassOrObject -> classDeclaration.toLightClass()
else -> null
}
}
private fun PsiElement.extractReceiverType(isDestructionDeclarationSearch: Boolean): FuzzyType? {
val descriptor = resolveTargetToDescriptor(isDestructionDeclarationSearch)?.takeIf { it.isValidOperator() } ?: return null
return if (descriptor.isExtension) {
descriptor.fuzzyExtensionReceiverType()!!
} else {
val classDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return null
classDescriptor.defaultType.toFuzzyType(classDescriptor.typeConstructor.parameters)
}
}
fun PsiElement.getReceiverTypeSearcherInfo(isDestructionDeclarationSearch: Boolean): ReceiverTypeSearcherInfo? {
val receiverType = runReadAction { extractReceiverType(isDestructionDeclarationSearch) } ?: return null
val psiClass = runReadAction { receiverType.toPsiClass(project) }
return ReceiverTypeSearcherInfo(psiClass) {
containsTypeOrDerivedInside(it, receiverType)
}
}
fun KtFile.getDefaultImports(): List<ImportPath> {
val moduleInfo = getNullableModuleInfo() ?: return emptyList()
return TargetPlatformDetector.getPlatform(this).findAnalyzerServices(project).getDefaultImports(
IDELanguageSettingsProvider.getLanguageVersionSettings(moduleInfo, project),
includeLowPriorityImports = true
)
}
fun PsiFile.scriptDefinitionExists(): Boolean = findScriptDefinition() != null
@@ -11,7 +11,7 @@ import com.intellij.psi.PsiEnumConstant
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiModifierListOwner
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
import org.jetbrains.kotlin.idea.search.declarationsSearch.findDeepestSuperMethodsNoWrapping
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.findDeepestSuperMethodsNoWrapping
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.nj2k.isObjectOrCompanionObject
import org.jetbrains.kotlin.nj2k.psi