Refactor generator of JS source map

- refactor pipeline for generation of source map
- generate "empty" mappings for nodes that impossible
  to map to something reasonable
- generate more accurate locations in source maps for specific
  JS AST nodes
- for binary operation nodes parser now returns location
  of binary operator tokens instead of location of first operand
- change completely how source map remapper works
This commit is contained in:
Alexey Andreev
2017-06-20 15:34:36 +03:00
parent 6a2f3d8065
commit dea73ebecf
30 changed files with 622 additions and 336 deletions
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.js.JavaScript
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.config.EcmaVersion
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
@@ -42,7 +43,6 @@ import org.jetbrains.kotlin.js.dce.InputFile
import org.jetbrains.kotlin.js.facade.*
import org.jetbrains.kotlin.js.parser.parse
import org.jetbrains.kotlin.js.parser.sourcemaps.*
import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver
import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
import org.jetbrains.kotlin.js.test.utils.*
@@ -430,8 +430,8 @@ abstract class BasicBoxTest(
val output = TextOutputImpl()
val pathResolver = SourceFilePathResolver(mutableListOf(File(".")))
val sourceMapBuilder = SourceMap3Builder(outputFile, output, "", SourceMapBuilderConsumer(pathResolver, false, false))
generatedProgram.accept(JsSourceGenerationVisitor(output, sourceMapBuilder))
val sourceMapBuilder = SourceMap3Builder(outputFile, output, "")
generatedProgram.accept(JsToStringGenerationVisitor(output, SourceMapBuilderConsumer(sourceMapBuilder, pathResolver, false, false)))
val code = output.toString()
val generatedSourceMap = sourceMapBuilder.build()
@@ -446,7 +446,7 @@ abstract class BasicBoxTest(
is SourceMapError -> error("Could not parse source map: ${sourceMapParseResult.message}")
}
val remapper = SourceMapLocationRemapper(mapOf(outputFile.path to sourceMap))
val remapper = SourceMapLocationRemapper(sourceMap)
remapper.remap(parsedProgram)
val codeWithRemappedLines = parsedProgram.toStringWithLineNumbers()
@@ -16,15 +16,14 @@
package org.jetbrains.kotlin.js.test.optimizer
import com.google.gwt.dev.js.rhino.CodePosition
import com.google.gwt.dev.js.rhino.ErrorReporter
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.synthetic
import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor
import org.jetbrains.kotlin.js.parser.parse
import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor
import org.jetbrains.kotlin.js.test.BasicBoxTest
import org.jetbrains.kotlin.js.test.createScriptEngine
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
@@ -120,7 +119,7 @@ abstract class BasicOptimizerTest(private var basePath: String) {
private fun astToString(ast: List<JsStatement>): String {
val output = TextOutputImpl()
val visitor = JsSourceGenerationVisitor(output, null)
val visitor = JsToStringGenerationVisitor(output)
for (stmt in ast) {
stmt.accept(visitor)
}
@@ -16,64 +16,20 @@
package org.jetbrains.kotlin.js.test.utils
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.js.backend.ast.*
class AmbiguousAstSourcePropagation : RecursiveJsVisitor() {
private var sourceDefined = false
override fun visitConditional(x: JsConditional) = acceptAll(x, x.testExpression, x.thenExpression, x.elseExpression)
override fun visitBinaryExpression(x: JsBinaryOperation) = acceptAll(x, x.arg1, x.arg2)
override fun visitPostfixOperation(x: JsPostfixOperation) = acceptAll(x, x.arg)
override fun visitArrayAccess(x: JsArrayAccess) = acceptAll(x, x.arrayExpression, x.indexExpression)
override fun visitPropertyInitializer(x: JsPropertyInitializer) = acceptAll(x, x.labelExpr, x.valueExpr)
override fun visitInvocation(invocation: JsInvocation) = acceptAll(invocation, invocation.qualifier,
*invocation.arguments.toTypedArray())
override fun visitNameRef(nameRef: JsNameRef) {
val qualifier = nameRef.qualifier
if (qualifier != null) {
acceptAll(nameRef, qualifier)
}
else {
super.visitNameRef(nameRef)
}
}
private var lastSource: Any? = null
override fun visitElement(node: JsNode) {
val old = sourceDefined
propagate(node)
val source = node.source
if (source == null && node is JsExpression) {
node.source = lastSource
}
sourceDefined = false
val oldLastSource = lastSource
lastSource = node.source
super.visitElement(node)
sourceDefined = old
}
private fun acceptAll(node: JsNode, first: JsNode, vararg remaining: JsNode) {
val old = sourceDefined
propagate(node)
accept(first)
sourceDefined = false
remaining.forEach { accept(it) }
sourceDefined = old
}
private fun propagate(node: JsNode) {
if (!sourceDefined) {
val source = node.source
if (source is JsLocationWithSource || source is PsiElement) {
sourceDefined = true
}
}
else if (node !is JsExpressionStatement) {
node.source = null
}
lastSource = oldLastSource
}
}
@@ -87,10 +87,9 @@ class LineCollector : RecursiveJsVisitor() {
override fun visitDoWhile(x: JsDoWhile) {
withStatement(x) {
handleNodeLocation(x)
x.body.accept(this)
x.condition.accept(this)
}
x.body.accept(this)
}
override fun visitFor(x: JsFor) {
@@ -130,8 +129,8 @@ class LineCollector : RecursiveJsVisitor() {
override fun visit(x: JsSwitch) {
withStatement(x) {
x.expression.accept(this)
x.cases.forEach { accept(it) }
}
x.cases.forEach { accept(it) }
}
override fun visitThrow(x: JsThrow) {
@@ -140,6 +139,14 @@ class LineCollector : RecursiveJsVisitor() {
}
}
override fun visitTry(x: JsTry) {
withStatement(x) {
x.tryBlock.acceptChildren(this)
x.catches?.forEach { accept(it) }
x.finallyBlock?.acceptChildren(this)
}
}
private fun withStatement(statement: JsStatement, action: () -> Unit) {
val oldStatement = currentStatement
currentStatement = statement
@@ -73,6 +73,11 @@ class LineOutputToStringVisitor(output: TextOutput, val lineCollector: LineColle
super.visitReturn(x)
}
override fun visitTry(x: JsTry) {
printLineNumbers(x)
super.visitTry(x)
}
override fun visit(x: JsSwitch) {
printLineNumbers(x)
super.visit(x)