JS: move label renaming to new fragment post-processing
Also remove metadata renaming from the global passes
This commit is contained in:
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.js.backend.ast.metadata.localAlias
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.staticRef
|
||||
import org.jetbrains.kotlin.js.inline.clean.removeUnusedFunctionDefinitions
|
||||
import org.jetbrains.kotlin.js.inline.clean.removeUnusedImports
|
||||
import org.jetbrains.kotlin.js.inline.clean.renameLabels
|
||||
import org.jetbrains.kotlin.js.inline.clean.simplifyWrappedFunctions
|
||||
import org.jetbrains.kotlin.js.inline.util.*
|
||||
import org.jetbrains.kotlin.js.translate.declaration.transformSpecialFunctionsToCoroutineMetadata
|
||||
@@ -162,6 +163,7 @@ class ProgramFragmentInliningScope(
|
||||
simplifyWrappedFunctions(allCode)
|
||||
removeUnusedFunctionDefinitions(allCode, collectNamedFunctions(allCode))
|
||||
removeUnusedImports(fragment, allCode)
|
||||
renameLabels(allCode)
|
||||
}
|
||||
|
||||
override fun hasImport(name: JsName, tag: String): JsName? {
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.js.inline.clean
|
||||
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
fun renameLabels(root: JsNode) {
|
||||
// Labels in JS are in separate scope from local variables. It's only important that nested labels don't clash.
|
||||
// Adjacent labels in one function is OK
|
||||
root.accept(object : RecursiveJsVisitor() {
|
||||
val replacements = mutableMapOf<JsName, JsName>()
|
||||
|
||||
var labels = mutableSetOf<String>()
|
||||
|
||||
override fun visitElement(node: JsNode) {
|
||||
super.visitElement(node)
|
||||
if (node is HasName) {
|
||||
val name = node.name
|
||||
if (name != null) {
|
||||
replacements[name]?.let { node.name = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitLabel(x: JsLabel) {
|
||||
var addedName: String? = null
|
||||
if (x.name.isTemporary) {
|
||||
var resolvedName = x.name.ident
|
||||
var suffix = 0
|
||||
while (!labels.add(resolvedName)) {
|
||||
resolvedName = "${x.name.ident}_${suffix++}"
|
||||
}
|
||||
replacements[x.name] = JsDynamicScope.declareName(resolvedName)
|
||||
addedName = resolvedName
|
||||
}
|
||||
super.visitLabel(x)
|
||||
addedName?.let {
|
||||
labels.remove(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunction(x: JsFunction) {
|
||||
val oldLabels = labels
|
||||
labels = mutableSetOf()
|
||||
super.visitFunction(x)
|
||||
labels = oldLabels
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -62,36 +62,6 @@ private fun JsNode.resolveNames(): Map<JsName, JsName> {
|
||||
|
||||
traverse(rootScope)
|
||||
|
||||
// Labels in JS are in separate scope from local variables. It's only important that nested labels don't clash.
|
||||
// Adjacent labels in one function is OK
|
||||
accept(object : RecursiveJsVisitor() {
|
||||
var labels = mutableSetOf<String>()
|
||||
|
||||
override fun visitLabel(x: JsLabel) {
|
||||
var addedName: String? = null
|
||||
if (x.name.isTemporary) {
|
||||
var resolvedName = x.name.ident
|
||||
var suffix = 0
|
||||
while (!labels.add(resolvedName)) {
|
||||
resolvedName = "${x.name.ident}_${suffix++}"
|
||||
}
|
||||
replacements[x.name] = JsDynamicScope.declareName(resolvedName)
|
||||
addedName = resolvedName
|
||||
}
|
||||
super.visitLabel(x)
|
||||
addedName?.let {
|
||||
labels.remove(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunction(x: JsFunction) {
|
||||
val oldLabels = labels
|
||||
labels = mutableSetOf()
|
||||
super.visitFunction(x)
|
||||
labels = oldLabels
|
||||
}
|
||||
})
|
||||
|
||||
return replacements
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ 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.ast.*
|
||||
import org.jetbrains.kotlin.js.inline.clean.renameLabels
|
||||
import org.jetbrains.kotlin.js.inline.clean.resolveTemporaryNames
|
||||
import org.jetbrains.kotlin.js.parser.parse
|
||||
import org.jetbrains.kotlin.js.test.BasicBoxTest
|
||||
@@ -69,21 +70,21 @@ class NameResolutionTest {
|
||||
node.name = node.name?.let { name ->
|
||||
if (name.ident.startsWith("$")) {
|
||||
cache.getOrPut(name) { JsScope.declareTemporaryName("x") }
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
renameLabels(originalAst)
|
||||
originalAst.resolveTemporaryNames()
|
||||
|
||||
assertEquals(expectedAst.toString(), originalAst.toString())
|
||||
}
|
||||
|
||||
private val errorReporter = object : ErrorReporter {
|
||||
override fun warning(message: String, startPosition: CodePosition, endPosition: CodePosition) { }
|
||||
override fun warning(message: String, startPosition: CodePosition, endPosition: CodePosition) {}
|
||||
|
||||
override fun error(message: String, startPosition: CodePosition, endPosition: CodePosition) {
|
||||
fail("Error parsing JS file: $message at $startPosition")
|
||||
|
||||
@@ -241,7 +241,7 @@ class Merger(
|
||||
|
||||
// TODO better placing?
|
||||
val additionalFakeOverrides = mutableListOf<JsStatement>()
|
||||
importedFunctionWrappers.values.forEach {block ->
|
||||
importedFunctionWrappers.values.forEach { block ->
|
||||
block.statements.forEach { s ->
|
||||
if (s.isFakeOverrideAssignment()) {
|
||||
additionalFakeOverrides += s
|
||||
|
||||
Reference in New Issue
Block a user