[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.for.1.call=Smart cast to {0} (for {1} call)
smart.cast.to.0=Smart cast to {0} smart.cast.to.0=Smart cast to {0}
replace.overloaded.operator.with.function.call=Replace overloaded operator with function call replace.overloaded.operator.with.function.call=Replace overloaded operator with function call
searching.for.implicit.usages=Searching for implicit usages...
class.initializer=<class initializer> class.initializer=<class initializer>
object.0=object{0} object.0=object{0}
show.non.public=Show non-public show.non.public=Show non-public
@@ -16,14 +16,14 @@
package org.jetbrains.kotlin.idea.search.usagesSearch package org.jetbrains.kotlin.idea.search.usagesSearch
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNamedElement import com.intellij.psi.PsiNamedElement
import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.LightClassUtil.PropertyAccessorsPsiMethods import org.jetbrains.kotlin.asJava.LightClassUtil.PropertyAccessorsPsiMethods
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.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.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* 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.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver 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.* import java.util.*
fun PsiNamedElement.getAccessorNames(readable: Boolean = true, writable: Boolean = true): List<String> { 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 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.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.search.excludeKotlinSources 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.stubindex.*
import org.jetbrains.kotlin.idea.util.CallType import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
@@ -18,6 +18,7 @@ dependencies {
compileOnly(project(":kotlin-reflect-api")) compileOnly(project(":kotlin-reflect-api"))
compileOnly(intellijCoreDep()) compileOnly(intellijCoreDep())
compileOnly(intellijDep()) compileOnly(intellijDep())
compileOnly(project(":compiler:light-classes"))
Platform[191].orLower { Platform[191].orLower {
compileOnly(intellijDep()) { includeJars("java-api", "java-impl") } compileOnly(intellijDep()) { includeJars("java-api", "java-impl") }
@@ -29,8 +30,14 @@ dependencies {
} }
sourceSets { sourceSets {
"main" { projectDefault() } "main" {
projectDefault()
resources.srcDirs(
"resources-en"
)
}
"test" { projectDefault() } "test" { projectDefault() }
} }
testsJar() 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.openapi.ui.Messages
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.search.searches.OverridingMethodsSearch 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.asJava.unwrapped
import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinBundleIndependent
import org.jetbrains.kotlin.idea.core.isOverridable 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.DelegatingFindMemberUsagesHandler
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindMemberUsagesHandler import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindMemberUsagesHandler
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinTypeParameterFindUsagesHandler 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.idea.references.mainReference
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
@@ -85,14 +85,14 @@ class KotlinFindUsagesHandlerFactory(project: Project) : FindUsagesHandlerFactor
val declarationsToSearch = checkSuperMethods( val declarationsToSearch = checkSuperMethods(
element, element,
null, null,
KotlinBundle.message("find.usages.action.text.find.usages.of") KotlinBundleIndependent.message("find.usages.action.text.find.usages.of")
) )
return handlerForMultiple(element, declarationsToSearch) return handlerForMultiple(element, declarationsToSearch)
} }
val function = element.ownerFunction val function = element.ownerFunction
if (function != null && function.isOverridable()) { if (function != null && function.isOverridable()) {
val psiMethod = function.toLightMethods().singleOrNull() val psiMethod = function.providedToLightMethods().singleOrNull()
if (psiMethod != null) { if (psiMethod != null) {
val hasOverridden = OverridingMethodsSearch.search(psiMethod).any() val hasOverridden = OverridingMethodsSearch.search(psiMethod).any()
if (hasOverridden && askWhetherShouldSearchForParameterInOverridingMethods(element)) { if (hasOverridden && askWhetherShouldSearchForParameterInOverridingMethods(element)) {
@@ -122,7 +122,7 @@ class KotlinFindUsagesHandlerFactory(project: Project) : FindUsagesHandlerFactor
val declarationsToSearch = checkSuperMethods( val declarationsToSearch = checkSuperMethods(
declaration, declaration,
null, null,
KotlinBundle.message("find.usages.action.text.find.usages.of") KotlinBundleIndependent.message("find.usages.action.text.find.usages.of")
) )
return handlerForMultiple(declaration, declarationsToSearch) 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 com.intellij.ui.StateRestoringCheckBox;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.asJava.LightClassProvider;
import org.jetbrains.kotlin.asJava.LightClassUtilsKt; import org.jetbrains.kotlin.asJava.LightClassUtilsKt;
import org.jetbrains.kotlin.idea.KotlinBundle; import org.jetbrains.kotlin.idea.KotlinBundleIndependent;
import org.jetbrains.kotlin.idea.core.PsiModificationUtilsKt;
import org.jetbrains.kotlin.idea.findUsages.KotlinClassFindUsagesOptions; 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.KtClass;
import org.jetbrains.kotlin.psi.KtClassOrObject; import org.jetbrains.kotlin.psi.KtClassOrObject;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt; import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import javax.swing.*; import javax.swing.*;
import static org.jetbrains.kotlin.asJava.LightClassUtilsKt.toLightClass;
public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog { public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
private StateRestoringCheckBox constructorUsages; private StateRestoringCheckBox constructorUsages;
private StateRestoringCheckBox derivedClasses; private StateRestoringCheckBox derivedClasses;
@@ -66,7 +64,7 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
@NotNull @NotNull
private static PsiClass getRepresentingPsiClass(@NotNull KtClassOrObject classOrObject) { private static PsiClass getRepresentingPsiClass(@NotNull KtClassOrObject classOrObject) {
PsiClass lightClass = toLightClass(classOrObject); PsiClass lightClass = LightClassProvider.Companion.providedToLightClass(classOrObject);
if (lightClass != null) return lightClass; if (lightClass != null) return lightClass;
// TODO: Remove this code when light classes are generated for builtins // TODO: Remove this code when light classes are generated for builtins
@@ -74,7 +72,7 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
String name = classOrObject.getName(); String name = classOrObject.getName();
if (name == null || name.isEmpty()) { if (name == null || name.isEmpty()) {
name = KotlinBundle.message("find.usages.class.name.anonymous"); name = KotlinBundleIndependent.message("find.usages.class.name.anonymous");
} }
PsiClass javaClass; PsiClass javaClass;
@@ -93,7 +91,7 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
//noinspection ConstantConditions //noinspection ConstantConditions
javaClass.getModifierList().setModifierProperty( javaClass.getModifierList().setModifierProperty(
PsiModifier.FINAL, PsiModifier.FINAL,
!(classOrObject instanceof KtClass && PsiModificationUtilsKt.isInheritable((KtClass) classOrObject)) !(classOrObject instanceof KtClass && KotlinSearchUsagesSupport.Companion.isInheritable((KtClass) classOrObject))
); );
javaClass.putUserData(ORIGINAL_CLASS, classOrObject); javaClass.putUserData(ORIGINAL_CLASS, classOrObject);
@@ -109,31 +107,31 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
Utils.renameCheckbox( Utils.renameCheckbox(
findWhatPanel, findWhatPanel,
FindBundle.message("find.what.methods.usages.checkbox"), FindBundle.message("find.what.methods.usages.checkbox"),
KotlinBundle.message("find.declaration.functions.usages.checkbox") KotlinBundleIndependent.message("find.declaration.functions.usages.checkbox")
); );
Utils.renameCheckbox( Utils.renameCheckbox(
findWhatPanel, findWhatPanel,
FindBundle.message("find.what.fields.usages.checkbox"), 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.implementing.classes.checkbox"));
Utils.removeCheckbox(findWhatPanel, FindBundle.message("find.what.derived.interfaces.checkbox")); Utils.removeCheckbox(findWhatPanel, FindBundle.message("find.what.derived.interfaces.checkbox"));
Utils.removeCheckbox(findWhatPanel, FindBundle.message("find.what.derived.classes.checkbox")); Utils.removeCheckbox(findWhatPanel, FindBundle.message("find.what.derived.classes.checkbox"));
derivedClasses = addCheckboxToPanel( derivedClasses = addCheckboxToPanel(
KotlinBundle.message("find.declaration.derived.classes.checkbox"), KotlinBundleIndependent.message("find.declaration.derived.classes.checkbox"),
getFindUsagesOptions().isDerivedClasses, getFindUsagesOptions().isDerivedClasses,
findWhatPanel, findWhatPanel,
true true
); );
derivedTraits = addCheckboxToPanel( derivedTraits = addCheckboxToPanel(
KotlinBundle.message("find.declaration.derived.interfaces.checkbox"), KotlinBundleIndependent.message("find.declaration.derived.interfaces.checkbox"),
getFindUsagesOptions().isDerivedInterfaces, getFindUsagesOptions().isDerivedInterfaces,
findWhatPanel, findWhatPanel,
true true
); );
constructorUsages = addCheckboxToPanel( constructorUsages = addCheckboxToPanel(
KotlinBundle.message("find.declaration.constructor.usages.checkbox"), KotlinBundleIndependent.message("find.declaration.constructor.usages.checkbox"),
getFindUsagesOptions().getSearchConstructorUsages(), getFindUsagesOptions().getSearchConstructorUsages(),
findWhatPanel, findWhatPanel,
true true
@@ -165,7 +163,7 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
KotlinClassFindUsagesOptions options = getFindUsagesOptions(); KotlinClassFindUsagesOptions options = getFindUsagesOptions();
if (isActual) { if (isActual) {
expectedUsages = addCheckboxToPanel( expectedUsages = addCheckboxToPanel(
KotlinBundle.message("find.usages.checkbox.name.expected.classes"), KotlinBundleIndependent.message("find.usages.checkbox.name.expected.classes"),
options.getSearchExpected(), options.getSearchExpected(),
optionsPanel, optionsPanel,
false false
@@ -177,7 +175,7 @@ public class KotlinFindClassUsagesDialog extends FindClassUsagesDialog {
public void configureLabelComponent(@NotNull SimpleColoredComponent coloredComponent) { public void configureLabelComponent(@NotNull SimpleColoredComponent coloredComponent) {
KtClassOrObject originalClass = getOriginalClass(); KtClassOrObject originalClass = getOriginalClass();
if (originalClass != null) { 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.annotations.NotNull;
import org.jetbrains.kotlin.asJava.LightClassUtilsKt; import org.jetbrains.kotlin.asJava.LightClassUtilsKt;
import org.jetbrains.kotlin.asJava.elements.KtLightMethod; 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.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.KtDeclaration;
import org.jetbrains.kotlin.psi.KtNamedDeclaration; import org.jetbrains.kotlin.psi.KtNamedDeclaration;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt; import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
@@ -61,7 +61,7 @@ public class KotlinFindFunctionUsagesDialog extends FindMethodUsagesDialog {
@Override @Override
public void configureLabelComponent(@NotNull SimpleColoredComponent coloredComponent) { public void configureLabelComponent(@NotNull SimpleColoredComponent coloredComponent) {
coloredComponent.append(RenderingUtilsKt.formatJavaOrLightMethod((PsiMethod) myPsiElement)); coloredComponent.append(KotlinSearchUsagesSupport.Companion.formatJavaOrLightMethod((PsiMethod) myPsiElement));
} }
@Override @Override
@@ -72,12 +72,12 @@ public class KotlinFindFunctionUsagesDialog extends FindMethodUsagesDialog {
Utils.renameCheckbox( Utils.renameCheckbox(
findWhatPanel, findWhatPanel,
FindBundle.message("find.what.implementing.methods.checkbox"), FindBundle.message("find.what.implementing.methods.checkbox"),
KotlinBundle.message("find.declaration.implementing.methods.checkbox") KotlinBundleIndependent.message("find.declaration.implementing.methods.checkbox")
); );
Utils.renameCheckbox( Utils.renameCheckbox(
findWhatPanel, findWhatPanel,
FindBundle.message("find.what.overriding.methods.checkbox"), 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( if (!Utils.renameCheckbox(
optionsPanel, optionsPanel,
FindBundle.message("find.options.include.overloaded.methods.checkbox"), 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( addCheckboxToPanel(
KotlinBundle.message("find.declaration.include.overloaded.methods.checkbox"), KotlinBundleIndependent.message("find.declaration.include.overloaded.methods.checkbox"),
FindSettings.getInstance().isSearchOverloadedMethods(), FindSettings.getInstance().isSearchOverloadedMethods(),
optionsPanel, optionsPanel,
false false
@@ -110,7 +110,7 @@ public class KotlinFindFunctionUsagesDialog extends FindMethodUsagesDialog {
KotlinFunctionFindUsagesOptions options = getFindUsagesOptions(); KotlinFunctionFindUsagesOptions options = getFindUsagesOptions();
if (isActual) { if (isActual) {
expectedUsages = addCheckboxToPanel( expectedUsages = addCheckboxToPanel(
KotlinBundle.message("find.usages.checkbox.name.expected.functions"), KotlinBundleIndependent.message("find.usages.checkbox.name.expected.functions"),
options.getSearchExpected(), options.getSearchExpected(),
optionsPanel, optionsPanel,
false false
@@ -27,7 +27,7 @@ import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.StateRestoringCheckBox; import com.intellij.ui.StateRestoringCheckBox;
import org.jetbrains.annotations.NotNull; 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.idea.findUsages.KotlinPropertyFindUsagesOptions;
import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
@@ -85,13 +85,13 @@ public class KotlinFindPropertyUsagesDialog extends JavaFindUsagesDialog<KotlinP
KotlinPropertyFindUsagesOptions options = getFindUsagesOptions(); KotlinPropertyFindUsagesOptions options = getFindUsagesOptions();
readAccesses = addCheckboxToPanel( readAccesses = addCheckboxToPanel(
KotlinBundle.message("find.declaration.property.readers.checkbox"), KotlinBundleIndependent.message("find.declaration.property.readers.checkbox"),
options.isReadAccess, options.isReadAccess,
findWhatPanel, findWhatPanel,
true true
); );
writeAccesses = addCheckboxToPanel( writeAccesses = addCheckboxToPanel(
KotlinBundle.message("find.declaration.property.writers.checkbox"), KotlinBundleIndependent.message("find.declaration.property.writers.checkbox"),
options.isWriteAccess, options.isWriteAccess,
findWhatPanel, findWhatPanel,
true true
@@ -116,8 +116,8 @@ public class KotlinFindPropertyUsagesDialog extends JavaFindUsagesDialog<KotlinP
if (isOpen || isAbstract) { if (isOpen || isAbstract) {
overrideUsages = addCheckboxToPanel( overrideUsages = addCheckboxToPanel(
isAbstract isAbstract
? KotlinBundle.message("find.declaration.implementing.properties.checkbox") ? KotlinBundleIndependent.message("find.declaration.implementing.properties.checkbox")
: KotlinBundle.message("find.declaration.overriding.properties.checkbox"), : KotlinBundleIndependent.message("find.declaration.overriding.properties.checkbox"),
FindSettings.getInstance().isSearchOverloadedMethods(), FindSettings.getInstance().isSearchOverloadedMethods(),
optionsPanel, optionsPanel,
false false
@@ -127,7 +127,7 @@ public class KotlinFindPropertyUsagesDialog extends JavaFindUsagesDialog<KotlinP
KotlinPropertyFindUsagesOptions options = getFindUsagesOptions(); KotlinPropertyFindUsagesOptions options = getFindUsagesOptions();
if (isActual) { if (isActual) {
expectedUsages = addCheckboxToPanel( expectedUsages = addCheckboxToPanel(
KotlinBundle.message("find.usages.checkbox.name.expected.properties"), KotlinBundleIndependent.message("find.usages.checkbox.name.expected.properties"),
options.getSearchExpected(), options.getSearchExpected(),
optionsPanel, optionsPanel,
false false
@@ -136,8 +136,8 @@ public class KotlinFindPropertyUsagesDialog extends JavaFindUsagesDialog<KotlinP
if (isDataClassConstructorProperty(property)) { if (isDataClassConstructorProperty(property)) {
JCheckBox dataClassComponentCheckBox = JCheckBox dataClassComponentCheckBox =
new JCheckBox(KotlinBundle.message("find.usages.checkbox.text.fast.data.class.component.search")); new JCheckBox(KotlinBundleIndependent.message("find.usages.checkbox.text.fast.data.class.component.search"));
dataClassComponentCheckBox.setToolTipText(KotlinBundle.message( dataClassComponentCheckBox.setToolTipText(KotlinBundleIndependent.message(
"find.usages.tool.tip.text.disable.search.for.data.class.components.and.destruction.declarations.project.wide.setting")); "find.usages.tool.tip.text.disable.search.for.data.class.components.and.destruction.declarations.project.wide.setting"));
Project project = property.getProject(); Project project = property.getProject();
dataClassComponentCheckBox.setSelected(getDisableComponentAndDestructionSearch(project)); dataClassComponentCheckBox.setSelected(getDisableComponentAndDestructionSearch(project));
@@ -18,10 +18,8 @@ package org.jetbrains.kotlin.idea.findUsages.dialogs;
import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleColoredComponent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesSupport;
import org.jetbrains.kotlin.idea.search.usagesSearch.UtilsKt;
import org.jetbrains.kotlin.psi.KtNamedDeclaration; import org.jetbrains.kotlin.psi.KtNamedDeclaration;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
@@ -34,9 +32,9 @@ class Utils {
@NotNull SimpleColoredComponent coloredComponent, @NotNull SimpleColoredComponent coloredComponent,
@NotNull KtNamedDeclaration declaration @NotNull KtNamedDeclaration declaration
) { ) {
DeclarationDescriptor descriptor = UtilsKt.getDescriptor(declaration); String renderedDeclaration = KotlinFindUsagesSupport.Companion.tryRenderDeclarationCompactStyle(declaration);
if (descriptor != null) { if (renderedDeclaration != null) {
coloredComponent.append(DescriptorRenderer.COMPACT.render(descriptor)); coloredComponent.append(renderedDeclaration);
} }
} }
@@ -27,8 +27,8 @@ import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.usageView.UsageInfo import com.intellij.usageView.UsageInfo
import com.intellij.usages.UsageViewManager import com.intellij.usages.UsageViewManager
import com.intellij.util.Query import com.intellij.util.Query
import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightClass
import org.jetbrains.kotlin.asJava.toLightElements import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightElements
import org.jetbrains.kotlin.idea.references.KtReference import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.psi.KtConstructor import org.jetbrains.kotlin.psi.KtConstructor
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
@@ -44,9 +44,9 @@ fun KtDeclaration.processAllExactUsages(
if (reference is KtReference) return listOf(this) if (reference is KtReference) return listOf(this)
return SmartList<PsiElement>().also { list -> return SmartList<PsiElement>().also { list ->
list += this list += this
list += toLightElements() list += providedToLightElements()
if (this is KtConstructor<*>) { 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.psi.search.searches.ReferencesSearch
import com.intellij.util.FilteredQuery import com.intellij.util.FilteredQuery
import com.intellij.util.Processor 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.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.KotlinClassFindUsagesOptions
import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory 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.findUsages.dialogs.KotlinFindClassUsagesDialog
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.idea.search.isImportUsage
import org.jetbrains.kotlin.idea.search.usagesSearch.isConstructorUsage
import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.contains import org.jetbrains.kotlin.psi.psiUtil.contains
import org.jetbrains.kotlin.psi.psiUtil.effectiveDeclarations import org.jetbrains.kotlin.psi.psiUtil.effectiveDeclarations
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType 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.* import java.util.*
class KotlinFindClassUsagesHandler( class KotlinFindClassUsagesHandler(
@@ -97,7 +93,7 @@ class KotlinFindClassUsagesHandler(
} }
if (kotlinOptions.searchConstructorUsages) { if (kotlinOptions.searchConstructorUsages) {
classOrObject.toLightClass()?.constructors?.filterIsInstance<KtLightMethod>()?.forEach { constructor -> classOrObject.providedToLightClass()?.constructors?.filterIsInstance<KtLightMethod>()?.forEach { constructor ->
val scope = constructor.useScope.intersectWith(options.searchScope) val scope = constructor.useScope.intersectWith(options.searchScope)
var query = MethodReferencesSearch.search(constructor, scope, true) var query = MethodReferencesSearch.search(constructor, scope, true)
if (kotlinOptions.isSkipImportStatements) { if (kotlinOptions.isSkipImportStatements) {
@@ -161,18 +157,11 @@ class KotlinFindClassUsagesHandler(
private fun processCompanionObjectInternalReferences(companionObject: KtObjectDeclaration): Boolean { private fun processCompanionObjectInternalReferences(companionObject: KtObjectDeclaration): Boolean {
val klass = companionObject.getStrictParentOfType<KtClass>() ?: return true val klass = companionObject.getStrictParentOfType<KtClass>() ?: return true
val companionObjectDescriptor = companionObject.descriptor
return !klass.anyDescendantOfType(fun(element: KtElement): Boolean { return !klass.anyDescendantOfType(fun(element: KtElement): Boolean {
if (element == companionObject) return false // skip companion object itself if (element == companionObject) return false // skip companion object itself
return if (element.isCallReceiverRefersToCompanionObject(companionObject)) {
val bindingContext = element.analyze() element.references.any { !referenceProcessor.process(it) }
val resolvedCall = bindingContext[BindingContext.CALL, element]?.getResolvedCall(bindingContext) ?: return false } else false
if ((resolvedCall.dispatchReceiver as? ImplicitClassReceiver)?.declarationDescriptor == companionObjectDescriptor
|| (resolvedCall.extensionReceiver as? ImplicitClassReceiver)?.declarationDescriptor == companionObjectDescriptor
) {
return element.references.any { !referenceProcessor.process(it) }
}
return false
}) })
} }
@@ -190,7 +179,7 @@ class KotlinFindClassUsagesHandler(
override fun getStringsToSearch(element: PsiElement): Collection<String> { override fun getStringsToSearch(element: PsiElement): Collection<String> {
val psiClass = when (element) { val psiClass = when (element) {
is PsiClass -> element is PsiClass -> element
is KtClassOrObject -> getElement().toLightClass() is KtClassOrObject -> getElement().providedToLightClass()
else -> null else -> null
} ?: return Collections.emptyList() } ?: return Collections.emptyList()
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2015 JetBrains s.r.o. * 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.
* 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.handlers 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.psi.search.searches.ReferencesSearch
import com.intellij.util.* import com.intellij.util.*
import org.jetbrains.annotations.TestOnly import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightMethods
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.idea.KotlinBundleIndependent
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.findUsages.* 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.KotlinFindFunctionUsagesDialog
import org.jetbrains.kotlin.idea.findUsages.dialogs.KotlinFindPropertyUsagesDialog import org.jetbrains.kotlin.idea.findUsages.dialogs.KotlinFindPropertyUsagesDialog
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest 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.KotlinReadWriteAccessDetector
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
import org.jetbrains.kotlin.idea.search.isImportUsage
import org.jetbrains.kotlin.idea.search.isOnlyKotlinSearch 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.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.* 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.HyperlinkEvent
import javax.swing.event.HyperlinkListener import javax.swing.event.HyperlinkListener
@@ -86,7 +70,7 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration> protected c
mustOpenInNewTab: Boolean mustOpenInNewTab: Boolean
): AbstractFindUsagesDialog { ): AbstractFindUsagesDialog {
val options = factory.findFunctionOptions val options = factory.findFunctionOptions
val lightMethod = getElement().toLightMethods().firstOrNull() val lightMethod = getElement().providedToLightMethods().firstOrNull()
if (lightMethod != null) { if (lightMethod != null) {
return KotlinFindFunctionUsagesDialog(lightMethod, project, options, toShowInNewTab, mustOpenInNewTab, isSingleFile, this) 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 is KtParameterList &&
propertyDeclaration.parent.parent is KtPrimaryConstructor && propertyDeclaration.parent.parent is KtPrimaryConstructor &&
propertyDeclaration.parent.parent.parent.let { it is KtClass && it.isData() } 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)) { if (element is KtElement && !isOnlyKotlinSearch(options.searchScope)) {
// TODO: very bad code!! ReferencesSearch does not work correctly for constructors and annotation parameters // TODO: very bad code!! ReferencesSearch does not work correctly for constructors and annotation parameters
val psiMethodScopeSearch = when { val psiMethodScopeSearch = when {
element is KtParameter && element.dataClassComponentFunction() != null -> element is KtParameter && element.isDataClassComponentFunction ->
options.searchScope.excludeKotlinSources() options.searchScope.excludeKotlinSources()
else -> options.searchScope else -> options.searchScope
} }
for (psiMethod in element.toLightMethods().filterDataClassComponentsIfDisabled(kotlinSearchOptions)) { for (psiMethod in element.providedToLightMethods().filterDataClassComponentsIfDisabled(kotlinSearchOptions)) {
addTask { addTask {
applyQueryFilters( applyQueryFilters(
element, element,
@@ -284,13 +268,8 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration> protected c
!isSingleFile && psiElement !is KtParameter !isSingleFile && psiElement !is KtParameter
override fun findReferencesToHighlight(target: PsiElement, searchScope: SearchScope): Collection<PsiReference> { 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()) { return if (baseDeclarations.isNotEmpty()) {
baseDeclarations.flatMap { baseDeclarations.flatMap {
@@ -311,7 +290,7 @@ abstract class KotlinFindMemberUsagesHandler<T : KtNamedDeclaration> protected c
private const val DISABLE_ONCE = "DISABLE_ONCE" private const val DISABLE_ONCE = "DISABLE_ONCE"
private const val DISABLE = "DISABLE" 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", "find.usages.text.find.usages.for.data.class.components.and.destruction.declarations",
DISABLE_ONCE, DISABLE_ONCE,
DISABLE 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.KotlinReferencePreservingUsageInfo
import org.jetbrains.kotlin.idea.findUsages.KotlinReferenceUsageInfo import org.jetbrains.kotlin.idea.findUsages.KotlinReferenceUsageInfo
import org.jetbrains.kotlin.idea.util.application.runReadAction 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.* import java.util.*
abstract class KotlinFindUsagesHandler<T : PsiElement>( 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.annotations.TestOnly
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult import org.jetbrains.kotlin.asJava.ImpreciseResolveResult
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.caches.trackers.KotlinCodeBlockModificationListener
import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.findTypeAliasByShortName
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.getDefaultImports
import org.jetbrains.kotlin.idea.project.findAnalyzerServices
import org.jetbrains.kotlin.idea.stubindex.KotlinTypeAliasShortNameIndex
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.ImportPath
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
/** /**
@@ -35,6 +31,7 @@ import java.util.concurrent.atomic.AtomicInteger
* with the given qualified name. * with the given qualified name.
*/ */
class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName: String) { class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName: String) {
private val targetShortName = targetClassFqName.substringAfterLast('.') private val targetShortName = targetClassFqName.substringAfterLast('.')
private val targetPackage = targetClassFqName.substringBeforeLast('.', "") private val targetPackage = targetClassFqName.substringBeforeLast('.', "")
@@ -125,7 +122,7 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
} }
private fun findPotentialTypeAliasConflicts(target: PsiClass) { 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) { for (candidate in candidates) {
packagesWithTypeAliases.add(candidate.containingKtFile.packageFqName.asString()) packagesWithTypeAliases.add(candidate.containingKtFile.packageFqName.asString())
} }
@@ -244,12 +241,4 @@ class PsiBasedClassResolver @TestOnly constructor(private val targetClassFqName:
} }
return Result.Ambiguity 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.psi.search.searches.ClassInheritorsSearch
import com.intellij.util.EmptyQuery import com.intellij.util.EmptyQuery
import com.intellij.util.Query import com.intellij.util.Query
import org.jetbrains.kotlin.asJava.toLightClassWithBuiltinMapping import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedCreateKtFakeLightClass
import org.jetbrains.kotlin.idea.caches.lightClasses.KtFakeLightClass import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightClassWithBuiltinMapping
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
fun HierarchySearchRequest<*>.searchInheritors(): Query<PsiClass> { fun HierarchySearchRequest<*>.searchInheritors(): Query<PsiClass> {
val psiClass: PsiClass = when (originalElement) { val psiClass: PsiClass = when (originalElement) {
is KtClassOrObject -> runReadAction { originalElement.toLightClassWithBuiltinMapping() ?: KtFakeLightClass(originalElement) } is KtClassOrObject -> runReadAction { originalElement.providedToLightClassWithBuiltinMapping() ?: providedCreateKtFakeLightClass(originalElement) }
is PsiClass -> originalElement is PsiClass -> originalElement
else -> null else -> null
} ?: return EmptyQuery.getEmptyQuery() } ?: return EmptyQuery.getEmptyQuery()
@@ -18,27 +18,20 @@ import com.intellij.util.EmptyQuery
import com.intellij.util.MergeQuery import com.intellij.util.MergeQuery
import com.intellij.util.Processor import com.intellij.util.Processor
import com.intellij.util.Query import com.intellij.util.Query
import org.jetbrains.kotlin.asJava.getRepresentativeLightMethod import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedCreateKtFakeLightMethod
import org.jetbrains.kotlin.asJava.unwrapped import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedGetRepresentativeLightMethod
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedIsKtFakeLightClass
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.idea.asJava.LightClassProvider.Companion.providedToLightMethods
import org.jetbrains.kotlin.descriptors.isOverridable import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.findDeepestSuperMethodsNoWrapping
import org.jetbrains.kotlin.idea.caches.lightClasses.KtFakeLightClass import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.forEachKotlinOverride
import org.jetbrains.kotlin.idea.caches.lightClasses.KtFakeLightMethod import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.forEachOverridingMethod
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.isOverridable
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.idea.search.allScope import org.jetbrains.kotlin.idea.search.allScope
import org.jetbrains.kotlin.idea.search.excludeKotlinSources import org.jetbrains.kotlin.idea.search.excludeKotlinSources
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject 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.* import java.util.*
fun PsiElement.isOverridableElement(): Boolean = when (this) { fun PsiElement.isOverridableElement(): Boolean = when (this) {
@@ -48,7 +41,7 @@ fun PsiElement.isOverridableElement(): Boolean = when (this) {
} }
fun HierarchySearchRequest<*>.searchOverriders(): Query<PsiMethod> { fun HierarchySearchRequest<*>.searchOverriders(): Query<PsiMethod> {
val psiMethods = runReadAction { originalElement.toLightMethods() } val psiMethods = runReadAction { originalElement.providedToLightMethods() }
if (psiMethods.isEmpty()) return EmptyQuery.getEmptyQuery() if (psiMethods.isEmpty()) return EmptyQuery.getEmptyQuery()
return psiMethods return psiMethods
@@ -111,44 +104,10 @@ fun PsiElement.toPossiblyFakeLightMethods(): List<PsiMethod> {
val element = unwrapped ?: return emptyList() val element = unwrapped ?: return emptyList()
val lightMethods = element.toLightMethods() val lightMethods = element.providedToLightMethods()
if (lightMethods.isNotEmpty()) return lightMethods if (lightMethods.isNotEmpty()) return lightMethods
return if (element is KtNamedDeclaration) listOfNotNull(KtFakeLightMethod.get(element)) else emptyList() return if (element is KtNamedDeclaration) listOfNotNull(providedCreateKtFakeLightMethod(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
} }
fun KtNamedDeclaration.forEachOverridingElement( fun KtNamedDeclaration.forEachOverridingElement(
@@ -157,29 +116,13 @@ fun KtNamedDeclaration.forEachOverridingElement(
): Boolean { ): Boolean {
val ktClass = runReadAction { containingClassOrObject as? KtClass } ?: return true 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 if (!OverridingMethodsSearch.search(baseMethod, scope.excludeKotlinSources(), true).all { processor(baseMethod, it) }) return false
} }
return forEachKotlinOverride(ktClass, listOf(this), scope) { baseElement, overrider -> processor(baseElement, overrider) } 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( fun PsiMethod.forEachImplementation(
scope: SearchScope = runReadAction { useScope }, scope: SearchScope = runReadAction { useScope },
processor: (PsiElement) -> Boolean processor: (PsiElement) -> Boolean
@@ -191,7 +134,7 @@ fun PsiMethod.forEachImplementation(
fun PsiClass.forEachDeclaredMemberOverride(processor: (superMember: PsiElement, overridingMember: PsiElement) -> Boolean) { fun PsiClass.forEachDeclaredMemberOverride(processor: (superMember: PsiElement, overridingMember: PsiElement) -> Boolean) {
val scope = runReadAction { useScope } val scope = runReadAction { useScope }
if (this !is KtFakeLightClass) { if (!providedIsKtFakeLightClass()) {
AllOverridingMethodsSearch.search(this, scope.excludeKotlinSources()).all { processor(it.first, it.second) } 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) 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) = 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.psi.search.searches.ReferencesSearch
import com.intellij.util.Processor import com.intellij.util.Processor
import com.intellij.util.containers.nullize 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.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightMember import org.jetbrains.kotlin.asJava.elements.KtLightMember
import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.elements.KtLightParameter import org.jetbrains.kotlin.asJava.elements.KtLightParameter
import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesSupport.Companion.sourcesAndLibraries
import org.jetbrains.kotlin.asJava.toLightElements import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.dataClassComponentMethodName
import org.jetbrains.kotlin.descriptors.FunctionDescriptor 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.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.search.* 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.Empty
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions.Companion.calculateEffectiveScope 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.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.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.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
import org.jetbrains.kotlin.psi.psiUtil.parents
import java.util.* import java.util.*
data class KotlinReferencesSearchOptions( data class KotlinReferencesSearchOptions(
@@ -76,7 +74,7 @@ data class KotlinReferencesSearchOptions(
): SearchScope { ): SearchScope {
val kotlinOptions = (parameters as? KotlinAwareReferencesSearchParameters)?.kotlinOptions ?: Empty val kotlinOptions = (parameters as? KotlinAwareReferencesSearchParameters)?.kotlinOptions ?: Empty
val elements = if (elementToSearch is KtDeclaration && !isOnlyKotlinSearch(parameters.scopeDeterminedByUser)) { val elements = if (elementToSearch is KtDeclaration && !isOnlyKotlinSearch(parameters.scopeDeterminedByUser)) {
elementToSearch.toLightElements().filterDataClassComponentsIfDisabled(kotlinOptions).nullize() elementToSearch.providedToLightElements().filterDataClassComponentsIfDisabled(kotlinOptions).nullize()
} else { } else {
null null
} ?: listOf(elementToSearch) } ?: listOf(elementToSearch)
@@ -194,7 +192,6 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
} }
} }
val classNameForCompanionObject = elementToSearch.getClassNameForCompanionObject() val classNameForCompanionObject = elementToSearch.getClassNameForCompanionObject()
if (classNameForCompanionObject != null) { if (classNameForCompanionObject != null) {
queryParameters.optimizer.searchWord( queryParameters.optimizer.searchWord(
@@ -220,25 +217,14 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
} }
if (kotlinOptions.searchForComponentConventions) { if (kotlinOptions.searchForComponentConventions) {
when (element) { searchForComponentConventions(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)
}
}
}
} }
} }
private fun PsiNamedElement.getClassNameForCompanionObject(): String? =
(this is KtObjectDeclaration && this.isCompanion())
.ifTrue { getNonStrictParentOfType<KtClass>()?.name }
private fun searchNamedArguments(parameter: KtParameter) { private fun searchNamedArguments(parameter: KtParameter) {
val parameterName = parameter.name ?: return val parameterName = parameter.name ?: return
val function = parameter.ownerFunction as? KtFunction ?: return val function = parameter.ownerFunction as? KtFunction ?: return
@@ -247,7 +233,7 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
var namedArgsScope = function.useScope.intersectWith(queryParameters.scopeDeterminedByUser) var namedArgsScope = function.useScope.intersectWith(queryParameters.scopeDeterminedByUser)
if (namedArgsScope is GlobalSearchScope) { if (namedArgsScope is GlobalSearchScope) {
namedArgsScope = KotlinSourceFilterScope.sourcesAndLibraries(namedArgsScope, project) namedArgsScope = sourcesAndLibraries(namedArgsScope, project)
val filesWithFunctionName = CacheManager.SERVICE.getInstance(project).getVirtualFilesWithWord( val filesWithFunctionName = CacheManager.SERVICE.getInstance(project).getVirtualFilesWithWord(
function.name!!, UsageSearchContext.IN_CODE, namedArgsScope, true function.name!!, UsageSearchContext.IN_CODE, namedArgsScope, true
@@ -275,7 +261,7 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
is KtNamedFunction, is KtSecondaryConstructor -> { is KtNamedFunction, is KtSecondaryConstructor -> {
val name = (element as KtFunction).name val name = (element as KtFunction).name
if (name != null) { if (name != null) {
val methods = LightClassUtil.getLightClassMethods(element) val methods = providedGetLightClassMethods(element)
for (method in methods) { for (method in methods) {
searchNamedElement(method) searchNamedElement(method)
} }
@@ -285,8 +271,8 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
} }
is KtProperty -> { is KtProperty -> {
val propertyMethods = LightClassUtil.getLightClassPropertyMethods(element) val propertyDeclarations = providedGetLightClassPropertyDeclarations(element)
propertyMethods.allDeclarations.forEach { searchNamedElement(it) } propertyDeclarations.forEach { searchNamedElement(it) }
processStaticsFromCompanionObject(element) processStaticsFromCompanionObject(element)
} }
@@ -294,8 +280,8 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
searchPropertyAccessorMethods(element) searchPropertyAccessorMethods(element)
if (element.getStrictParentOfType<KtPrimaryConstructor>() != null) { if (element.getStrictParentOfType<KtPrimaryConstructor>() != null) {
// Simple parameters without val and var shouldn't be processed here because of local search scope // Simple parameters without val and var shouldn't be processed here because of local search scope
val methods = LightClassUtil.getLightClassPropertyMethods(element) val parameterDeclarations = providedGetLightClassParameterDeclarations(element)
methods.allDeclarations.filterDataClassComponentsIfDisabled(kotlinOptions).forEach { searchNamedElement(it) } parameterDeclarations.filterDataClassComponentsIfDisabled(kotlinOptions).forEach { searchNamedElement(it) }
} }
} }
@@ -323,19 +309,19 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
} }
private fun searchPropertyAccessorMethods(origin: KtParameter) { private fun searchPropertyAccessorMethods(origin: KtParameter) {
origin.toLightElements().filterDataClassComponentsIfDisabled(kotlinOptions).forEach { searchNamedElement(it) } origin.providedToLightElements().filterDataClassComponentsIfDisabled(kotlinOptions).forEach { searchNamedElement(it) }
} }
private fun processKtClassOrObject(element: KtClassOrObject) { private fun processKtClassOrObject(element: KtClassOrObject) {
val className = element.name ?: return val className = element.name ?: return
val lightClass = element.toLightClass() ?: return val lightClass = element.providedToLightClass() ?: return
searchNamedElement(lightClass, className) searchNamedElement(lightClass, className)
if (element is KtObjectDeclaration && element.isCompanion()) { if (element is KtObjectDeclaration && element.isCompanion()) {
LightClassUtil.getLightFieldForCompanionObject(element)?.let { searchNamedElement(it) } providedGetLightFieldForCompanionObject(element)?.let { searchNamedElement(it) }
if (kotlinOptions.acceptCompanionObjectMembers) { if (kotlinOptions.acceptCompanionObjectMembers) {
val originLightClass = element.getStrictParentOfType<KtClass>()?.toLightClass() val originLightClass = element.getStrictParentOfType<KtClass>()?.providedToLightClass()
if (originLightClass != null) { if (originLightClass != null) {
val lightDeclarations: List<KtLightMember<*>?> = val lightDeclarations: List<KtLightMember<*>?> =
originLightClass.methods.map { it as? KtLightMethod } + originLightClass.fields.map { it as? KtLightField } 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( private fun searchDataClassComponentUsages(
containingClass: PsiClass?, containingClass: PsiClass?,
componentFunctionDescriptor: FunctionDescriptor, componentMethodName: String,
kotlinOptions: KotlinReferencesSearchOptions kotlinOptions: KotlinReferencesSearchOptions
) { ) {
val componentFunction = containingClass?.methods?.firstOrNull { val componentFunction = containingClass?.methods?.firstOrNull {
it.name == componentFunctionDescriptor.name.asString() && it.parameterList.parametersCount == 0 it.name == componentMethodName && it.parameterList.parametersCount == 0
} }
if (componentFunction != null) { if (componentFunction != null) {
searchNamedElement(componentFunction) searchNamedElement(componentFunction)
@@ -378,7 +391,7 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
.firstOrNull() as? KtObjectDeclaration ?: return emptyList() .firstOrNull() as? KtObjectDeclaration ?: return emptyList()
if (!originObject.isCompanion()) return emptyList() if (!originObject.isCompanion()) return emptyList()
val originClass = originObject.getStrictParentOfType<KtClass>() val originClass = originObject.getStrictParentOfType<KtClass>()
val originLightClass = originClass?.toLightClass() ?: return emptyList() val originLightClass = originClass?.providedToLightClass() ?: return emptyList()
val allMethods = originLightClass.allMethods val allMethods = originLightClass.allMethods
return allMethods.filter { it is KtLightMethod && it.kotlinOrigin == declaration } 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.ReferenceRange
import com.intellij.psi.search.RequestResultProcessor import com.intellij.psi.search.RequestResultProcessor
import com.intellij.util.Processor 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.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.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtNamedDeclaration 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.progress.ProgressIndicator
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement import com.intellij.psi.*
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.cache.impl.id.IdIndex import com.intellij.psi.impl.cache.impl.id.IdIndex
import com.intellij.psi.impl.cache.impl.id.IdIndexEntry import com.intellij.psi.impl.cache.impl.id.IdIndexEntry
import com.intellij.psi.search.GlobalSearchScope 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.psi.search.searches.ReferencesSearch
import com.intellij.util.CommonProcessors import com.intellij.util.CommonProcessors
import com.intellij.util.indexing.FileBasedIndex import com.intellij.util.indexing.FileBasedIndex
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.idea.KotlinFileType 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.idea.util.application.runReadAction
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtNamedDeclaration 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 org.jetbrains.kotlin.types.expressions.OperatorConventions
import java.util.* import java.util.*
@@ -141,6 +144,28 @@ fun findScriptsWithUsages(declaration: KtNamedDeclaration): List<KtFile> {
} }
return collector.results return collector.results
.mapNotNull { PsiManager.getInstance(project).findFile(it) as? KtFile } .mapNotNull { PsiManager.getInstance(project).findFile(it) as? KtFile }
.filter { it.findScriptDefinition() != null } .filter { it.scriptDefinitionExists() }
.toList() .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.JavaFileType
import com.intellij.ide.highlighter.XmlFileType import com.intellij.ide.highlighter.XmlFileType
import com.intellij.ide.projectView.impl.ProjectRootsUtil
import com.intellij.lang.java.JavaLanguage import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
@@ -22,37 +23,30 @@ import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.util.Processor import com.intellij.util.Processor
import org.jetbrains.annotations.TestOnly import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.KtNodeTypes 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.classes.KtLightClass
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.hasType
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.isInProjectSource
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMemberDescriptor import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.isSamInterface
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
import org.jetbrains.kotlin.idea.search.excludeFileTypes 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.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
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.idea.util.application.runReadAction
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName 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.*
import org.jetbrains.kotlin.psi.psiUtil.* 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.* import java.util.*
//TODO: check if smart search is too expensive //TODO: check if smart search is too expensive
class ExpressionsOfTypeProcessor( class ExpressionsOfTypeProcessor(
private val typeToSearch: FuzzyType, private val containsTypeOrDerivedInside: (KtDeclaration) -> Boolean,
private val classToSearch: PsiClass?, private val classToSearch: PsiClass?,
private val searchScope: SearchScope, private val searchScope: SearchScope,
private val project: Project, private val project: Project,
@@ -132,7 +126,7 @@ class ExpressionsOfTypeProcessor(
}) return }) return
// for class from library always use plain search because we cannot search usages in compiled code (we could though) // 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) possibleMatchesInScopeHandler(searchScope)
return return
} }
@@ -535,9 +529,7 @@ class ExpressionsOfTypeProcessor(
if (element.getStrictParentOfType<KtImportDirective>() != null) return true // ignore usage in import if (element.getStrictParentOfType<KtImportDirective>() != null) return true // ignore usage in import
val bindingContext = element.analyze(BodyResolveMode.PARTIAL) if (element.hasType) { // access to object or companion object
val hasType = bindingContext.getType(element) != null
if (hasType) { // access to object or companion object
processSuspiciousExpression(element) processSuspiciousExpression(element)
return true return true
} }
@@ -590,7 +582,7 @@ class ExpressionsOfTypeProcessor(
val parent = typeRefParent.parent val parent = typeRefParent.parent
if (parent is KtSuperTypeCallEntry) { if (parent is KtSuperTypeCallEntry) {
val classOrObject = (parent.parent as KtSuperTypeList).parent as KtClassOrObject val classOrObject = (parent.parent as KtSuperTypeList).parent as KtClassOrObject
val psiClass = classOrObject.toLightClass() val psiClass = classOrObject.providedToLightClass()
psiClass?.let { addClassToProcess(it) } psiClass?.let { addClassToProcess(it) }
return true return true
} }
@@ -599,7 +591,7 @@ class ExpressionsOfTypeProcessor(
is KtSuperTypeListEntry -> { // super-interface name in the list of bases is KtSuperTypeListEntry -> { // super-interface name in the list of bases
if (typeRef == typeRefParent.typeReference) { if (typeRef == typeRefParent.typeReference) {
val classOrObject = (typeRefParent.parent as KtSuperTypeList).parent as KtClassOrObject val classOrObject = (typeRefParent.parent as KtSuperTypeList).parent as KtClassOrObject
val psiClass = classOrObject.toLightClass() val psiClass = classOrObject.providedToLightClass()
psiClass?.let { addClassToProcess(it) } psiClass?.let { addClassToProcess(it) }
return true return true
} }
@@ -762,8 +754,7 @@ class ExpressionsOfTypeProcessor(
if (psiClass != null) { if (psiClass != null) {
testLog { "Resolved java class to descriptor: ${psiClass.qualifiedName}" } testLog { "Resolved java class to descriptor: ${psiClass.qualifiedName}" }
val classDescriptor = psiClass.getJavaMemberDescriptor() as? JavaClassDescriptor if (psiClass.isSamInterface) {
if (classDescriptor != null && getSingleAbstractMethodOrNull(classDescriptor) != null) {
addSamInterfaceToProcess(psiClass) addSamInterfaceToProcess(psiClass)
return true return true
} }
@@ -838,9 +829,7 @@ class ExpressionsOfTypeProcessor(
testLog { "Checked type of ${logPresentation(declaration)}" } testLog { "Checked type of ${logPresentation(declaration)}" }
val descriptor = declaration.resolveToDescriptorIfAny() as? CallableDescriptor ?: return if (containsTypeOrDerivedInside(declaration)) {
val type = descriptor.returnType
if (type != null && type.containsTypeOrDerivedInside(typeToSearch)) {
addCallableDeclarationOfOurType(declaration) addCallableDeclarationOfOurType(declaration)
} }
} }
@@ -907,10 +896,6 @@ class ExpressionsOfTypeProcessor(
return true // we don't know 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 { private fun isImplicitlyTyped(declaration: KtDeclaration): Boolean {
return when (declaration) { return when (declaration) {
is KtFunction -> !declaration.hasDeclaredReturnType() is KtFunction -> !declaration.hasDeclaredReturnType()
@@ -22,10 +22,8 @@ import com.intellij.psi.search.SearchRequestCollector
import com.intellij.psi.search.SearchScope import com.intellij.psi.search.SearchScope
import com.intellij.util.Processor import com.intellij.util.Processor
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions 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.psi.*
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
@@ -44,15 +42,6 @@ class DestructuringDeclarationReferenceSearcher(
options, options,
wordsToSearch = listOf("(") wordsToSearch = listOf("(")
) { ) {
override fun resolveTargetToDescriptor(): FunctionDescriptor? {
return if (targetDeclaration is KtParameter) {
targetDeclaration.dataClassComponentFunction()
} else {
super.resolveTargetToDescriptor()
}
}
override fun extractReference(element: KtElement): PsiReference? { override fun extractReference(element: KtElement): PsiReference? {
val destructuringDeclaration = element as? KtDestructuringDeclaration ?: return null val destructuringDeclaration = element as? KtDestructuringDeclaration ?: return null
val entries = destructuringDeclaration.entries val entries = destructuringDeclaration.entries
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.idea.search.usagesSearch.operators 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.ProgressIndicatorProvider
import com.intellij.openapi.progress.util.ProgressWrapper import com.intellij.openapi.progress.util.ProgressWrapper
import com.intellij.psi.* import com.intellij.psi.*
@@ -13,36 +12,25 @@ import com.intellij.psi.search.*
import com.intellij.util.Processor import com.intellij.util.Processor
import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.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.KotlinFileType
import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundleIndependent
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.forceResolveReferences
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.Companion.getReceiverTypeSearcherInfo
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.search.ideaExtensions.KotlinReferencesSearchOptions import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinRequestResultProcessor import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinRequestResultProcessor
import org.jetbrains.kotlin.idea.search.ifTrue
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor 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.logPresentation
import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor.Companion.testLog 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.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.lexer.KtTokens
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver 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.types.expressions.OperatorConventions
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.util.isValidOperator
import java.util.* import java.util.*
abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>( abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
@@ -89,10 +77,9 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
options: KotlinReferencesSearchOptions options: KotlinReferencesSearchOptions
): OperatorReferenceSearcher<*>? { ): OperatorReferenceSearcher<*>? {
return runReadAction { return runReadAction {
if (declaration.isValid) declaration.isValid.ifTrue {
createInReadAction(declaration, searchScope, consumer, optimizer, options) 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() { 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() val inProgress = SearchesInProgress.get()
if (psiClass != null) { if (psiClass != null) {
@@ -235,7 +214,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
try { try {
ExpressionsOfTypeProcessor( ExpressionsOfTypeProcessor(
receiverType, containsTypeOrDerivedInside,
psiClass, psiClass,
searchScope, searchScope,
project, 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) { private fun doPlainSearch(scope: SearchScope) {
testLog { "Used plain search of ${logPresentation(targetDeclaration)} in ${scope.logPresentation()}" } testLog { "Used plain search of ${logPresentation(targetDeclaration)} in ${scope.logPresentation()}" }
@@ -284,7 +242,7 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
} }
// resolve all references at once // resolve all references at once
(element.containingFile as KtFile).getResolutionFacade().analyze(elements, BodyResolveMode.PARTIAL) (element.containingFile as? KtFile)?.forceResolveReferences(elements)
refs refs
.filter { it.isReferenceTo(targetDeclaration) } .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 // we must unwrap progress indicator because ProgressWrapper does not do anything on changing text and fraction
val progress = ProgressWrapper.unwrap(ProgressIndicatorProvider.getGlobalProgressIndicator()) val progress = ProgressWrapper.unwrap(ProgressIndicatorProvider.getGlobalProgressIndicator())
progress?.pushState() progress?.pushState()
progress?.text = KotlinIdeaAnalysisBundle.message("searching.for.implicit.usages") progress?.text = KotlinIdeaAnalysisBundleIndependent.message("searching.for.implicit.usages")
try { try {
val files = runReadAction { FileTypeIndex.getFiles(KotlinFileType.INSTANCE, scope) } 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.command.CommandProcessor
import com.intellij.openapi.components.ComponentManager import com.intellij.openapi.components.ComponentManager
import com.intellij.openapi.progress.impl.CancellationCheck import com.intellij.openapi.progress.impl.CancellationCheck
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
fun <T> runReadAction(action: () -> T): T { 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 = inline fun <reified T : Any> ComponentManager.getServiceSafe(): T =
this.getService(T::class.java) ?: error("Unable to locate service ${T::class.java.name}") 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.components.ComponentManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.annotations.Nls import org.jetbrains.annotations.Nls
import com.intellij.openapi.project.DumbService
fun <T> runReadAction(action: () -> T): T { fun <T> runReadAction(action: () -> T): T {
return ApplicationManager.getApplication().runReadAction<T>(action) 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 = inline fun <reified T : Any> ComponentManager.getServiceSafe(): T =
this.getService(T::class.java) ?: error("Unable to locate service ${T::class.java.name}") 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.ProgressIndicatorProvider
import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.project.DumbService
fun <T> runReadAction(action: () -> T): T { fun <T> runReadAction(action: () -> T): T {
return ApplicationManager.getApplication().runReadAction<T>(action) 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}") this.getService(T::class.java) ?: error("Unable to locate service ${T::class.java.name}")
fun <T> Project.getServiceIfCreated(serviceClass: Class<T>): T? = 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.DebuggerClassNameProvider.Companion.getRelevantElement
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches.ComputedClassNames 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.stubindex.KotlinSourceFilterScope
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.application.runReadAction 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.member=Member
override.declaration.delete.multiple.parameters={0} is a part of method hierarchy. Do you want to delete multiple parameters? 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.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.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 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.text.inline.function.call.site=inline function call site
filters.title.navigate.to=Navigate to 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.named.argument=Named argument
find.usages.type.type.alias=Type alias find.usages.type.type.alias=Type alias
find.usages.type.callable.reference=Callable reference 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"/> <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" <fileType name="Kotlin"
implementationClass="org.jetbrains.kotlin.idea.KotlinFileType" implementationClass="org.jetbrains.kotlin.idea.KotlinFileType"
fieldName="INSTANCE" fieldName="INSTANCE"
@@ -211,6 +211,9 @@
<projectService serviceInterface="org.jetbrains.kotlin.asJava.KotlinAsJavaSupport" <projectService serviceInterface="org.jetbrains.kotlin.asJava.KotlinAsJavaSupport"
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.IDEKotlinAsJavaSupport"/> 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" <projectService serviceInterface="org.jetbrains.kotlin.psi.KtFileClassProvider"
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.KtFileClassProviderImpl"/> serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.KtFileClassProviderImpl"/>
@@ -281,6 +284,12 @@
<projectService serviceInterface="org.jetbrains.kotlin.idea.debugger.coroutine.DebuggerListener" <projectService serviceInterface="org.jetbrains.kotlin.idea.debugger.coroutine.DebuggerListener"
serviceImplementation="org.jetbrains.kotlin.idea.debugger.coroutine.CoroutineDebuggerListener"/> 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"/> <errorHandler implementation="org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter"/>
<registryKey <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 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.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.RenameJavaSyntheticPropertyHandler
import org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinPropertyProcessor 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 { class KotlinElementDescriptionProvider : KotlinElementDescriptionProviderBase() {
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>") override val PsiElement.isRenameJavaSyntheticPropertyHandler: Boolean
get() = this is RenameJavaSyntheticPropertyHandler.SyntheticPropertyWrapper
private fun KtNamedDeclaration.fqName(): FqNameUnsafe { override val PsiElement.isRenameKotlinPropertyProcessor: Boolean
containingClassOrObject?.let { get() = this is RenameKotlinPropertyProcessor.PropertyMethodWrapper
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
}
}
} }
@@ -19,72 +19,21 @@ import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
class KotlinFindUsagesProvider : FindUsagesProvider { class KotlinFindUsagesProvider : KotlinFindUsagesProviderBase() {
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
}
override fun getDescriptiveName(element: PsiElement): String { override fun getDescriptiveName(element: PsiElement): String {
return when (element) {
is PsiDirectory, is PsiPackage, is PsiFile -> javaProvider.getDescriptiveName(element) if (element !is KtFunction) return super.getDescriptiveName(element)
is KtClassOrObject -> {
if (element is KtObjectDeclaration && element.isObjectLiteral()) return "<unnamed>" val name = element.name ?: ""
element.fqName?.asString() ?: element.name ?: "<unnamed>" val descriptor = element.unsafeResolveToDescriptor() as FunctionDescriptor
} val renderer = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS
is KtProperty -> (element.name ?: "") + (element.containerDescription?.let { " of $it" } ?: "") val paramsDescription =
is KtFunction -> { descriptor.valueParameters.joinToString(prefix = "(", postfix = ")") { renderer.renderType(it.type) }
val name = element.name ?: "" val returnType = descriptor.returnType
val descriptor = element.unsafeResolveToDescriptor() as FunctionDescriptor val returnTypeDescription = if (returnType != null && !returnType.isUnit()) renderer.renderType(returnType) else null
val renderer = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS val funDescription = "$name$paramsDescription" + (returnTypeDescription?.let { ": $it" } ?: "")
val paramsDescription = return funDescription + (element.containerDescription?.let { " of $it" } ?: "")
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 -> ""
}
} }
override fun getNodeText(element: PsiElement, useFullName: Boolean): String = 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 import com.intellij.codeInsight.daemon.impl.quickfix.ClassKind as IdeaClassKind
enum class ClassKind(@NonNls val keyword: String, @Nls val description: String) { 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_CLASS("enum class", KotlinBundle.message("text.enum")),
ENUM_ENTRY("", KotlinBundle.message("text.enum.constant")), ENUM_ENTRY("", KotlinBundle.message("text.enum.constant")),
ANNOTATION_CLASS("annotation class", KotlinBundle.message("text.annotation")), 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.mainReference
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.idea.search.fileScope 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.ImportInsertHelperImpl
import org.jetbrains.kotlin.idea.util.getAllAccessibleFunctions import org.jetbrains.kotlin.idea.util.getAllAccessibleFunctions
import org.jetbrains.kotlin.idea.util.getAllAccessibleVariables import org.jetbrains.kotlin.idea.util.getAllAccessibleVariables
@@ -136,7 +136,7 @@ private fun invokeRename(
private fun replaceUsages(usages: List<UsageContext>, newName: String) { private fun replaceUsages(usages: List<UsageContext>, newName: String) {
// case: inner element // case: inner element
for (usage in usages.asReversed()) { 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 val newExpression = reference.handleElementRename(newName) as? KtNameReferenceExpression ?: continue
if (usage.isExtension) { if (usage.isExtension) {
newExpression.getQualifiedElementSelector()?.replace(newExpression) 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 package org.jetbrains.kotlin.idea.search.usagesSearch
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.search.SearchScope import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.searches.MethodReferencesSearch import com.intellij.psi.search.searches.MethodReferencesSearch
@@ -26,29 +27,59 @@ import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.elements.KtLightElement import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.asJava.unwrapped import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.* 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.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.caches.resolve.resolveToParameterDescriptorIfAny 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.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.references.unwrappedTargets
import org.jetbrains.kotlin.idea.search.ReceiverTypeSearcherInfo
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions 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.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.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.contains import org.jetbrains.kotlin.psi.psiUtil.contains
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.* 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.isTypeRefinementEnabled
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode 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? fun tryRenderDeclarationCompactStyle(declaration: KtDeclaration): String? =
get() = if (this is KtParameter) this.descriptor else this.resolveToDescriptorIfAny(BodyResolveMode.FULL) 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? val KtDeclaration.constructor: ConstructorDescriptor?
get() { get() {
@@ -60,9 +91,6 @@ val KtDeclaration.constructor: ConstructorDescriptor?
} }
} }
val KtParameter.descriptor: ValueParameterDescriptor?
get() = this.resolveToParameterDescriptorIfAny(BodyResolveMode.FULL)
val KtParameter.propertyDescriptor: PropertyDescriptor? val KtParameter.propertyDescriptor: PropertyDescriptor?
get() = this.resolveToDescriptorIfAny(BodyResolveMode.FULL) as? 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 PsiReference.isConstructorUsage(ktClassOrObject: KtClassOrObject): Boolean = with(element) {
fun checkJavaUsage(): Boolean { fun checkJavaUsage(): Boolean {
val call = getNonStrictParentOfType<PsiConstructorCall>() val call = getNonStrictParentOfType<PsiConstructorCall>()
@@ -306,4 +331,72 @@ fun <T : PsiNamedElement> List<T>.filterDataClassComponentsIfDisabled(kotlinOpti
} }
return filter { !it.isComponentElement() } 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.PsiMethod
import com.intellij.psi.PsiModifierListOwner import com.intellij.psi.PsiModifierListOwner
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName 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.name.SpecialNames
import org.jetbrains.kotlin.nj2k.isObjectOrCompanionObject import org.jetbrains.kotlin.nj2k.isObjectOrCompanionObject
import org.jetbrains.kotlin.nj2k.psi import org.jetbrains.kotlin.nj2k.psi