From 5383d8e169391bb8a165478e04e5d2d3a383d1fb Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 6 May 2024 14:52:52 +0200 Subject: [PATCH] [kotlin] k2: find usages on class: allow to filter out constructor usages in kmp projects - for k1 constructor usages are filtered in the current source set as before ^KTIJ-29819 fixed ^KTIJ-29820 fixed GitOrigin-RevId: 9df16dc174bc05c4fdff672feabd40f9b2aba0b8 --- .../idea/search/KotlinSearchUsagesSupport.kt | 5 +++++ .../ideaExtensions/KotlinRequestResultProcessor.kt | 11 +++++++++++ .../idea/search/KotlinSearchUsagesSupportImpl.kt | 5 +++++ .../kotlin/findUsages/FindUsagesMultiModuleTest.kt | 8 ++++++++ .../findClassConstructors/common/common.kt | 2 ++ .../findClassConstructors/directives.txt | 1 + .../findClassConstructors/js/js.kt | 5 +++++ .../findClassConstructors/js/js.results.txt | 3 +++ .../findClassConstructors/jvm/jvm.kt | 2 ++ .../common/common.kt | 2 ++ .../directives.txt | 1 + .../js/js.fir.results.txt | 0 .../findClassUsagesWithoutConstructors/js/js.kt | 5 +++++ .../js/js.results.txt | 2 ++ .../findClassUsagesWithoutConstructors/jvm/jvm.kt | 2 ++ .../findCommonClassFromActual/jvm/jvm.kt | 2 +- .../findCommonSuperclass/common/common.kt | 2 +- .../searching/usages/KotlinK2FindUsagesSupport.kt | 12 +++++++++--- .../usages/KotlinK2SearchUsagesSupport.kt | 14 +++++++++----- .../kotlin/idea/test/AbstractMultiModuleTest.kt | 11 +++++++---- 20 files changed, 81 insertions(+), 14 deletions(-) create mode 100644 plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/common/common.kt create mode 100644 plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/directives.txt create mode 100644 plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/js/js.kt create mode 100644 plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/js/js.results.txt create mode 100644 plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/jvm/jvm.kt create mode 100644 plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/common/common.kt create mode 100644 plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/directives.txt create mode 100644 plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/js/js.fir.results.txt create mode 100644 plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/js/js.kt create mode 100644 plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/js/js.results.txt create mode 100644 plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/jvm/jvm.kt diff --git a/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/search/KotlinSearchUsagesSupport.kt b/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/search/KotlinSearchUsagesSupport.kt index 76f4bc90b7e5..0f0dc630d875 100644 --- a/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/search/KotlinSearchUsagesSupport.kt +++ b/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/search/KotlinSearchUsagesSupport.kt @@ -63,6 +63,9 @@ interface KotlinSearchUsagesSupport { fun PsiReference.isUsageInContainingDeclaration(declaration: KtNamedDeclaration): Boolean = getInstance(declaration.project).isUsageInContainingDeclaration(this, declaration) + fun PsiReference.isUsageOfActual(declaration: KtNamedDeclaration): Boolean = + getInstance(declaration.project).isUsageOfActual(this, declaration) + fun PsiReference.isExtensionOfDeclarationClassUsage(declaration: KtNamedDeclaration): Boolean = getInstance(declaration.project).isExtensionOfDeclarationClassUsage(this, declaration) @@ -109,6 +112,8 @@ interface KotlinSearchUsagesSupport { getInstance(psiMethod.project).createConstructorHandle(psiMethod) } + fun isUsageOfActual(reference: PsiReference, declaration: KtNamedDeclaration): Boolean + fun isInvokeOfCompanionObject(psiReference: PsiReference, searchTarget: KtNamedDeclaration): Boolean fun isCallableOverrideUsage(reference: PsiReference, declaration: KtNamedDeclaration): Boolean diff --git a/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinRequestResultProcessor.kt b/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinRequestResultProcessor.kt index f48447fbe017..b7277bec9307 100644 --- a/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinRequestResultProcessor.kt +++ b/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinRequestResultProcessor.kt @@ -10,11 +10,16 @@ import com.intellij.psi.ReferenceRange import com.intellij.psi.search.RequestResultProcessor import com.intellij.util.Processor import org.jetbrains.kotlin.asJava.unwrapped +import org.jetbrains.kotlin.idea.base.psi.isExpectDeclaration import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference +import org.jetbrains.kotlin.idea.references.unwrappedTargets +import org.jetbrains.kotlin.idea.search.ExpectActualSupport import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.SearchUtils.isCallableOverrideUsage import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.SearchUtils.isExtensionOfDeclarationClassUsage import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.SearchUtils.isInvokeOfCompanionObject import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.SearchUtils.isUsageInContainingDeclaration +import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.SearchUtils.isUsageOfActual +import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDestructuringDeclaration import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtNamedDeclaration @@ -55,7 +60,13 @@ class KotlinRequestResultProcessor( if (resolve()?.unwrapped == element.originalElement) { return true } + if (originalElement is KtNamedDeclaration) { + if (options.searchForExpectedUsages && isUsageOfActual(originalElement) + ) { + return true + } + if (isInvokeOfCompanionObject(originalElement)) { return true } diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/search/KotlinSearchUsagesSupportImpl.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/search/KotlinSearchUsagesSupportImpl.kt index b65f693c738e..4ff87923b89a 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/search/KotlinSearchUsagesSupportImpl.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/search/KotlinSearchUsagesSupportImpl.kt @@ -21,6 +21,11 @@ class KotlinSearchUsagesSupportImpl : KotlinSearchUsagesSupport { return false } + override fun isUsageOfActual( + reference: PsiReference, + declaration: KtNamedDeclaration + ): Boolean = false + override fun isCallableOverrideUsage(reference: PsiReference, declaration: KtNamedDeclaration): Boolean = reference.isCallableOverrideUsage(declaration) diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/findUsages/FindUsagesMultiModuleTest.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/findUsages/FindUsagesMultiModuleTest.kt index a599f0b70cff..8a006ed8f27c 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/findUsages/FindUsagesMultiModuleTest.kt +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/findUsages/FindUsagesMultiModuleTest.kt @@ -69,6 +69,14 @@ open class FindUsagesMultiModuleTest : AbstractFindUsagesMultiModuleTest() { doTest() } + fun testFindClassConstructors() { + doTest() + } + + fun testFindClassUsagesWithoutConstructors() { + doTest() + } + private fun doTest() { setupMppProjectFromDirStructure(getTestdataFile()) doFindUsagesTest() diff --git a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/common/common.kt b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/common/common.kt new file mode 100644 index 000000000000..92afa8f8e379 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/common/common.kt @@ -0,0 +1,2 @@ +expect open class Clazz004() +val ac = Clazz004() \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/directives.txt b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/directives.txt new file mode 100644 index 000000000000..7f5a7487e171 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/directives.txt @@ -0,0 +1 @@ +// FIR_COMPARISON diff --git a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/js/js.kt b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/js/js.kt new file mode 100644 index 000000000000..814f9e16810f --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/js/js.kt @@ -0,0 +1,5 @@ +// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtClass +// OPTIONS: constructorUsages, expected +actual open class Clazz004 actual constructor() +val a1 = Clazz004() +// IGNORE_K2_LOG \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/js/js.results.txt b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/js/js.results.txt new file mode 100644 index 000000000000..dfbd5976a2e2 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/js/js.results.txt @@ -0,0 +1,3 @@ +[common.kt] New instance creation 2 val ac = Clazz004() +[js.kt] New instance creation 4 val a1 = Clazz004() +[jvm.kt] New instance creation 2 val a2 = Clazz004() \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/jvm/jvm.kt b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/jvm/jvm.kt new file mode 100644 index 000000000000..2cf9a760d2af --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassConstructors/jvm/jvm.kt @@ -0,0 +1,2 @@ +actual open class Clazz004 actual constructor() +val a2 = Clazz004() \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/common/common.kt b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/common/common.kt new file mode 100644 index 000000000000..92afa8f8e379 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/common/common.kt @@ -0,0 +1,2 @@ +expect open class Clazz004() +val ac = Clazz004() \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/directives.txt b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/directives.txt new file mode 100644 index 000000000000..7f5a7487e171 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/directives.txt @@ -0,0 +1 @@ +// FIR_COMPARISON diff --git a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/js/js.fir.results.txt b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/js/js.fir.results.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/js/js.kt b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/js/js.kt new file mode 100644 index 000000000000..7766cbd55556 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/js/js.kt @@ -0,0 +1,5 @@ +// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtClass +// OPTIONS: usages, expected +actual open class Clazz004 actual constructor() +val a1 = Clazz004() +// IGNORE_K2_LOG \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/js/js.results.txt b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/js/js.results.txt new file mode 100644 index 000000000000..60279b7be9c0 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/js/js.results.txt @@ -0,0 +1,2 @@ +[common.kt] New instance creation 2 val ac = Clazz004() +[jvm.kt] New instance creation 2 val a2 = Clazz004() \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/jvm/jvm.kt b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/jvm/jvm.kt new file mode 100644 index 000000000000..2cf9a760d2af --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findClassUsagesWithoutConstructors/jvm/jvm.kt @@ -0,0 +1,2 @@ +actual open class Clazz004 actual constructor() +val a2 = Clazz004() \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findCommonClassFromActual/jvm/jvm.kt b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findCommonClassFromActual/jvm/jvm.kt index 7a811244b00a..39f68df139fa 100644 --- a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findCommonClassFromActual/jvm/jvm.kt +++ b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findCommonClassFromActual/jvm/jvm.kt @@ -1,5 +1,5 @@ // PSI_ELEMENT: org.jetbrains.kotlin.psi.KtClass -// OPTIONS: usages, expected +// OPTIONS: usages, constructorUsages, expected actual class My(val s: String) { actual fun boo() {} diff --git a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findCommonSuperclass/common/common.kt b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findCommonSuperclass/common/common.kt index 96b54600db57..4d716ab72a8d 100644 --- a/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findCommonSuperclass/common/common.kt +++ b/plugins/kotlin/idea/tests/testData/multiModuleFindUsages/findCommonSuperclass/common/common.kt @@ -1,5 +1,5 @@ // PSI_ELEMENT: org.jetbrains.kotlin.psi.KtClass -// OPTIONS: usages, expected +// OPTIONS: usages, constructorUsages, expected expect open class OClass(i: Int) expect class Inheritor : OClass \ No newline at end of file diff --git a/plugins/kotlin/kotlin.searching/src/org/jetbrains/kotlin/idea/searching/usages/KotlinK2FindUsagesSupport.kt b/plugins/kotlin/kotlin.searching/src/org/jetbrains/kotlin/idea/searching/usages/KotlinK2FindUsagesSupport.kt index f0edcf302ab5..2f9b379ee2aa 100644 --- a/plugins/kotlin/kotlin.searching/src/org/jetbrains/kotlin/idea/searching/usages/KotlinK2FindUsagesSupport.kt +++ b/plugins/kotlin/kotlin.searching/src/org/jetbrains/kotlin/idea/searching/usages/KotlinK2FindUsagesSupport.kt @@ -15,8 +15,9 @@ import org.jetbrains.kotlin.analysis.api.renderer.base.annotations.KtRendererAnn import org.jetbrains.kotlin.analysis.api.renderer.declarations.KtDeclarationRenderer import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol -import org.jetbrains.kotlin.analysis.api.symbols.KtClassifierSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtConstructorSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol import org.jetbrains.kotlin.asJava.unwrapped import org.jetbrains.kotlin.idea.base.analysis.api.utils.analyzeInModalWindow import org.jetbrains.kotlin.idea.base.analysis.api.utils.getImplicitReceivers @@ -108,8 +109,13 @@ internal class KotlinK2FindUsagesSupport : KotlinFindUsagesSupport { is KtFunctionCall<*> -> { val constructorSymbol = call.symbol as? KtConstructorSymbol ?: return@withResolvedCall false val constructedClassSymbol = - constructorSymbol.getContainingSymbol() as? KtClassifierSymbol ?: return@withResolvedCall false - constructedClassSymbol == ktClassOrObject.getClassOrObjectSymbol() + constructorSymbol.getContainingSymbol() as? KtClassLikeSymbol ?: return@withResolvedCall false + val classOrObjectSymbol = ktClassOrObject.getClassOrObjectSymbol() + + fun KtClassLikeSymbol.getExpectsOrSelf(): List = (listOf(this).takeIf { isExpect } ?: getExpectsForActual()) + + constructedClassSymbol == classOrObjectSymbol || + constructedClassSymbol.getExpectsOrSelf() == classOrObjectSymbol?.getExpectsOrSelf() } else -> false diff --git a/plugins/kotlin/kotlin.searching/src/org/jetbrains/kotlin/idea/searching/usages/KotlinK2SearchUsagesSupport.kt b/plugins/kotlin/kotlin.searching/src/org/jetbrains/kotlin/idea/searching/usages/KotlinK2SearchUsagesSupport.kt index d55f38e910c0..21ba66d44bc5 100644 --- a/plugins/kotlin/kotlin.searching/src/org/jetbrains/kotlin/idea/searching/usages/KotlinK2SearchUsagesSupport.kt +++ b/plugins/kotlin/kotlin.searching/src/org/jetbrains/kotlin/idea/searching/usages/KotlinK2SearchUsagesSupport.kt @@ -84,12 +84,16 @@ internal class KotlinK2SearchUsagesSupport : KotlinSearchUsagesSupport { } } - override fun isCallableOverrideUsage(reference: PsiReference, declaration: KtNamedDeclaration): Boolean { - if (declaration.isExpectDeclaration() && - reference.unwrappedTargets.any { target -> target is KtDeclaration && ExpectActualSupport.getInstance(declaration.project).expectedDeclarationIfAny(target) == declaration }) { - return true - } + override fun isUsageOfActual( + reference: PsiReference, + declaration: KtNamedDeclaration + ): Boolean = declaration.isExpectDeclaration() && + reference.unwrappedTargets.any { target -> + target is KtDeclaration && ExpectActualSupport.getInstance(declaration.project) + .expectedDeclarationIfAny(target) == declaration + } + override fun isCallableOverrideUsage(reference: PsiReference, declaration: KtNamedDeclaration): Boolean { fun KtDeclaration.isTopLevelCallable() = when (this) { is KtNamedFunction -> isTopLevel is KtProperty -> isTopLevel diff --git a/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/AbstractMultiModuleTest.kt b/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/AbstractMultiModuleTest.kt index 65d09ff8f635..f6f48196ae84 100644 --- a/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/AbstractMultiModuleTest.kt +++ b/plugins/kotlin/test-framework/test/org/jetbrains/kotlin/idea/test/AbstractMultiModuleTest.kt @@ -35,6 +35,8 @@ import org.jetbrains.kotlin.idea.facet.getOrCreateFacet import org.jetbrains.kotlin.idea.facet.initializeIfNeeded import org.jetbrains.kotlin.idea.test.KotlinTestUtils.allowProjectRootAccess import org.jetbrains.kotlin.idea.test.KotlinTestUtils.disposeVfsRootAccess +import org.jetbrains.kotlin.idea.test.util.checkPluginIsCorrect +import org.jetbrains.kotlin.idea.test.util.setUpWithKotlinPlugin import org.jetbrains.kotlin.idea.test.util.slashedPath import org.jetbrains.kotlin.idea.util.sourceRoots import org.jetbrains.kotlin.konan.target.TargetSupportException @@ -62,11 +64,12 @@ abstract class AbstractMultiModuleTest : DaemonAnalyzerTestCase(), } override fun setUp() { - super.setUp() - enableKotlinOfficialCodeStyle(project) + setUpWithKotlinPlugin(isFirPlugin()) { + super.setUp() + enableKotlinOfficialCodeStyle(project) - vfsDisposable = allowProjectRootAccess(this) - assertKotlinPluginMode() + vfsDisposable = allowProjectRootAccess(this) + } } // [TargetSupportException] can be thrown by the multiplatform test setup when a test artifact doesn't exist for the host platform.