[kotlin] KTIJ-35896 "go to declaration" and "find usages" for new destructuring syntax

GitOrigin-RevId: ef51d3fb6e85ab4f0aca7f3319b633b85a37d51b
This commit is contained in:
Olga Klisho
2026-02-02 11:52:57 +00:00
committed by intellij-monorepo-bot
parent ae1721f13b
commit 13a3de0a72
13 changed files with 155 additions and 8 deletions
@@ -0,0 +1,46 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.search.ideaExtensions
import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiPolyVariantReference
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
/**
* Handles "Go to Declaration" for destructuring declaration entries.
*
* For both short-form and full-form,
* Can be removed when this one is fixed (KT-82708): Only the initializer symbol is expected.
*/
class KotlinDestructuringGotoDeclarationHandler : GotoDeclarationHandler {
override fun getGotoDeclarationTargets(sourceElement: PsiElement?, offset: Int, editor: Editor?): Array<PsiElement>? {
if (sourceElement == null) return null
val entry = findDestructuringEntry(sourceElement) ?: return null
val reference = entry.reference as? PsiPolyVariantReference ?: return null
val results = reference.multiResolve(false)
// Can be changed when this one is fixed (KT-82708): Only the initializer symbol is expected
val targets = results
.mapNotNull { it.element }
.filter { it !is KtDestructuringDeclarationEntry }
return if (targets.isNotEmpty()) targets.toTypedArray() else null
}
private fun findDestructuringEntry(sourceElement: PsiElement): KtDestructuringDeclarationEntry? {
val parent = sourceElement.parent
if (parent is KtNameReferenceExpression) {
val entry = parent.parent as? KtDestructuringDeclarationEntry ?: return null
val destructuring = entry.parent as? KtDestructuringDeclaration ?: return null
if (destructuring.isFullForm) {
return entry
}
}
return null
}
}
@@ -1,4 +1,4 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.fir.search.refIndex;
@@ -5540,6 +5540,25 @@ public abstract class FindUsagesWithCompilerReferenceIndexFirTestGenerated exten
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../idea/tests/testData/findUsages/kotlin/variable")
public abstract static class Variable extends AbstractFindUsagesWithCompilerReferenceIndexFirTest {
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../idea/tests/testData/findUsages/kotlin/variable")
public static class TestDestructuringEntry extends AbstractFindUsagesWithCompilerReferenceIndexFirTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K2;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("destructuringEntry.0.kt")
public void testDestructuringEntry() throws Exception {
runTest("../../idea/tests/testData/findUsages/kotlin/variable/destructuringEntry.0.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../idea/tests/testData/findUsages/kotlin/variable")
public static class TestPlusAssignFun extends AbstractFindUsagesWithCompilerReferenceIndexFirTest {
@@ -1,4 +1,4 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.search.refIndex;
@@ -5540,6 +5540,25 @@ public abstract class FindUsagesWithCompilerReferenceIndexTestGenerated extends
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../idea/tests/testData/findUsages/kotlin/variable")
public abstract static class Variable extends AbstractK1FindUsagesWithCompilerReferenceIndexTest {
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../idea/tests/testData/findUsages/kotlin/variable")
public static class TestDestructuringEntry extends AbstractK1FindUsagesWithCompilerReferenceIndexTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K1;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("destructuringEntry.0.kt")
public void testDestructuringEntry() throws Exception {
runTest("../../idea/tests/testData/findUsages/kotlin/variable/destructuringEntry.0.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../idea/tests/testData/findUsages/kotlin/variable")
public static class TestPlusAssignFun extends AbstractK1FindUsagesWithCompilerReferenceIndexTest {
@@ -1,4 +1,4 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.fir.findUsages;
@@ -1804,6 +1804,11 @@ public abstract class FindUsagesFirTestGenerated extends AbstractFindUsagesFirTe
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("destructuringEntry.0.kt")
public void testDestructuringEntry() throws Exception {
runTest("../../idea/tests/testData/findUsages/kotlin/variable/destructuringEntry.0.kt");
}
@TestMetadata("plusAssignFun.0.kt")
public void testPlusAssignFun() throws Exception {
runTest("../../idea/tests/testData/findUsages/kotlin/variable/plusAssignFun.0.kt");
@@ -1,4 +1,4 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.fir.findUsages.kmpFindUsages;
@@ -1929,6 +1929,11 @@ public abstract class JsFindUsagesFirTestGenerated extends AbstractFindUsagesFir
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("destructuringEntry.0.kt")
public void testDestructuringEntry() throws Exception {
runTest("../../idea/tests/testData/findUsages/kotlin/variable/destructuringEntry.0.kt");
}
@TestMetadata("plusAssignFun.0.kt")
public void testPlusAssignFun() throws Exception {
runTest("../../idea/tests/testData/findUsages/kotlin/variable/plusAssignFun.0.kt");
@@ -1,4 +1,4 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.fir.findUsages.kmpFindUsages;
@@ -1929,6 +1929,11 @@ public abstract class NativeLinuxFindUsagesFirTestGenerated extends AbstractFind
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("destructuringEntry.0.kt")
public void testDestructuringEntry() throws Exception {
runTest("../../idea/tests/testData/findUsages/kotlin/variable/destructuringEntry.0.kt");
}
@TestMetadata("plusAssignFun.0.kt")
public void testPlusAssignFun() throws Exception {
runTest("../../idea/tests/testData/findUsages/kotlin/variable/plusAssignFun.0.kt");
@@ -1,4 +1,4 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.fir.navigation;
@@ -40,6 +40,11 @@ public class FirGotoDeclarationTestGenerated extends AbstractFirGotoDeclarationT
runTest("../../idea/tests/testData/navigation/gotoDeclaration/dataClassToString.test");
}
@TestMetadata("destructuringDeclarationInitializer.test")
public void testDestructuringDeclarationInitializer() throws Exception {
runTest("../../idea/tests/testData/navigation/gotoDeclaration/destructuringDeclarationInitializer.test");
}
@TestMetadata("enumEntries.test")
public void testEnumEntries() throws Exception {
runTest("../../idea/tests/testData/navigation/gotoDeclaration/enumEntries.test");
@@ -1,4 +1,4 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.findUsages;
@@ -1804,6 +1804,11 @@ public abstract class FindUsagesTestGenerated extends AbstractK1FindUsagesTest {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("destructuringEntry.0.kt")
public void testDestructuringEntry() throws Exception {
runTest("testData/findUsages/kotlin/variable/destructuringEntry.0.kt");
}
@TestMetadata("plusAssignFun.0.kt")
public void testPlusAssignFun() throws Exception {
runTest("testData/findUsages/kotlin/variable/plusAssignFun.0.kt");
@@ -1,4 +1,4 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.navigation;
@@ -40,6 +40,11 @@ public class GotoDeclarationTestGenerated extends AbstractGotoDeclarationTest {
runTest("testData/navigation/gotoDeclaration/dataClassToString.test");
}
@TestMetadata("destructuringDeclarationInitializer.test")
public void testDestructuringDeclarationInitializer() throws Exception {
runTest("testData/navigation/gotoDeclaration/destructuringDeclarationInitializer.test");
}
@TestMetadata("enumEntries.test")
public void testEnumEntries() throws Exception {
runTest("testData/navigation/gotoDeclaration/enumEntries.test");
@@ -0,0 +1,12 @@
// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
// OPTIONS: usages
// IGNORE_K1
// CRI_IGNORE
// COMPILER_ARGUMENTS: -Xname-based-destructuring=only-syntax
data class Person(val fullName: String, val age: Int)
fun test(person: Person) {
(val <caret>a = fullName, val b = age) = person
println(a)
}
@@ -0,0 +1 @@
Value read 11 println(a)
@@ -0,0 +1,19 @@
// FILE: before.kt
// COMPILER_ARGUMENTS: -Xname-based-destructuring
package c
data class Person(val fullName: String, val age: Int)
fun test(person: Person) {
(val a = full<caret>Name, val b = age) = person
}
// FILE: after.kt
// COMPILER_ARGUMENTS: -Xname-based-destructuring
package c
data class Person(val <caret>fullName: String, val age: Int)
fun test(person: Person) {
(val a = fullName, val b = age) = person
}
@@ -188,6 +188,7 @@
<breadcrumbsInfoProvider implementation="org.jetbrains.kotlin.idea.codeInsight.KotlinBreadcrumbsInfoProvider"/>
<gotoDeclarationHandler implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinImportAliasGotoDeclarationHandler"/>
<gotoDeclarationHandler implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDestructuringGotoDeclarationHandler"/>
<createFromTemplateHandler implementation="org.jetbrains.kotlin.idea.actions.KotlinCreateFromTemplateHandler"/>