[FIR-IDE] Add DestructuringDeclarationEntry to SymbolProvider
diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10SymbolProvider.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10SymbolProvider.kt
index 31e7102..68000de 100644
--- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10SymbolProvider.kt
+++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10SymbolProvider.kt
@@ -126,4 +126,8 @@
             .filter { it.name == name }
             .mapNotNull { it.toKtSymbol(analysisContext) as? KtCallableSymbol }
     }
+
+    override fun getDestructuringDeclarationEntrySymbol(psi: KtDestructuringDeclarationEntry): KtLocalVariableSymbol {
+        return KtFe10PsiLocalVariableSymbol(psi, analysisContext)
+    }
 }
\ No newline at end of file
diff --git a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java
index e9d64d4..f21656c 100644
--- a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java
+++ b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/symbols/Fe10IdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java
@@ -113,6 +113,12 @@
     }
 
     @Test
+    @TestMetadata("destructuringDeclaration.kt")
+    public void testDestructuringDeclaration() throws Exception {
+        runTest("analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.kt");
+    }
+
+    @Test
     @TestMetadata("enum.kt")
     public void testEnum() throws Exception {
         runTest("analysis/analysis-api/testData/symbols/symbolByPsi/enum.kt");
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSymbolProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSymbolProvider.kt
index 95fde0c..03a822a 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSymbolProvider.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirSymbolProvider.kt
@@ -122,14 +122,14 @@
         // A KtClassOrObject may also map to an FirEnumEntry. Hence, we need to return null in this case.
         if (psi is KtEnumEntry) return null
         return firSymbolBuilder.classifierBuilder.buildNamedClassOrObjectSymbol(
-            psi.resolveToFirSymbolOfType<FirRegularClassSymbol>(firResolveSession)
-        )
+            psi.resolveToFirSymbolOfType<FirRegularClassSymbol>(firResolveSession))
+
     }
 
     override fun getPropertyAccessorSymbol(psi: KtPropertyAccessor): KtPropertyAccessorSymbol {
         return firSymbolBuilder.callableBuilder.buildPropertyAccessorSymbol(
-            psi.resolveToFirSymbolOfType<FirPropertyAccessorSymbol>(firResolveSession)
-        )
+            psi.resolveToFirSymbolOfType<FirPropertyAccessorSymbol>(firResolveSession))
+
     }
 
     override fun getClassInitializerSymbol(psi: KtClassInitializer): KtClassInitializerSymbol {
@@ -149,4 +149,12 @@
     }
 
     override val ROOT_PACKAGE_SYMBOL: KtPackageSymbol = KtFirPackageSymbol(FqName.ROOT, firResolveSession.project, token)
+
+    override fun getDestructuringDeclarationEntrySymbol(psi: KtDestructuringDeclarationEntry): KtLocalVariableSymbol {
+        return firSymbolBuilder.variableLikeBuilder.buildLocalVariableSymbol(
+            psi.resolveToFirSymbolOfType<FirPropertySymbol>(
+                firResolveSession
+            )
+        )
+    }
 }
diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java
index f4fa5ae..0eaf69a 100644
--- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java
+++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/symbols/FirIdeNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java
@@ -113,6 +113,12 @@
     }
 
     @Test
+    @TestMetadata("destructuringDeclaration.kt")
+    public void testDestructuringDeclaration() throws Exception {
+        runTest("analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.kt");
+    }
+
+    @Test
     @TestMetadata("enum.kt")
     public void testEnum() throws Exception {
         runTest("analysis/analysis-api/testData/symbols/symbolByPsi/enum.kt");
diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolByPsiTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolByPsiTest.kt
index 00472af..022f2586 100644
--- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolByPsiTest.kt
+++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolByPsiTest.kt
@@ -8,6 +8,7 @@
 import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
 import org.jetbrains.kotlin.psi.KtBackingField
 import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
 import org.jetbrains.kotlin.psi.KtFile
 import org.jetbrains.kotlin.psi.KtParameter
 import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
@@ -30,6 +31,7 @@
         get() =
             when (this) {
                 is KtBackingField -> false
+                is KtDestructuringDeclaration -> false
                 is KtParameter -> !this.isFunctionTypeParameter
                 else -> true
             }
diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java
index e48438f..8938c31 100644
--- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java
+++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/symbols/FirStandaloneNormalAnalysisSourceModuleSymbolByPsiTestGenerated.java
@@ -113,6 +113,12 @@
     }
 
     @Test
+    @TestMetadata("destructuringDeclaration.kt")
+    public void testDestructuringDeclaration() throws Exception {
+        runTest("analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.kt");
+    }
+
+    @Test
     @TestMetadata("enum.kt")
     public void testEnum() throws Exception {
         runTest("analysis/analysis-api/testData/symbols/symbolByPsi/enum.kt");
diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtSymbolProvider.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtSymbolProvider.kt
index 7405df7..16f8e0e 100644
--- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtSymbolProvider.kt
+++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtSymbolProvider.kt
@@ -30,6 +30,7 @@
         }
         is KtPropertyAccessor -> getPropertyAccessorSymbol(psi)
         is KtClassInitializer -> getClassInitializerSymbol(psi)
+        is KtDestructuringDeclarationEntry -> getDestructuringDeclarationEntrySymbol(psi)
         else -> error("Cannot build symbol for ${psi::class}")
     }
 
@@ -48,6 +49,7 @@
     public abstract fun getNamedClassOrObjectSymbol(psi: KtClassOrObject): KtNamedClassOrObjectSymbol?
     public abstract fun getPropertyAccessorSymbol(psi: KtPropertyAccessor): KtPropertyAccessorSymbol
     public abstract fun getClassInitializerSymbol(psi: KtClassInitializer): KtClassInitializerSymbol
+    public abstract fun getDestructuringDeclarationEntrySymbol(psi: KtDestructuringDeclarationEntry): KtLocalVariableSymbol
 
     public abstract fun getClassOrObjectSymbolByClassId(classId: ClassId): KtClassOrObjectSymbol?
 
@@ -133,6 +135,13 @@
     public fun FqName.getContainingCallableSymbolsWithName(name: Name): Sequence<KtSymbol> =
         withValidityAssertion { analysisSession.symbolProvider.getTopLevelCallableSymbols(this, name) }
 
+    /**
+     * @return symbol corresponding to the local variable introduced by individual destructuring declaration entries.
+     * E.g. `val (x, y) = p` has two declaration entries, one corresponding to `x`, one to `y`.
+     */
+    public fun KtDestructuringDeclarationEntry.getDestructuringDeclarationEntrySymbol(): KtLocalVariableSymbol =
+        analysisSession.symbolProvider.getDestructuringDeclarationEntrySymbol(this)
+
     @Suppress("PropertyName")
     public val ROOT_PACKAGE_SYMBOL: KtPackageSymbol
         get() = withValidityAssertion { analysisSession.symbolProvider.ROOT_PACKAGE_SYMBOL }
diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.descriptors.pretty.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.descriptors.pretty.txt
new file mode 100644
index 0000000..edb93c5
--- /dev/null
+++ b/analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.descriptors.pretty.txt
@@ -0,0 +1,9 @@
+fun destruct(): kotlin.Int
+
+data class P {
+  constructor(x: kotlin.Int, y: kotlin.Int)
+
+  val x: kotlin.Int
+
+  val y: kotlin.Int
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.kt b/analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.kt
new file mode 100644
index 0000000..22f601b
--- /dev/null
+++ b/analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.kt
@@ -0,0 +1,6 @@
+data class P(val x: Int, val y: Int)
+
+fun destruct(): Int {
+    val (l, r) = P(1, 2)
+    return l + r
+}
diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.pretty.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.pretty.txt
new file mode 100644
index 0000000..3ecaf04
--- /dev/null
+++ b/analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.pretty.txt
@@ -0,0 +1,15 @@
+fun destruct(): kotlin.Int
+
+class P {
+  constructor(x: kotlin.Int, y: kotlin.Int)
+
+  val x: kotlin.Int
+
+  val y: kotlin.Int
+
+  operator fun component1(): kotlin.Int
+
+  operator fun component2(): kotlin.Int
+
+  fun copy(x: kotlin.Int = ..., y: kotlin.Int = ...): P
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.txt
new file mode 100644
index 0000000..5b3eee6
--- /dev/null
+++ b/analysis/analysis-api/testData/symbols/symbolByPsi/destructuringDeclaration.txt
@@ -0,0 +1,128 @@
+KtValueParameterSymbol:
+  annotationsList: []
+  callableIdIfNonLocal: null
+  generatedPrimaryConstructorProperty: KtKotlinPropertySymbol(/P.x)
+  hasDefaultValue: false
+  isExtension: false
+  isImplicitLambdaParameter: false
+  isVararg: false
+  name: x
+  origin: SOURCE
+  receiverType: null
+  returnType: kotlin/Int
+  symbolKind: LOCAL
+  typeParameters: []
+  getContainingModule: KtSourceModule "Sources of main"
+  deprecationStatus: null
+
+KtValueParameterSymbol:
+  annotationsList: []
+  callableIdIfNonLocal: null
+  generatedPrimaryConstructorProperty: KtKotlinPropertySymbol(/P.y)
+  hasDefaultValue: false
+  isExtension: false
+  isImplicitLambdaParameter: false
+  isVararg: false
+  name: y
+  origin: SOURCE
+  receiverType: null
+  returnType: kotlin/Int
+  symbolKind: LOCAL
+  typeParameters: []
+  getContainingModule: KtSourceModule "Sources of main"
+  deprecationStatus: null
+
+KtConstructorSymbol:
+  annotationsList: []
+  callableIdIfNonLocal: null
+  containingClassIdIfNonLocal: P
+  hasStableParameterNames: true
+  isExtension: false
+  isPrimary: true
+  origin: SOURCE
+  receiverType: null
+  returnType: P
+  symbolKind: CLASS_MEMBER
+  typeParameters: []
+  valueParameters: [
+    KtValueParameterSymbol(x)
+    KtValueParameterSymbol(y)
+  ]
+  visibility: Public
+  getContainingModule: KtSourceModule "Sources of main"
+  deprecationStatus: null
+
+KtNamedClassOrObjectSymbol:
+  annotationsList: []
+  classIdIfNonLocal: P
+  classKind: CLASS
+  companionObject: null
+  isData: true
+  isExternal: false
+  isFun: false
+  isInline: false
+  isInner: false
+  modality: FINAL
+  name: P
+  origin: SOURCE
+  superTypes: [
+    kotlin/Any
+  ]
+  symbolKind: TOP_LEVEL
+  typeParameters: []
+  visibility: Public
+  getContainingModule: KtSourceModule "Sources of main"
+  deprecationStatus: null
+
+KtLocalVariableSymbol:
+  annotationsList: []
+  callableIdIfNonLocal: null
+  isExtension: false
+  isVal: true
+  name: l
+  origin: SOURCE
+  receiverType: null
+  returnType: kotlin/Int
+  symbolKind: LOCAL
+  typeParameters: []
+  getContainingModule: KtSourceModule "Sources of main"
+  deprecationStatus: null
+
+KtLocalVariableSymbol:
+  annotationsList: []
+  callableIdIfNonLocal: null
+  isExtension: false
+  isVal: true
+  name: r
+  origin: SOURCE
+  receiverType: null
+  returnType: kotlin/Int
+  symbolKind: LOCAL
+  typeParameters: []
+  getContainingModule: KtSourceModule "Sources of main"
+  deprecationStatus: null
+
+KtFunctionSymbol:
+  annotationsList: []
+  callableIdIfNonLocal: /destruct
+  hasStableParameterNames: true
+  isBuiltinFunctionInvoke: false
+  isExtension: false
+  isExternal: false
+  isInfix: false
+  isInline: false
+  isOperator: false
+  isOverride: false
+  isStatic: false
+  isSuspend: false
+  modality: FINAL
+  name: destruct
+  origin: SOURCE
+  receiverType: null
+  returnType: kotlin/Int
+  symbolKind: TOP_LEVEL
+  typeParameters: []
+  valueParameters: []
+  visibility: Public
+  getContainingModule: KtSourceModule "Sources of main"
+  deprecationStatus: null
\ No newline at end of file