Skip to content

Commit

Permalink
Record imported symbols in PreprocessorSymbolTable before they are re…
Browse files Browse the repository at this point in the history
…moved by Es6RewriteModule pass.

Tested:
  kythe tests

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=186799301
  • Loading branch information
nbeloglazov authored and dimvar committed Feb 25, 2018
1 parent 4b2f978 commit 1f3052e
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 52 deletions.
2 changes: 1 addition & 1 deletion src/com/google/javascript/jscomp/ClosureRewriteModule.java
Expand Up @@ -1785,7 +1785,7 @@ private void maybeAddToSymbolTable(Node n) {
*/ */
private void maybeAddAliasToSymbolTable(Node n, String module) { private void maybeAddAliasToSymbolTable(Node n, String module) {
if (preprocessorSymbolTable != null) { if (preprocessorSymbolTable != null) {
n.putBooleanProp(Node.GOOG_MODULE_ALIAS, true); n.putBooleanProp(Node.MODULE_ALIAS, true);
// Alias can be used in js types. Types have node type STRING and not NAME so we have to // Alias can be used in js types. Types have node type STRING and not NAME so we have to
// use their name as string. // use their name as string.
String nodeName = String nodeName =
Expand Down
41 changes: 18 additions & 23 deletions src/com/google/javascript/jscomp/DefaultPassConfig.java
Expand Up @@ -65,6 +65,7 @@
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.annotation.Nullable;


/** /**
* Pass factories and meta-data for native JSCompiler passes. * Pass factories and meta-data for native JSCompiler passes.
Expand Down Expand Up @@ -99,11 +100,9 @@ public final class DefaultPassConfig extends PassConfig {
*/ */
private transient GlobalNamespace namespaceForChecks = null; private transient GlobalNamespace namespaceForChecks = null;


/** /** A symbol table for registering references that get removed during preprocessing. */
* A symbol table for registering references that get removed during private final transient PreprocessorSymbolTable.CachedInstanceFactory
* preprocessing. preprocessorSymbolTableFactory;
*/
private transient PreprocessorSymbolTable preprocessorSymbolTable = null;


/** /**
* Global state necessary for doing hotswap recompilation of files with references to * Global state necessary for doing hotswap recompilation of files with references to
Expand All @@ -124,23 +123,16 @@ public DefaultPassConfig(CompilerOptions options) {
// wrap them in a function call that is stripped later, this shouldn't // wrap them in a function call that is stripped later, this shouldn't
// be done in IDE mode where AST changes may be unexpected. // be done in IDE mode where AST changes may be unexpected.
protectHiddenSideEffects = options != null && options.shouldProtectHiddenSideEffects(); protectHiddenSideEffects = options != null && options.shouldProtectHiddenSideEffects();
preprocessorSymbolTableFactory = new PreprocessorSymbolTable.CachedInstanceFactory();
} }


GlobalNamespace getGlobalNamespace() { GlobalNamespace getGlobalNamespace() {
return namespaceForChecks; return namespaceForChecks;
} }


@Nullable
PreprocessorSymbolTable getPreprocessorSymbolTable() { PreprocessorSymbolTable getPreprocessorSymbolTable() {
return preprocessorSymbolTable; return preprocessorSymbolTableFactory.getInstanceOrNull();
}

void maybeInitializePreprocessorSymbolTable(AbstractCompiler compiler) {
if (options.preservesDetailedSourceInfo()) {
Node root = compiler.getRoot();
if (preprocessorSymbolTable == null || preprocessorSymbolTable.getRootNode() != root) {
preprocessorSymbolTable = new PreprocessorSymbolTable(root);
}
}
} }


void maybeInitializeModuleRewriteState() { void maybeInitializeModuleRewriteState() {
Expand All @@ -158,7 +150,7 @@ protected List<PassFactory> getTranspileOnlyPasses() {
} }


if (options.getLanguageIn().toFeatureSet().has(FeatureSet.Feature.MODULES)) { if (options.getLanguageIn().toFeatureSet().has(FeatureSet.Feature.MODULES)) {
TranspilationPasses.addEs6ModulePass(passes); TranspilationPasses.addEs6ModulePass(passes, preprocessorSymbolTableFactory);
} }


passes.add(checkSuper); passes.add(checkSuper);
Expand Down Expand Up @@ -305,7 +297,7 @@ protected List<PassFactory> getChecks() {
} }


if (options.getLanguageIn().toFeatureSet().has(FeatureSet.Feature.MODULES)) { if (options.getLanguageIn().toFeatureSet().has(FeatureSet.Feature.MODULES)) {
TranspilationPasses.addEs6ModulePass(checks); TranspilationPasses.addEs6ModulePass(checks, preprocessorSymbolTableFactory);
} }


checks.add(checkVariableReferences); checks.add(checkVariableReferences);
Expand Down Expand Up @@ -1363,11 +1355,11 @@ public FeatureSet featureSet() {
new HotSwapPassFactory("closurePrimitives") { new HotSwapPassFactory("closurePrimitives") {
@Override @Override
protected HotSwapCompilerPass create(final AbstractCompiler compiler) { protected HotSwapCompilerPass create(final AbstractCompiler compiler) {
maybeInitializePreprocessorSymbolTable(compiler); preprocessorSymbolTableFactory.maybeInitialize(compiler);
final ProcessClosurePrimitives pass = final ProcessClosurePrimitives pass =
new ProcessClosurePrimitives( new ProcessClosurePrimitives(
compiler, compiler,
preprocessorSymbolTable, preprocessorSymbolTableFactory.getInstanceOrNull(),
options.brokenClosureRequiresLevel, options.brokenClosureRequiresLevel,
options.shouldPreservesGoogProvidesAndRequires()); options.shouldPreservesGoogProvidesAndRequires());


Expand Down Expand Up @@ -1454,9 +1446,11 @@ public FeatureSet featureSet() {
new HotSwapPassFactory("closureGoogScopeAliases") { new HotSwapPassFactory("closureGoogScopeAliases") {
@Override @Override
protected HotSwapCompilerPass create(AbstractCompiler compiler) { protected HotSwapCompilerPass create(AbstractCompiler compiler) {
maybeInitializePreprocessorSymbolTable(compiler); preprocessorSymbolTableFactory.maybeInitialize(compiler);
return new ScopedAliases( return new ScopedAliases(
compiler, preprocessorSymbolTable, options.getAliasTransformationHandler()); compiler,
preprocessorSymbolTableFactory.getInstanceOrNull(),
options.getAliasTransformationHandler());
} }


@Override @Override
Expand Down Expand Up @@ -1610,9 +1604,10 @@ protected FeatureSet featureSet() {
new HotSwapPassFactory("closureRewriteModule") { new HotSwapPassFactory("closureRewriteModule") {
@Override @Override
protected HotSwapCompilerPass create(AbstractCompiler compiler) { protected HotSwapCompilerPass create(AbstractCompiler compiler) {
maybeInitializePreprocessorSymbolTable(compiler); preprocessorSymbolTableFactory.maybeInitialize(compiler);
maybeInitializeModuleRewriteState(); maybeInitializeModuleRewriteState();
return new ClosureRewriteModule(compiler, preprocessorSymbolTable, moduleRewriteState); return new ClosureRewriteModule(
compiler, preprocessorSymbolTableFactory.getInstanceOrNull(), moduleRewriteState);
} }


@Override @Override
Expand Down
39 changes: 36 additions & 3 deletions src/com/google/javascript/jscomp/Es6RewriteModules.java
Expand Up @@ -38,6 +38,7 @@
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.annotation.Nullable;


/** /**
* Rewrites a ES6 module into a form that can be safely concatenated. Note that we treat a file as * Rewrites a ES6 module into a form that can be safely concatenated. Note that we treat a file as
Expand All @@ -64,6 +65,8 @@ public final class Es6RewriteModules extends AbstractPostOrderCallback
DiagnosticType.error("JSC_DUPLICATE_EXPORT", "Duplicate export ''{0}''."); DiagnosticType.error("JSC_DUPLICATE_EXPORT", "Duplicate export ''{0}''.");


private final AbstractCompiler compiler; private final AbstractCompiler compiler;

@Nullable private final PreprocessorSymbolTable preprocessorSymbolTable;
private int scriptNodeCount; private int scriptNodeCount;


/** /**
Expand All @@ -85,11 +88,13 @@ public final class Es6RewriteModules extends AbstractPostOrderCallback
private Set<String> typedefs; private Set<String> typedefs;


/** /**
* Creates a new Es6RewriteModules instance which can be used to rewrite * Creates a new Es6RewriteModules instance which can be used to rewrite ES6 modules to a
* ES6 modules to a concatenable form. * concatenable form.
*/ */
public Es6RewriteModules(AbstractCompiler compiler) { public Es6RewriteModules(
AbstractCompiler compiler, @Nullable PreprocessorSymbolTable preprocessorSymbolTable) {
this.compiler = compiler; this.compiler = compiler;
this.preprocessorSymbolTable = preprocessorSymbolTable;
} }


/** /**
Expand Down Expand Up @@ -234,6 +239,7 @@ private void visitImport(NodeTraversal t, Node importDecl, Node parent) {
} else if (child.isImportSpecs()) { } else if (child.isImportSpecs()) {
for (Node grandChild : child.children()) { for (Node grandChild : child.children()) {
String origName = grandChild.getFirstChild().getString(); String origName = grandChild.getFirstChild().getString();
maybeAddAliasToSymbolTable(grandChild.getFirstChild(), t.getSourceName());
checkState(grandChild.hasTwoChildren()); checkState(grandChild.hasTwoChildren());
importMap.put( importMap.put(
grandChild.getLastChild().getString(), grandChild.getLastChild().getString(),
Expand All @@ -249,6 +255,7 @@ private void visitImport(NodeTraversal t, Node importDecl, Node parent) {
t.makeError( t.makeError(
importDecl, NAMESPACE_IMPORT_CANNOT_USE_STAR, child.getString(), moduleName)); importDecl, NAMESPACE_IMPORT_CANNOT_USE_STAR, child.getString(), moduleName));
} }
maybeAddAliasToSymbolTable(child, t.getSourceName());
importMap.put( importMap.put(
child.getString(), child.getString(),
new ModuleOriginalNamePair(moduleName, "")); new ModuleOriginalNamePair(moduleName, ""));
Expand Down Expand Up @@ -628,6 +635,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
boolean isImportStar = pair.originalName.isEmpty(); boolean isImportStar = pair.originalName.isEmpty();
Node moduleAccess = NodeUtil.newQName(compiler, pair.module); Node moduleAccess = NodeUtil.newQName(compiler, pair.module);


maybeAddAliasToSymbolTable(n, t.getSourceName());
if (isImportStar) { if (isImportStar) {
n.replaceWith(moduleAccess.useSourceInfoIfMissingFromForTree(n)); n.replaceWith(moduleAccess.useSourceInfoIfMissingFromForTree(n));
} else { } else {
Expand Down Expand Up @@ -689,6 +697,7 @@ private void fixTypeNode(NodeTraversal t, Node typeNode) {
maybeSetNewName(t, typeNode, name, baseName + "$$" + suffix + rest); maybeSetNewName(t, typeNode, name, baseName + "$$" + suffix + rest);
} else if (var == null && importMap.containsKey(baseName)) { } else if (var == null && importMap.containsKey(baseName)) {
ModuleOriginalNamePair pair = importMap.get(baseName); ModuleOriginalNamePair pair = importMap.get(baseName);
maybeAddAliasToSymbolTable(typeNode, t.getSourceName());
if (pair.originalName.isEmpty()) { if (pair.originalName.isEmpty()) {
maybeSetNewName(t, typeNode, name, pair.module + rest); maybeSetNewName(t, typeNode, name, pair.module + rest);
} else { } else {
Expand All @@ -713,6 +722,30 @@ private void maybeSetNewName(NodeTraversal t, Node node, String name, String new
} }
} }


/**
* Add alias nodes to the symbol table as they going to be removed by rewriter. Example aliases:
*
* <pre>
* import * as foo from './foo';
* import {doBar} from './bar';
* </pre>
*/
private void maybeAddAliasToSymbolTable(Node n, String module) {
if (preprocessorSymbolTable != null) {
n.putBooleanProp(Node.MODULE_ALIAS, true);
// Alias can be used in js types. Types have node type STRING and not NAME so we have to
// use their name as string.
String nodeName =
n.isString() || n.isImportStar()
? n.getString()
: preprocessorSymbolTable.getQualifiedName(n);
// We need to include module as part of the name because aliases are local to current module.
// Aliases with the same name from different module should be completely different entities.
String name = "alias_" + module + "_" + nodeName;
preprocessorSymbolTable.addReference(n, name);
}
}

private static class ModuleOriginalNamePair { private static class ModuleOriginalNamePair {
private final String module; private final String module;
private final String originalName; private final String originalName;
Expand Down
27 changes: 27 additions & 0 deletions src/com/google/javascript/jscomp/PreprocessorSymbolTable.java
Expand Up @@ -29,6 +29,7 @@
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import javax.annotation.Nullable;


/** /**
* A symbol table for references that are removed by preprocessor passes * A symbol table for references that are removed by preprocessor passes
Expand Down Expand Up @@ -131,4 +132,30 @@ static final class Reference extends SimpleReference<SimpleSlot> {
super(symbol, node); super(symbol, node);
} }
} }

/**
* Object that maybe contains instance of the table. This object is needed because
* PreprocessorSymbolTable is used by multiple passes in different parts of code which initialized
* at different times (some even before compiler object is created). Instead instance of factory
* is passed around. Each pass that uses PreprocessorSymbolTable has to call maybeInitialize()
* before getting instance.
*/
public static class CachedInstanceFactory {

@Nullable private PreprocessorSymbolTable instance;

public void maybeInitialize(AbstractCompiler compiler) {
if (compiler.getOptions().preservesDetailedSourceInfo()) {
Node root = compiler.getRoot();
if (instance == null || instance.getRootNode() != root) {
instance = new PreprocessorSymbolTable(root);
}
}
}

@Nullable
public PreprocessorSymbolTable getInstanceOrNull() {
return instance;
}
}
} }
32 changes: 16 additions & 16 deletions src/com/google/javascript/jscomp/TranspilationPasses.java
Expand Up @@ -32,8 +32,22 @@
public class TranspilationPasses { public class TranspilationPasses {
private TranspilationPasses() {} private TranspilationPasses() {}


public static void addEs6ModulePass(List<PassFactory> passes) { public static void addEs6ModulePass(
passes.add(es6RewriteModule); List<PassFactory> passes,
final PreprocessorSymbolTable.CachedInstanceFactory preprocessorTableFactory) {
passes.add(
new HotSwapPassFactory("es6RewriteModule") {
@Override
protected HotSwapCompilerPass create(AbstractCompiler compiler) {
preprocessorTableFactory.maybeInitialize(compiler);
return new Es6RewriteModules(compiler, preprocessorTableFactory.getInstanceOrNull());
}

@Override
protected FeatureSet featureSet() {
return ES_NEXT;
}
});
} }


public static void addEs6ModuleToCjsPass(List<PassFactory> passes) { public static void addEs6ModuleToCjsPass(List<PassFactory> passes) {
Expand Down Expand Up @@ -110,20 +124,6 @@ public static void addRewritePolyfillPass(List<PassFactory> passes) {
passes.add(rewritePolyfills); passes.add(rewritePolyfills);
} }


/** Rewrites ES6 modules */
private static final HotSwapPassFactory es6RewriteModule =
new HotSwapPassFactory("es6RewriteModule") {
@Override
protected HotSwapCompilerPass create(AbstractCompiler compiler) {
return new Es6RewriteModules(compiler);
}

@Override
protected FeatureSet featureSet() {
return ES_NEXT;
}
};

/** Rewrites ES6 modules */ /** Rewrites ES6 modules */
private static final PassFactory es6RewriteModuleToCjs = private static final PassFactory es6RewriteModuleToCjs =
new PassFactory("es6RewriteModuleToCjs", true) { new PassFactory("es6RewriteModuleToCjs", true) {
Expand Down
14 changes: 10 additions & 4 deletions src/com/google/javascript/jscomp/parsing/IRFactory.java
Expand Up @@ -2337,10 +2337,16 @@ Node processImportDecl(ImportDeclarationTree tree) {
maybeWarnForFeature(tree, Feature.MODULES); maybeWarnForFeature(tree, Feature.MODULES);


Node firstChild = transformOrEmpty(tree.defaultBindingIdentifier, tree); Node firstChild = transformOrEmpty(tree.defaultBindingIdentifier, tree);
Node secondChild = (tree.nameSpaceImportIdentifier != null) Node secondChild;
? newStringNode(Token.IMPORT_STAR, tree.nameSpaceImportIdentifier.value) if (tree.nameSpaceImportIdentifier == null) {
: transformListOrEmpty(Token.IMPORT_SPECS, tree.importSpecifierList); secondChild = transformListOrEmpty(Token.IMPORT_SPECS, tree.importSpecifierList);
setSourceInfo(secondChild, tree); // Currently source info is "import {foo} from '...';" expression. If needed this should be
// changed to use only "{foo}" part.
setSourceInfo(secondChild, tree);
} else {
secondChild = newStringNode(Token.IMPORT_STAR, tree.nameSpaceImportIdentifier.value);
setSourceInfo(secondChild, tree.nameSpaceImportIdentifier);
}
Node thirdChild = processString(tree.moduleSpecifier); Node thirdChild = processString(tree.moduleSpecifier);


return newNode(Token.IMPORT, firstChild, secondChild, thirdChild); return newNode(Token.IMPORT, firstChild, secondChild, thirdChild);
Expand Down
6 changes: 3 additions & 3 deletions src/com/google/javascript/rhino/Node.java
Expand Up @@ -155,8 +155,8 @@ public class Node implements Serializable {
IS_ES6_CLASS = 92, // Indicates that a FUNCTION node is converted from an ES6 class IS_ES6_CLASS = 92, // Indicates that a FUNCTION node is converted from an ES6 class
TRANSPILED = 93, // Indicates that a SCRIPT represents a transpiled file TRANSPILED = 93, // Indicates that a SCRIPT represents a transpiled file
DELETED = 94, // For passes that work only on deleted funs. DELETED = 94, // For passes that work only on deleted funs.
GOOG_MODULE_ALIAS = 95, // Indicates that the node is an alias of goog.require'd module. MODULE_ALIAS = 95, // Indicates that the node is an alias or a name from goog.require'd module
// Aliases are desugared and inlined by compiler passes but we // or ES6 module. Aliases are desugared and inlined by compiler passes but we
// need to preserve them for building index. // need to preserve them for building index.
IS_UNUSED_PARAMETER = 96, // Mark a parameter as unused. Used to defer work from IS_UNUSED_PARAMETER = 96, // Mark a parameter as unused. Used to defer work from
// RemovedUnusedVars to OptimizeParameters. // RemovedUnusedVars to OptimizeParameters.
Expand Down Expand Up @@ -223,7 +223,7 @@ private static final String propToString(byte propType) {
case IS_ES6_CLASS: return "is_es6_class"; case IS_ES6_CLASS: return "is_es6_class";
case TRANSPILED: return "transpiled"; case TRANSPILED: return "transpiled";
case DELETED: return "DELETED"; case DELETED: return "DELETED";
case GOOG_MODULE_ALIAS: return "goog_module_alias"; case MODULE_ALIAS: return "module_alias";
case IS_UNUSED_PARAMETER: return "is_unused_parameter"; case IS_UNUSED_PARAMETER: return "is_unused_parameter";
case MODULE_EXPORT: case MODULE_EXPORT:
return "module_export"; return "module_export";
Expand Down
3 changes: 2 additions & 1 deletion test/com/google/javascript/jscomp/CompilerTestCase.java
Expand Up @@ -1738,7 +1738,8 @@ private void testInternal(


private static void transpileToEs5(AbstractCompiler compiler, Node externsRoot, Node codeRoot) { private static void transpileToEs5(AbstractCompiler compiler, Node externsRoot, Node codeRoot) {
List<PassFactory> factories = new ArrayList<>(); List<PassFactory> factories = new ArrayList<>();
TranspilationPasses.addEs6ModulePass(factories); TranspilationPasses.addEs6ModulePass(
factories, new PreprocessorSymbolTable.CachedInstanceFactory());
TranspilationPasses.addEs2017Passes(factories); TranspilationPasses.addEs2017Passes(factories);
TranspilationPasses.addEs2016Passes(factories); TranspilationPasses.addEs2016Passes(factories);
TranspilationPasses.addEs6EarlyPasses(factories); TranspilationPasses.addEs6EarlyPasses(factories);
Expand Down
Expand Up @@ -53,7 +53,7 @@ protected CompilerOptions getOptions() {


@Override @Override
protected CompilerPass getProcessor(Compiler compiler) { protected CompilerPass getProcessor(Compiler compiler) {
return new Es6RewriteModules(compiler); return new Es6RewriteModules(compiler, /* preprocessorSymbolTable= */ null);
} }


@Override @Override
Expand Down

0 comments on commit 1f3052e

Please sign in to comment.