[JS IR] Emit original names for local vars to sourcemaps

#KT-35655 Fixed
This commit is contained in:
Sergej Jaskiewicz
2022-11-01 19:19:25 +01:00
committed by Space Team
parent 8efa72ca36
commit 7b7c517dbb
114 changed files with 1970 additions and 376 deletions
@@ -6,18 +6,24 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.backend.common.compilationException
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.js.backend.ast.*
private typealias Replacement = Pair<JsExpression, IrValueParameter>
class FunctionWithJsFuncAnnotationInliner(private val jsFuncCall: IrCall, private val context: JsGenerationContext) {
private val function = getJsFunctionImplementation()
private val replacements = collectReplacementsForCall()
fun generateResultStatement(): List<JsStatement> {
val irFunction = jsFuncCall.symbol.owner
val newContext = context.newFile(irFunction.file, irFunction, context.localNames)
return function.body.statements
.run {
SimpleJsCodeInliner(replacements)
SimpleJsCodeInliner(replacements, newContext)
.apply { acceptList(this@run) }
.withTemporaryVariablesForExpressions(this)
}
@@ -27,9 +33,10 @@ class FunctionWithJsFuncAnnotationInliner(private val jsFuncCall: IrCall, privat
context.staticContext.backendContext.getJsCodeForFunction(jsFuncCall.symbol)?.deepCopy()
?: compilationException("JS function not found", jsFuncCall)
private fun collectReplacementsForCall(): Map<JsName, JsExpression> {
private fun collectReplacementsForCall(): Map<JsName, Replacement> {
val translatedArguments = Array(jsFuncCall.valueArgumentsCount) {
jsFuncCall.getValueArgument(it)!!.accept(IrElementToJsExpressionTransformer(), context)
jsFuncCall.getValueArgument(it)!!
.accept(IrElementToJsExpressionTransformer(), context) to jsFuncCall.symbol.owner.valueParameters[it]
}
return function.parameters
.mapIndexed { i, param -> param.name to translatedArguments[i] }
@@ -37,15 +44,19 @@ class FunctionWithJsFuncAnnotationInliner(private val jsFuncCall: IrCall, privat
}
}
private class SimpleJsCodeInliner(private val replacements: Map<JsName, JsExpression>): RecursiveJsVisitor() {
private val temporaryNamesForExpressions = mutableMapOf<JsName, JsExpression>()
private class SimpleJsCodeInliner(private val replacements: Map<JsName, Replacement>, val context: JsGenerationContext) :
RecursiveJsVisitor()
{
private val temporaryNamesForExpressions = mutableMapOf<JsName, Replacement>()
fun withTemporaryVariablesForExpressions(statements: List<JsStatement>): List<JsStatement> {
if (temporaryNamesForExpressions.isEmpty()) {
return statements
}
val variableDeclarations = temporaryNamesForExpressions.map { JsVars(JsVars.JsVar(it.key, it.value)) }
val variableDeclarations = temporaryNamesForExpressions.map {
JsVars(JsVars.JsVar(it.key, it.value.first).withSource(it.value.second, context, useNameOf = it.value.second))
}
return variableDeclarations + statements
}
@@ -55,16 +66,16 @@ private class SimpleJsCodeInliner(private val replacements: Map<JsName, JsExpres
nameRef.name = nameRef.name?.getReplacement() ?: return
}
private fun JsName.declareNewTemporaryFor(expression: JsExpression): JsName {
private fun JsName.declareNewTemporaryFor(expression: JsExpression, irValueParameter: IrValueParameter): JsName {
return JsName(ident, true)
.also { temporaryNamesForExpressions[it] = expression }
.also { temporaryNamesForExpressions[it] = expression to irValueParameter }
}
private fun JsName.getReplacement(): JsName? {
val expression = replacements[this] ?: return null
val (expression, irValueParameter) = replacements[this] ?: return null
return when {
expression is JsNameRef && expression.qualifier == null -> expression.name!!
else -> declareNewTemporaryFor(expression)
else -> declareNewTemporaryFor(expression, irValueParameter)
}
}
}
@@ -148,7 +148,8 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
}
}
return jsVar(varName, value, context).withSource(declaration, context)
val jsInitializer = value?.accept(IrElementToJsExpressionTransformer(), context)
return JsVars(JsVars.JsVar(varName, jsInitializer).withSource(declaration, context, useNameOf = declaration))
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, context: JsGenerationContext): JsStatement {
@@ -214,4 +215,3 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
return label?.let { JsLabel(it, loopStatement) } ?: loopStatement
}
}
@@ -6,10 +6,12 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.backend.common.compilationException
import org.jetbrains.kotlin.backend.common.lower.BOUND_VALUE_PARAMETER
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrFileEntry
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
import org.jetbrains.kotlin.ir.backend.js.sourceMapsInfo
import org.jetbrains.kotlin.ir.backend.js.utils.*
@@ -38,11 +40,6 @@ fun jsUndefined(context: IrNamer, backendContext: JsIrBackendContext): JsExpress
}
}
fun jsVar(name: JsName, initializer: IrExpression?, context: JsGenerationContext): JsVars {
val jsInitializer = initializer?.accept(IrElementToJsExpressionTransformer(), context)
return JsVars(JsVars.JsVar(name, jsInitializer))
}
fun <T : JsNode> IrWhen.toJsNode(
tr: BaseIrElementToJsNodeTransformer<T, JsGenerationContext>,
context: JsGenerationContext,
@@ -113,7 +110,7 @@ fun translateFunction(declaration: IrFunction, name: JsName?, context: JsGenerat
val functionContext = context.newDeclaration(declaration, localNameGenerator)
val functionParams = declaration.valueParameters.map { functionContext.getNameForValueDeclaration(it) }
val functionParams = declaration.valueParameters.map { it to functionContext.getNameForValueDeclaration(it) }
val body = declaration.body?.accept(IrElementToJsStatementTransformer(), functionContext) as? JsBlock ?: JsBlock()
val function = JsFunction(emptyScope, body, "member function ${name ?: "annon"}")
@@ -121,12 +118,12 @@ fun translateFunction(declaration: IrFunction, name: JsName?, context: JsGenerat
function.name = name
fun JsFunction.addParameter(parameter: JsName) {
parameters.add(JsParameter(parameter))
fun JsFunction.addParameter(parameter: JsName, irValueParameter: IrValueParameter) {
parameters.add(JsParameter(parameter).withSource(irValueParameter, functionContext, useNameOf = irValueParameter))
}
declaration.extensionReceiverParameter?.let { function.addParameter(functionContext.getNameForValueDeclaration(it)) }
functionParams.forEach { function.addParameter(it) }
declaration.extensionReceiverParameter?.let { function.addParameter(functionContext.getNameForValueDeclaration(it), it) }
functionParams.forEach { (irValueParameter, name) -> function.addParameter(name, irValueParameter) }
check(!declaration.isSuspend) { "All Suspend functions should be lowered" }
return function
@@ -621,6 +618,19 @@ private fun IrDeclarationWithName.originalNameForUseInSourceMap(policy: SourceMa
return it.asString()
}
}
is IrValueDeclaration -> if (origin !in nameMappingOriginAllowList) {
return null
}
}
return name.asString()
}
private val nameMappingOriginAllowList = setOf(
IrDeclarationOrigin.DEFINED,
IrDeclarationOrigin.FOR_LOOP_VARIABLE,
IrDeclarationOrigin.CATCH_PARAMETER,
IrDeclarationOrigin.CONTINUATION,
BOUND_VALUE_PARAMETER,
JsLoweredDeclarationOrigin.JS_SHADOWED_DEFAULT_PARAMETER,
)