JS: restore names that can be changed by minifier

For example, Kotlin object can be renamed in stdlib,
so when we inline stdlib function in context of other module
renamed Kotlin object reference does not exitst.
This commit is contained in:
Alexey Tsvetkov
2015-03-06 15:18:08 +03:00
parent d44da8e4d4
commit 889d39a43e
3 changed files with 52 additions and 2 deletions
@@ -42,7 +42,19 @@ public class FunctionReader(private val context: TranslationContext) {
* Maps module name to .js file content, that contains this module definition.
* One file can contain more than one module definition.
*/
private val moduleJsDefinition = hashMapOf<String, String>();
private val moduleJsDefinition = hashMapOf<String, String>()
/**
* Maps module name to variable, that is used to call functions inside module.
* The default variable is _, but it can be renamed by minifier.
*/
private val moduleRootVariable = hashMapOf<String, String>()
/**
* Maps moduleName to kotlin object variable.
* The default variable is Kotlin, but it can be renamed by minifier.
*/
private val moduleKotlinVariable = hashMapOf<String, String>();
{
val config = context.getConfig() as LibrarySourcesConfig
@@ -55,8 +67,12 @@ public class FunctionReader(private val context: TranslationContext) {
while (matcher.find()) {
val moduleName = matcher.group(3)
val moduleVariable = matcher.group(4)
val kotlinVariable = matcher.group(1)
assert(moduleName !in moduleJsDefinition) { "Module is defined in more, than one file" }
moduleJsDefinition[moduleName] = file
moduleRootVariable[moduleName] = moduleVariable
moduleKotlinVariable[moduleName] = kotlinVariable
}
}
}
@@ -93,6 +109,13 @@ public class FunctionReader(private val context: TranslationContext) {
}
val function = metadata.function
val moduleName = getExternalModuleName(descriptor)!!
val moduleNameLiteral = context.program().getStringLiteral(moduleName)
val moduleReference = context.namer().getModuleReference(moduleNameLiteral)
val replacements = hashMapOf(moduleRootVariable[moduleName] to moduleReference,
moduleKotlinVariable[moduleName] to Namer.KOTLIN_OBJECT_REF)
replaceExternalNames(function, replacements)
return function
}
@@ -108,3 +131,21 @@ public class FunctionReader(private val context: TranslationContext) {
}
}
}
private fun replaceExternalNames(function: JsFunction, externalReplacements: Map<String, JsExpression>) {
val replacements = externalReplacements.filterKeys { !function.getScope().hasOwnName(it) }
if (replacements.isEmpty()) return
val visitor = object: JsVisitorWithContextImpl() {
override fun endVisit(x: JsNameRef?, ctx: JsContext?) {
if (x == null || x.getQualifier() != null) return
replacements[x.getIdent()]?.let {
ctx?.replaceMe(it)
}
}
}
visitor.accept(function)
}
@@ -268,6 +268,9 @@ public final class Namer {
@NotNull
private final JsName isTypeName;
@NotNull
private final JsExpression modulesMap;
private Namer(@NotNull JsScope rootScope) {
kotlinName = rootScope.declareName(KOTLIN_NAME);
kotlinScope = JsObjectScope(rootScope, "Kotlin standard object");
@@ -290,6 +293,7 @@ public final class Namer {
callableRefForExtensionProperty = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_PROPERTY);
isTypeName = kotlinScope.declareName("isType");
modulesMap = kotlin("modules");
}
@NotNull
@@ -421,4 +425,9 @@ public final class Namer {
public JsExpression getCallSetProperty() {
return callSetProperty;
}
@NotNull
public JsExpression getModuleReference(@NotNull JsStringLiteral moduleName) {
return new JsArrayAccess(modulesMap, moduleName);
}
}
@@ -481,7 +481,7 @@ public final class StaticContext {
}
return JsAstUtils.replaceRootReference(
result, new JsArrayAccess(namer.kotlin("modules"), program.getStringLiteral(moduleName)));
result, namer.getModuleReference(program.getStringLiteral(moduleName)));
}
};
Rule<JsExpression> constructorOrDefaultObjectHasTheSameQualifierAsTheClass = new Rule<JsExpression>() {