Skip to content

Commit

Permalink
Refactor ClosureCheckModule to have static class containing per-modul…
Browse files Browse the repository at this point in the history
…e state.

I find this a little easier to follow, and easier to add additional per-module
information to this class in a follow-up.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=147150273
  • Loading branch information
blickly committed Feb 10, 2017
1 parent ef248b1 commit 4fac0c1
Showing 1 changed file with 43 additions and 28 deletions.
71 changes: 43 additions & 28 deletions src/com/google/javascript/jscomp/ClosureCheckModule.java
Expand Up @@ -128,9 +128,20 @@ public final class ClosureCheckModule extends AbstractModuleCallback

private final AbstractCompiler compiler;

private String currentModuleName = null;
private Map<String, String> shortRequiredNamespaces = new HashMap<>();
private Node defaultExportNode = null;
private static class ModuleInfo {
// Name of the module in question (i.e. the argument to goog.module)
private final String name;
// Mapping from fully qualified goog.required names to the import LHS node
private final Map<String, Node> importsByLongRequiredName = new HashMap<>();
// The node of the default (non-named) export of this module, if it exists.
private Node defaultExportNode = null;

ModuleInfo(String moduleName) {
this.name = moduleName;
}
}

private ModuleInfo currentModule = null;

public ClosureCheckModule(AbstractCompiler compiler) {
this.compiler = compiler;
Expand All @@ -153,22 +164,25 @@ public void enterModule(NodeTraversal t, Node scopeRoot) {
Node call = firstStatement.getFirstChild();
Node callee = call.getFirstChild();
if (callee.matchesQualifiedName("goog.module")) {
Preconditions.checkState(currentModuleName == null);
currentModuleName = extractFirstArgumentName(call);
Preconditions.checkState(currentModule == null);
String moduleName = extractFirstArgumentName(call);
if (moduleName == null) {
t.report(scopeRoot, ClosureRewriteModule.INVALID_MODULE_NAMESPACE);
} else {
currentModule = new ModuleInfo(moduleName);
}
}
}
}

@Override
public void exitModule(NodeTraversal t, Node scopeRoot) {
currentModuleName = null;
shortRequiredNamespaces.clear();
defaultExportNode = null;
currentModule = null;
}

@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (currentModuleName == null) {
if (currentModule == null) {
return;
}
JSDocInfo jsDoc = n.getJSDocInfo();
Expand All @@ -179,7 +193,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
case CALL:
Node callee = n.getFirstChild();
if (callee.matchesQualifiedName("goog.module")
&& !currentModuleName.equals(extractFirstArgumentName(n))) {
&& !currentModule.name.equals(extractFirstArgumentName(n))) {
t.report(n, MULTIPLE_MODULES_IN_FILE);
} else if (callee.matchesQualifiedName("goog.provide")) {
t.report(n, MODULE_AND_PROVIDES);
Expand Down Expand Up @@ -224,22 +238,23 @@ public void visit(NodeTraversal t, Node n, Node parent) {
}
break;
case GETPROP:
if (currentModuleName != null && n.matchesQualifiedName(currentModuleName)) {
if (n.matchesQualifiedName(currentModule.name)) {
t.report(n, REFERENCE_TO_MODULE_GLOBAL_NAME);
} else if (shortRequiredNamespaces.containsKey(n.getQualifiedName())) {
String shortName = shortRequiredNamespaces.get(n.getQualifiedName());
if (shortName == null) {
} else if (currentModule.importsByLongRequiredName.containsKey(n.getQualifiedName())) {
Node importLhs = currentModule.importsByLongRequiredName.get(n.getQualifiedName());
if (importLhs == null || !importLhs.isName()) {
t.report(n, REFERENCE_TO_FULLY_QUALIFIED_IMPORT_NAME, n.getQualifiedName());
} else {
t.report(n, REFERENCE_TO_SHORT_IMPORT_BY_LONG_NAME_INCLUDING_SHORT_NAME,
n.getQualifiedName(), shortName);
n.getQualifiedName(), importLhs.getQualifiedName());
}
}
break;
default:
break;
}
}

private void checkJSDoc(NodeTraversal t, JSDocInfo jsDoc) {
for (Node typeNode : jsDoc.getTypeNodes()) {
checkTypeExpression(t, typeNode);
Expand All @@ -257,16 +272,16 @@ public void visit(Node node) {
}
String type = node.getString();
while (true) {
if (shortRequiredNamespaces.containsKey(type)) {
String shortName = shortRequiredNamespaces.get(type);
if (shortName == null) {
if (currentModule.importsByLongRequiredName.containsKey(type)) {
Node importLhs = currentModule.importsByLongRequiredName.get(type);
if (importLhs == null || !importLhs.isName()) {
t.report(node, JSDOC_REFERENCE_TO_FULLY_QUALIFIED_IMPORT_NAME, type);
} else if (!shortName.equals(type)) {
} else if (!importLhs.getString().equals(type)) {
t.report(
node,
JSDOC_REFERENCE_TO_SHORT_IMPORT_BY_LONG_NAME_INCLUDING_SHORT_NAME,
type,
shortName);
importLhs.getString());
}
}
if (type.contains(".")) {
Expand All @@ -293,16 +308,17 @@ private void checkModuleExport(NodeTraversal t, Node n, Node parent) {
Preconditions.checkArgument(n.isAssign());
Node lhs = n.getFirstChild();
Preconditions.checkState(isExportLhs(lhs));
if (defaultExportNode == null && (!t.inModuleScope() || !parent.isExprResult())) {
if (currentModule.defaultExportNode == null && (!t.inModuleScope() || !parent.isExprResult())) {
// Invalid export location.
t.report(n, EXPORT_NOT_A_MODULE_LEVEL_STATEMENT);
}
if (lhs.isName()) {
if (defaultExportNode != null) {
if (currentModule.defaultExportNode != null) {
// Multiple exports
t.report(n, EXPORT_REPEATED_ERROR, String.valueOf(defaultExportNode.getLineno()));
int previousLine = currentModule.defaultExportNode.getLineno();
t.report(n, EXPORT_REPEATED_ERROR, String.valueOf(previousLine));
}
defaultExportNode = lhs;
currentModule.defaultExportNode = lhs;
}
if ((lhs.isName() || !NodeUtil.isPrototypeProperty(lhs))
&& !NodeUtil.isLegacyGoogModuleFile(NodeUtil.getEnclosingScript(n))) {
Expand Down Expand Up @@ -338,7 +354,7 @@ private void checkRequireCall(NodeTraversal t, Node callNode, Node parent) {
}

private void checkShortGoogRequireCall(NodeTraversal t, Node callNode, Node declaration) {
String shortName = null;
Node lhs = null;
if (NodeUtil.isNameDeclaration(declaration)) {
if (declaration.isLet()
&& !callNode.getFirstChild().matchesQualifiedName("goog.forwardDeclare")) {
Expand All @@ -347,13 +363,12 @@ private void checkShortGoogRequireCall(NodeTraversal t, Node callNode, Node decl
if (!declaration.hasOneChild()) {
t.report(declaration, ONE_REQUIRE_PER_DECLARATION);
}
Node lhs = declaration.getFirstChild();
lhs = declaration.getFirstChild();
if (lhs.isDestructuringLhs() && !isValidDestructuringImport(lhs)) {
t.report(declaration, INVALID_DESTRUCTURING_REQUIRE);
}
shortName = lhs.isName() ? lhs.getString() : null;
}
shortRequiredNamespaces.put(extractFirstArgumentName(callNode), shortName);
currentModule.importsByLongRequiredName.put(extractFirstArgumentName(callNode), lhs);
}

private static boolean isValidDestructuringImport(Node destructuringLhs) {
Expand Down

0 comments on commit 4fac0c1

Please sign in to comment.