[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