diff --git a/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinDestructuringGotoDeclarationHandler.kt b/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinDestructuringGotoDeclarationHandler.kt new file mode 100644 index 000000000000..1b6332d16129 --- /dev/null +++ b/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinDestructuringGotoDeclarationHandler.kt @@ -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? { + 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 + } +} \ No newline at end of file diff --git a/plugins/kotlin/compiler-reference-index/tests.k2/test/org/jetbrains/kotlin/idea/fir/search/refIndex/FindUsagesWithCompilerReferenceIndexFirTestGenerated.java b/plugins/kotlin/compiler-reference-index/tests.k2/test/org/jetbrains/kotlin/idea/fir/search/refIndex/FindUsagesWithCompilerReferenceIndexFirTestGenerated.java index 875543372fd5..45d9d87b7cd9 100644 --- a/plugins/kotlin/compiler-reference-index/tests.k2/test/org/jetbrains/kotlin/idea/fir/search/refIndex/FindUsagesWithCompilerReferenceIndexFirTestGenerated.java +++ b/plugins/kotlin/compiler-reference-index/tests.k2/test/org/jetbrains/kotlin/idea/fir/search/refIndex/FindUsagesWithCompilerReferenceIndexFirTestGenerated.java @@ -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 { diff --git a/plugins/kotlin/compiler-reference-index/tests/test/org/jetbrains/kotlin/idea/search/refIndex/FindUsagesWithCompilerReferenceIndexTestGenerated.java b/plugins/kotlin/compiler-reference-index/tests/test/org/jetbrains/kotlin/idea/search/refIndex/FindUsagesWithCompilerReferenceIndexTestGenerated.java index 7bfad5381aeb..e55f7d221468 100644 --- a/plugins/kotlin/compiler-reference-index/tests/test/org/jetbrains/kotlin/idea/search/refIndex/FindUsagesWithCompilerReferenceIndexTestGenerated.java +++ b/plugins/kotlin/compiler-reference-index/tests/test/org/jetbrains/kotlin/idea/search/refIndex/FindUsagesWithCompilerReferenceIndexTestGenerated.java @@ -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 { diff --git a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/findUsages/FindUsagesFirTestGenerated.java b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/findUsages/FindUsagesFirTestGenerated.java index c14ad72671ed..ca0544245aa9 100644 --- a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/findUsages/FindUsagesFirTestGenerated.java +++ b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/findUsages/FindUsagesFirTestGenerated.java @@ -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"); diff --git a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/findUsages/kmpFindUsages/JsFindUsagesFirTestGenerated.java b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/findUsages/kmpFindUsages/JsFindUsagesFirTestGenerated.java index 0398eb61464d..453910afda51 100644 --- a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/findUsages/kmpFindUsages/JsFindUsagesFirTestGenerated.java +++ b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/findUsages/kmpFindUsages/JsFindUsagesFirTestGenerated.java @@ -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"); diff --git a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/findUsages/kmpFindUsages/NativeLinuxFindUsagesFirTestGenerated.java b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/findUsages/kmpFindUsages/NativeLinuxFindUsagesFirTestGenerated.java index 586514d719ae..212b9fec6441 100644 --- a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/findUsages/kmpFindUsages/NativeLinuxFindUsagesFirTestGenerated.java +++ b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/findUsages/kmpFindUsages/NativeLinuxFindUsagesFirTestGenerated.java @@ -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"); diff --git a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/navigation/FirGotoDeclarationTestGenerated.java b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/navigation/FirGotoDeclarationTestGenerated.java index b9983e62ecf9..c9ad00932338 100644 --- a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/navigation/FirGotoDeclarationTestGenerated.java +++ b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/navigation/FirGotoDeclarationTestGenerated.java @@ -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"); diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/findUsages/FindUsagesTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/findUsages/FindUsagesTestGenerated.java index 5b630ce2605d..af36175a4a28 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/findUsages/FindUsagesTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/findUsages/FindUsagesTestGenerated.java @@ -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"); diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/navigation/GotoDeclarationTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/navigation/GotoDeclarationTestGenerated.java index d406b2cad6a8..4a18927492d5 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/navigation/GotoDeclarationTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/navigation/GotoDeclarationTestGenerated.java @@ -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"); diff --git a/plugins/kotlin/idea/tests/testData/findUsages/kotlin/variable/destructuringEntry.0.kt b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/variable/destructuringEntry.0.kt new file mode 100644 index 000000000000..df3e0d338848 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/variable/destructuringEntry.0.kt @@ -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 a = fullName, val b = age) = person + println(a) +} diff --git a/plugins/kotlin/idea/tests/testData/findUsages/kotlin/variable/destructuringEntry.results.txt b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/variable/destructuringEntry.results.txt new file mode 100644 index 000000000000..4d3f54dcadb6 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/findUsages/kotlin/variable/destructuringEntry.results.txt @@ -0,0 +1 @@ +Value read 11 println(a) diff --git a/plugins/kotlin/idea/tests/testData/navigation/gotoDeclaration/destructuringDeclarationInitializer.test b/plugins/kotlin/idea/tests/testData/navigation/gotoDeclaration/destructuringDeclarationInitializer.test new file mode 100644 index 000000000000..d7468dbc2134 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/navigation/gotoDeclaration/destructuringDeclarationInitializer.test @@ -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 = fullName, val b = age) = person +} + +// FILE: after.kt +// COMPILER_ARGUMENTS: -Xname-based-destructuring +package c + +data class Person(val fullName: String, val age: Int) + +fun test(person: Person) { + (val a = fullName, val b = age) = person +} \ No newline at end of file diff --git a/plugins/kotlin/plugin/common/resources/META-INF/kotlin-core.xml b/plugins/kotlin/plugin/common/resources/META-INF/kotlin-core.xml index a2efb09252f3..c8ed9ee3b617 100644 --- a/plugins/kotlin/plugin/common/resources/META-INF/kotlin-core.xml +++ b/plugins/kotlin/plugin/common/resources/META-INF/kotlin-core.xml @@ -188,6 +188,7 @@ +