[kotlin] kmp find usages: recognize references to connected expect/actuals

^KTIJ-29878 fixed

GitOrigin-RevId: 9c4032b5ae88753aee52a20fcd9fe057d0532f32
This commit is contained in:
Anna Kozlova
2024-05-13 11:22:54 +00:00
committed by intellij-monorepo-bot
parent 022b790ca6
commit ddb2037997
15 changed files with 102 additions and 3 deletions
@@ -13,7 +13,10 @@ import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.base.analysis.KotlinBaseAnalysisBundle
import org.jetbrains.kotlin.idea.base.psi.KotlinPsiHeuristics
import org.jetbrains.kotlin.idea.base.psi.isExpectDeclaration
import org.jetbrains.kotlin.idea.base.util.restrictToKotlinSources
import org.jetbrains.kotlin.idea.search.ExpectActualUtils.actualsForExpected
import org.jetbrains.kotlin.idea.search.ExpectActualUtils.expectedDeclarationIfAny
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.SearchUtils.forceResolveReferences
import org.jetbrains.kotlin.idea.search.KotlinSearchUsagesSupport.SearchUtils.getReceiverTypeSearcherInfo
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
@@ -60,7 +63,14 @@ abstract class OperatorReferenceSearcher<TReferenceElement : KtElement>(
protected fun processReferenceElement(element: TReferenceElement): Boolean {
val reference = extractReference(element) ?: return true
testLog { "Resolved ${logPresentation(element)}" }
return if (reference.isReferenceTo(targetDeclaration)) {
if (reference.isReferenceTo(targetDeclaration)) {
return consumer.process(reference)
}
val currentTarget = reference.resolve() as? KtDeclaration ?: return true
if (targetDeclaration !is KtDeclaration) return true
return if ((targetDeclaration.expectedDeclarationIfAny() ?: targetDeclaration) == (currentTarget.expectedDeclarationIfAny() ?: currentTarget)
) {
consumer.process(reference)
} else {
true
@@ -20,13 +20,15 @@ abstract class AbstractFindUsagesMultiModuleFirTest : AbstractFindUsagesMultiMod
)
}
override val ignoreLog: Boolean = true
override fun doTest(path: String) {
IgnoreTests.runTestIfNotDisabledByFileDirective(
getTestdataFile().toPath().resolve("directives.txt"),
IgnoreTests.DIRECTIVES.IGNORE_K2,
directivePosition = IgnoreTests.DirectivePosition.LAST_LINE_IN_FILE
) {
super.doTest(path)
super.doTestInternal(path)
}
}
}
@@ -28,6 +28,16 @@ public class FindUsagesMultiModuleFirTestGenerated extends AbstractFindUsagesMul
runTest("../../idea/tests/testData/multiModuleFindUsages/findActualInterface/");
}
@TestMetadata("findByConvention")
public void testFindByConvention() throws Exception {
runTest("../../idea/tests/testData/multiModuleFindUsages/findByConvention/");
}
@TestMetadata("findByConventionInPlatform")
public void testFindByConventionInPlatform() throws Exception {
runTest("../../idea/tests/testData/multiModuleFindUsages/findByConventionInPlatform/");
}
@TestMetadata("findClassConstructors")
public void testFindClassConstructors() throws Exception {
runTest("../../idea/tests/testData/multiModuleFindUsages/findClassConstructors/");
@@ -7,6 +7,7 @@ import com.intellij.testFramework.UsefulTestCase
import org.jetbrains.kotlin.executeOnPooledThreadInReadAction
import org.jetbrains.kotlin.findUsages.AbstractFindUsagesTest.Companion.FindUsageTestType
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode
import org.jetbrains.kotlin.idea.base.test.IgnoreTests
import org.jetbrains.kotlin.idea.base.test.InTextDirectivesUtils
import org.jetbrains.kotlin.idea.multiplatform.setupMppProjectFromDirStructure
import org.jetbrains.kotlin.idea.test.AbstractMultiModuleTest
@@ -28,7 +29,19 @@ abstract class AbstractFindUsagesMultiModuleTest : AbstractMultiModuleTest() {
file.text.contains("// ")
}
protected open fun doTest(path: String) {
open val ignoreLog: Boolean = false
open fun doTest(path: String) {
IgnoreTests.runTestIfNotDisabledByFileDirective(
getTestdataFile().toPath().resolve("directives.txt"),
IgnoreTests.DIRECTIVES.IGNORE_K1,
directivePosition = IgnoreTests.DirectivePosition.LAST_LINE_IN_FILE
) {
doTestInternal(path)
}
}
protected fun doTestInternal(path: String) {
setupMppProjectFromDirStructure(File(path))
val virtualFile = mainFile.virtualFile!!
@@ -67,6 +80,7 @@ abstract class AbstractFindUsagesMultiModuleTest : AbstractMultiModuleTest() {
project,
alwaysAppendFileName = true,
testType = testType,
ignoreLog = ignoreLog
)
}
}
@@ -28,6 +28,16 @@ public class FindUsagesMultiModuleTestGenerated extends AbstractFindUsagesMultiM
runTest("testData/multiModuleFindUsages/findActualInterface/");
}
@TestMetadata("findByConvention")
public void testFindByConvention() throws Exception {
runTest("testData/multiModuleFindUsages/findByConvention/");
}
@TestMetadata("findByConventionInPlatform")
public void testFindByConventionInPlatform() throws Exception {
runTest("testData/multiModuleFindUsages/findByConventionInPlatform/");
}
@TestMetadata("findClassConstructors")
public void testFindClassConstructors() throws Exception {
runTest("testData/multiModuleFindUsages/findClassConstructors/");
@@ -0,0 +1,9 @@
// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtFunction
// OPTIONS: usages
class DummyClass002
expect operator fun DummyClass002.invoke<caret>()
fun testInvokeCommon(d: DummyClass002) {
d()
d.invoke()
}
@@ -0,0 +1,6 @@
[common.kt] Function call 8 d.invoke()
[common.kt] Implicit 'invoke' 7 d()
[js.kt] Function call 4 d.invoke()
[js.kt] Implicit 'invoke' 3 d()
[jvm.kt] Function call 4 d.invoke()
[jvm.kt] Implicit 'invoke' 3 d()
@@ -0,0 +1,5 @@
actual operator fun DummyClass002.invoke() {}
fun testInvokeJs(d: DummyClass002) {
d()
d.invoke()
}
@@ -0,0 +1,5 @@
actual operator fun DummyClass002.invoke() {}
fun testInvokeJvm(d: DummyClass002) {
d()
d.invoke()
}
@@ -0,0 +1,6 @@
class DummyClass002
expect operator fun DummyClass002.invoke()
fun testInvokeCommon(d: DummyClass002) {
d()
d.invoke()
}
@@ -0,0 +1,9 @@
// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtFunction
// OPTIONS: usages, expected
actual operator fun DummyClass002.inv<caret>oke() {}
fun testInvokeJs(d: DummyClass002) {
d()
d.invoke()
}
// IGNORE_K1
@@ -0,0 +1,6 @@
[common.kt] Function call 5 d.invoke()
[common.kt] Implicit 'invoke' 4 d()
[js.kt] Function call 6 d.invoke()
[js.kt] Implicit 'invoke' 5 d()
[jvm.kt] Function call 4 d.invoke()
[jvm.kt] Implicit 'invoke' 3 d()
@@ -0,0 +1,5 @@
actual operator fun DummyClass002.invoke() {}
fun testInvokeJvm(d: DummyClass002) {
d()
d.invoke()
}