From 889d39a43eb1054082b13535be4d1bfc3e48a7b1 Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Fri, 6 Mar 2015 15:18:08 +0300 Subject: [PATCH] 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. --- .../kotlin/js/inline/FunctionReader.kt | 43 ++++++++++++++++++- .../kotlin/js/translate/context/Namer.java | 9 ++++ .../js/translate/context/StaticContext.java | 2 +- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt index 43a25af1f57..95a9df8210a 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt @@ -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(); + private val moduleJsDefinition = hashMapOf() + + /** + * 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() + + /** + * Maps moduleName to kotlin object variable. + * The default variable is Kotlin, but it can be renamed by minifier. + */ + private val moduleKotlinVariable = hashMapOf(); { 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) { + 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) +} diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java index 26556025216..1424687b2b3 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java @@ -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); + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java index 0010bbdac4f..ce9b7beb8fa 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java @@ -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 constructorOrDefaultObjectHasTheSameQualifierAsTheClass = new Rule() {