[LL API] Support '_DebugLabel's in code fragments
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/CodeFragmentCapturedValueAnalyzer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/CodeFragmentCapturedValueAnalyzer.kt
index 8c594f9..ed754d5 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/CodeFragmentCapturedValueAnalyzer.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/CodeFragmentCapturedValueAnalyzer.kt
@@ -6,7 +6,6 @@
 package org.jetbrains.kotlin.analysis.low.level.api.fir.compiler
 
 import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiFile
 import com.intellij.psi.util.PsiTreeUtil
 import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
 import org.jetbrains.kotlin.analysis.low.level.api.fir.api.resolveToFirSymbol
@@ -163,6 +162,7 @@
                 if (symbol.isLocal) {
                     val isCrossingInlineBounds = isCrossingInlineBounds(element, symbol)
                     val capturedValue = when {
+                        symbol.fir.foreignValueMarker == true -> CodeFragmentCapturedValue.ForeignValue(symbol.name, isCrossingInlineBounds)
                         symbol.hasDelegate -> CodeFragmentCapturedValue.LocalDelegate(symbol.name, symbol.isMutated, isCrossingInlineBounds)
                         else -> CodeFragmentCapturedValue.Local(symbol.name, symbol.isMutated, isCrossingInlineBounds)
                     }
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/CodeFragmentScopeProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/CodeFragmentScopeProvider.kt
new file mode 100644
index 0000000..9caaa2a
--- /dev/null
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/CodeFragmentScopeProvider.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.analysis.low.level.api.fir.compiler
+
+import com.intellij.psi.impl.compiled.ClsTypeElementImpl
+import com.intellij.psi.impl.compiled.SignatureParsing
+import com.intellij.psi.impl.compiled.StubBuildingVisitor
+import org.jetbrains.kotlin.descriptors.Modality
+import org.jetbrains.kotlin.descriptors.Visibilities
+import org.jetbrains.kotlin.fir.FirSession
+import org.jetbrains.kotlin.fir.FirSessionComponent
+import org.jetbrains.kotlin.fir.caches.firCachesFactory
+import org.jetbrains.kotlin.fir.declarations.*
+import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
+import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
+import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
+import org.jetbrains.kotlin.fir.java.resolveIfJavaType
+import org.jetbrains.kotlin.fir.moduleData
+import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
+import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
+import org.jetbrains.kotlin.fir.types.FirTypeRef
+import org.jetbrains.kotlin.fir.types.jvm.buildJavaTypeRef
+import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeImpl
+import org.jetbrains.kotlin.load.java.structure.impl.source.JavaElementSourceFactory
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.psi.KtCodeFragment
+import org.jetbrains.org.objectweb.asm.Type
+import java.text.StringCharacterIterator
+
+internal val FirSession.codeFragmentScopeProvider: CodeFragmentScopeProvider by FirSession.sessionComponentAccessor()
+
+private object ForeignValueMarkerDataKey : FirDeclarationDataKey()
+
+internal var FirProperty.foreignValueMarker: Boolean? by FirDeclarationDataRegistry.data(ForeignValueMarkerDataKey)
+
+internal class CodeFragmentScopeProvider(private val session: FirSession) : FirSessionComponent {
+    private val foreignValueProvider = ForeignValueProviderService.getInstance()
+
+    private val typeCache = session.firCachesFactory.createCache<String, FirTypeRef, KtCodeFragment> { typeDescriptor, ktCodeFragment ->
+        getPrimitiveType(typeDescriptor, session)?.let { return@createCache it }
+
+        val project = ktCodeFragment.project
+        val javaElementSourceFactory = JavaElementSourceFactory.getInstance(project)
+
+        val signatureIterator = StringCharacterIterator(typeDescriptor)
+        val typeString = SignatureParsing.parseTypeString(signatureIterator, StubBuildingVisitor.GUESSING_MAPPER)
+        val psiType = ClsTypeElementImpl(ktCodeFragment, typeString, '\u0000').type
+        val javaType = JavaTypeImpl.create(psiType, javaElementSourceFactory.createTypeSource(psiType))
+
+        val javaTypeRef = buildJavaTypeRef {
+            annotationBuilder = { emptyList() }
+            type = javaType
+        }
+
+        javaTypeRef.resolveIfJavaType(session, JavaTypeParameterStack.EMPTY)
+    }
+
+    fun getExtraScopes(codeFragment: KtCodeFragment): List<FirLocalScope> {
+        val foreignValues = foreignValueProvider?.getForeignValues(codeFragment)?.takeUnless { it.isEmpty() } ?: return emptyList()
+        return listOf(getForeignValuesScope(codeFragment, foreignValues))
+    }
+
+    private fun getForeignValuesScope(ktCodeFragment: KtCodeFragment, foreignValues: Map<String, String>): FirLocalScope {
+        var result = FirLocalScope(session)
+
+        for ((variableNameString, typeDescriptor) in foreignValues) {
+            val variableName = Name.identifier(variableNameString)
+
+            val variable = buildProperty {
+                resolvePhase = FirResolvePhase.BODY_RESOLVE
+                moduleData = session.moduleData
+                origin = FirDeclarationOrigin.Source
+                status = FirDeclarationStatusImpl(Visibilities.Local, Modality.FINAL)
+                returnTypeRef = typeCache.getValue(typeDescriptor, ktCodeFragment)
+                deprecationsProvider = EmptyDeprecationsProvider
+                name = variableName
+                isVar = false
+                symbol = FirPropertySymbol(variableName)
+                isLocal = true
+            }
+
+            variable.foreignValueMarker = true
+
+            result = result.storeVariable(variable, session)
+        }
+
+        return result
+    }
+}
+
+private fun getPrimitiveType(typeDescriptor: String, session: FirSession): FirTypeRef? {
+    val asmType = Type.getType(typeDescriptor)
+    return when (asmType.sort) {
+        Type.VOID -> session.builtinTypes.unitType
+        Type.BOOLEAN -> session.builtinTypes.booleanType
+        Type.CHAR -> session.builtinTypes.charType
+        Type.BYTE -> session.builtinTypes.byteType
+        Type.SHORT -> session.builtinTypes.shortType
+        Type.INT -> session.builtinTypes.intType
+        Type.FLOAT -> session.builtinTypes.floatType
+        Type.LONG -> session.builtinTypes.longType
+        Type.DOUBLE -> session.builtinTypes.doubleType
+        else -> null
+    }
+}
\ No newline at end of file
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/ForeignValueProviderService.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/ForeignValueProviderService.kt
new file mode 100644
index 0000000..27aff87
--- /dev/null
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/ForeignValueProviderService.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.analysis.low.level.api.fir.compiler
+
+import com.intellij.openapi.application.ApplicationManager
+import org.jetbrains.kotlin.psi.KtCodeFragment
+
+interface ForeignValueProviderService {
+    fun getForeignValues(codeFragment: KtCodeFragment): Map<String, String>
+
+    companion object {
+        fun getInstance(): ForeignValueProviderService? {
+            return ApplicationManager.getApplication().getService(ForeignValueProviderService::class.java)
+        }
+    }
+}
\ No newline at end of file
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/LLCompilerFacade.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/LLCompilerFacade.kt
index 7bf8940..80ba049 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/LLCompilerFacade.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/LLCompilerFacade.kt
@@ -7,6 +7,7 @@
 
 import com.intellij.openapi.progress.ProcessCanceledException
 import com.intellij.openapi.progress.ProgressManager
+import com.intellij.openapi.util.Key
 import org.jetbrains.kotlin.analysis.low.level.api.fir.api.*
 import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirResolvableModuleSession
 import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider
@@ -51,7 +52,6 @@
 import org.jetbrains.kotlin.resolve.source.PsiSourceFile
 import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
 import org.jetbrains.kotlin.utils.addToStdlib.runIf
-import org.jetbrains.org.objectweb.asm.Type
 
 class LLCompilationResult(
     val outputFiles: List<OutputFile>,
@@ -66,9 +66,6 @@
     /** Entry point method name for the code fragment. */
     val CODE_FRAGMENT_METHOD_NAME = CompilerConfigurationKey<String>("code fragment method name")
 
-    /** '_DebugLabel' mappings for the code fragment. */
-    val CODE_FRAGMENT_DEBUG_LABELS = CompilerConfigurationKey<Map<String, Type>>("code fragment '_DebugLabel' entries")
-
     fun compile(
         file: KtFile,
         configuration: CompilerConfiguration,
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/sessionFactoryHelpers.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/sessionFactoryHelpers.kt
index 60c9085..96214d6 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/sessionFactoryHelpers.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/sessionFactoryHelpers.kt
@@ -10,6 +10,7 @@
 import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider
 import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeSessionComponents
 import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.createSealedInheritorsProvider
+import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.CodeFragmentScopeProvider
 import org.jetbrains.kotlin.analysis.low.level.api.fir.fir.caches.FirThreadSafeCachesFactory
 import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirIdePredicateBasedProvider
 import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirIdeRegisteredPluginAnnotations
@@ -32,12 +33,9 @@
 import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
 import org.jetbrains.kotlin.fir.extensions.FirPredicateBasedProvider
 import org.jetbrains.kotlin.fir.extensions.FirRegisteredPluginAnnotations
-import org.jetbrains.kotlin.fir.java.FirJavaFacadeForSource
-import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
 import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
 import org.jetbrains.kotlin.fir.resolve.providers.impl.FirCompositeSymbolProvider
 import org.jetbrains.kotlin.fir.session.FirSessionConfigurator
-import org.jetbrains.kotlin.load.java.createJavaClassFinder
 
 @SessionConfiguration
 internal fun LLFirSession.registerIdeComponents(project: Project) {
@@ -45,6 +43,7 @@
     register(FirCachesFactory::class, FirThreadSafeCachesFactory)
     register(SealedClassInheritorsProvider::class, project.createSealedInheritorsProvider())
     register(FirExceptionHandler::class, LLFirExceptionHandler)
+    register(CodeFragmentScopeProvider::class, CodeFragmentScopeProvider(this))
     createResolveExtensionTool()?.let {
         register(LLFirResolveExtensionTool::class, it)
     }
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/FirCodeFragmentResolveContextCollector.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/FirCodeFragmentResolveContextCollector.kt
index 9e1da4a..ed7254d 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/FirCodeFragmentResolveContextCollector.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/FirCodeFragmentResolveContextCollector.kt
@@ -12,6 +12,7 @@
 import org.jetbrains.kotlin.fir.resolve.SessionHolder
 import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.BodyResolveContext
 import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirResolveContextCollector
+import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
 import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
 import org.jetbrains.kotlin.fir.types.ConeKotlinType
 import org.jetbrains.kotlin.psi.KtElement
@@ -20,7 +21,8 @@
 
 internal class FirCodeFragmentResolveContextCollector(
     private val sessionHolder: SessionHolder,
-    contextElement: KtElement
+    private val extraScopes: List<FirLocalScope>,
+    contextElement: KtElement,
 ) : FirResolveContextCollector {
     private val contextElementCandidates = contextElement.parentsWithSelf.toSet()
     private val elementContexts = hashMapOf<KtElement, FirCodeFragmentContext>()
@@ -30,7 +32,7 @@
 
     override fun addFileContext(file: FirFile, context: FirTowerDataContext) {
         val psiFile = file.psi as? KtFile ?: return
-        elementContexts[psiFile] = FileFirCodeFragmentContext(context)
+        elementContexts[psiFile] = FileFirCodeFragmentContext(context.includingExtraScopes())
     }
 
     override fun addStatementContext(statement: FirStatement, context: BodyResolveContext) {
@@ -73,7 +75,11 @@
             }
         }
 
-        return StatementFirCodeFragmentContext(towerDataContext, variables)
+        return StatementFirCodeFragmentContext(towerDataContext.includingExtraScopes(), variables)
+    }
+
+    private fun FirTowerDataContext.includingExtraScopes(): FirTowerDataContext {
+        return extraScopes.fold(this) { context, scope -> context.addLocalScope(scope) }
     }
 }
 
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt
index e92c0b8..30cf759 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirBodyLazyResolver.kt
@@ -9,6 +9,7 @@
 import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getFirResolveSession
 import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
 import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
+import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.codeFragmentScopeProvider
 import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
 import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
 import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.RawFirReplacement
@@ -174,7 +175,8 @@
         val module = codeFragment.llFirModuleData.ktModule
         val resolveSession = module.getFirResolveSession(ktFile.project) as LLFirResolvableResolveSession
 
-        val collector = FirCodeFragmentResolveContextCollector(transformer.components, contextElement)
+        val extraScopes = resolveSession.useSiteFirSession.codeFragmentScopeProvider.getExtraScopes(ktFile)
+        val collector = FirCodeFragmentResolveContextCollector(transformer.components, extraScopes, contextElement)
         val replacement = RawFirReplacement(contextElement, contextElement)
         LowLevelFirApiFacadeForResolveOnAir.runBodyResolveOnAir(resolveSession, replacement, onAirCreatedDeclaration = false, collector)
         codeFragment.codeFragmentContext = collector.context