[LL API] Fix on-air analysis for scripts (KTIJ-21108)

The implementation is rather limited. Advanced cases, such as
replacing a script with another one with different import directives,
won't work because of non-trivial relationship between 'FirFile' and
'FirScript'.
This commit is contained in:
Yan Zhulanow
2023-02-27 19:58:08 +09:00
committed by Space Team
parent ae40ddcf03
commit 1cfd2ae7ff
6 changed files with 80 additions and 43 deletions
@@ -1049,7 +1049,11 @@ open class RawFirBuilder(
declarations += when (declaration) {
is KtScript -> {
require(file.declarations.size == 1) { "Expect the script to be the only declaration in the file $name" }
convertScript(declaration, this)
convertScript(declaration, this.name) {
for (configurator in baseSession.extensionService.scriptConfigurators) {
with(configurator) { configure(this@buildFile) }
}
}
}
is KtDestructuringDeclaration -> buildErrorTopLevelDestructuringDeclaration(declaration.toFirSourceElement())
else -> declaration.convert()
@@ -1062,12 +1066,12 @@ open class RawFirBuilder(
}
}
private fun convertScript(script: KtScript, containingFile: FirFileBuilder): FirScript {
private fun convertScript(script: KtScript, fileName: String, setup: FirScriptBuilder.() -> Unit = {}): FirScript {
return buildScript {
source = script.toFirSourceElement()
moduleData = baseModuleData
origin = FirDeclarationOrigin.Source
name = Name.special("<script-${containingFile.name}>")
name = Name.special("<script-$fileName>")
symbol = FirScriptSymbol(context.packageFqName.child(name))
for (declaration in script.declarations) {
when (declaration) {
@@ -1079,12 +1083,13 @@ open class RawFirBuilder(
}
}
}
baseSession.extensionService.scriptConfigurators.forEach { with(it) { configure(containingFile) } }
setup()
}
}
override fun visitScript(script: KtScript, data: Unit?): FirElement {
error("should not be here")
val fileName = script.containingKtFile.name
return convertScript(script, fileName)
}
protected fun KtEnumEntry.toFirEnumEntry(
@@ -70,3 +70,23 @@ inline fun buildScript(init: FirScriptBuilder.() -> Unit): FirScript {
}
return FirScriptBuilder().apply(init).build()
}
@OptIn(ExperimentalContracts::class)
inline fun buildScriptCopy(original: FirScript, init: FirScriptBuilder.() -> Unit): FirScript {
contract {
callsInPlace(init, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
}
val copyBuilder = FirScriptBuilder()
copyBuilder.source = original.source
copyBuilder.resolvePhase = original.resolvePhase
copyBuilder.annotations.addAll(original.annotations)
copyBuilder.moduleData = original.moduleData
copyBuilder.origin = original.origin
copyBuilder.attributes = original.attributes.copy()
copyBuilder.name = original.name
copyBuilder.statements.addAll(original.statements)
copyBuilder.symbol = original.symbol
copyBuilder.parameters.addAll(original.parameters)
copyBuilder.contextReceivers.addAll(original.contextReceivers)
return copyBuilder.apply(init).build()
}
@@ -357,6 +357,10 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
fields from resolvedQualifier
}
builder(script) {
withCopy()
}
builder(resolvedQualifier) {
parents += abstractResolvedQualifierBuilder
defaultFalse("isNullableLHSForCallableReference", "isFullyQualified")