Skip to content

Commit

Permalink
Add support for running on unprocessed goog.modules to .i.js generator
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=129884330
  • Loading branch information
blickly committed Aug 10, 2016
1 parent a369bab commit 120864d
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 15 deletions.
65 changes: 50 additions & 15 deletions src/com/google/javascript/jscomp/ConvertToTypedInterface.java
Expand Up @@ -16,16 +16,15 @@
package com.google.javascript.jscomp;

import com.google.common.base.Preconditions;
import com.google.javascript.jscomp.NodeTraversal.AbstractModuleCallback;
import com.google.javascript.jscomp.NodeTraversal.AbstractShallowStatementCallback;
import com.google.javascript.jscomp.NodeTraversal.Callback;
import com.google.javascript.rhino.IR;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.JSDocInfoBuilder;
import com.google.javascript.rhino.JSTypeExpression;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import com.google.javascript.rhino.jstype.JSType;

import java.util.HashSet;
import java.util.Set;

Expand Down Expand Up @@ -58,7 +57,7 @@ class ConvertToTypedInterface implements CompilerPass {
@Override
public void process(Node externs, Node root) {
NodeTraversal.traverseEs6(compiler, root, new PropagateConstJsdoc(compiler));
NodeTraversal.traverseEs6(compiler, root, new RemoveCode(compiler));
NodeTraversal.traverseRootsEs6(compiler, new RemoveCode(compiler), externs, root);
}

private static class PropagateConstJsdoc extends NodeTraversal.AbstractPostOrderCallback {
Expand All @@ -74,22 +73,22 @@ public void visit(NodeTraversal t, Node n, Node parent) {
case EXPR_RESULT:
if (NodeUtil.isExprAssign(n)) {
Node expr = n.getFirstChild();
processName(t, expr.getFirstChild());
propagateJsdocAtName(t, expr.getFirstChild());
}
break;
case VAR:
case CONST:
case LET:
if (n.getChildCount() == 1) {
processName(t, n.getFirstChild());
propagateJsdocAtName(t, n.getFirstChild());
}
break;
default:
break;
}
}

private void processName(NodeTraversal t, Node nameNode) {
private void propagateJsdocAtName(NodeTraversal t, Node nameNode) {
Node jsdocNode = NodeUtil.getBestJSDocInfoNode(nameNode);
JSDocInfo jsdoc = jsdocNode.getJSDocInfo();
if (!isInferrableConst(jsdoc, nameNode)) {
Expand Down Expand Up @@ -168,14 +167,28 @@ private static JSDocInfo getJSDocForName(Var decl, JSDocInfo oldJSDoc) {

}

private static class RemoveCode implements Callback {
private static class RemoveCode extends AbstractModuleCallback {
private final AbstractCompiler compiler;
private final Set<String> seenNames = new HashSet<>();
private final Set<String> globalSeenNames = new HashSet<>();
private Node currentModule = null;
private Set<String> moduleSeenNames;

RemoveCode(AbstractCompiler compiler) {
this.compiler = compiler;
}

@Override
public void enterModule(NodeTraversal t, Node scopeRoot) {
currentModule = scopeRoot;
moduleSeenNames = new HashSet<>();
}

@Override
public void exitModule(NodeTraversal t, Node scopeRoot) {
currentModule = null;
moduleSeenNames = null;
}

@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
switch (n.getType()) {
Expand Down Expand Up @@ -213,12 +226,17 @@ public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
parent.removeChild(childBefore);
compiler.reportCodeChange();
}
} else if (!callee.matchesQualifiedName("goog.require")) {
} else if (!callee.matchesQualifiedName("goog.require")
&& !callee.matchesQualifiedName("goog.module")) {
n.detachFromParent();
compiler.reportCodeChange();
}
break;
case ASSIGN:
if (t.inModuleScope() && expr.getFirstChild().matchesQualifiedName("exports")) {
// Module exports shouldn't be renamed
break;
}
processName(expr.getFirstChild(), n);
break;
case GETPROP:
Expand Down Expand Up @@ -296,14 +314,32 @@ public void visit(NodeTraversal t, Node n, Node parent) {
}
}

private boolean isNameProcessed(String fullyQualifiedName) {
if (currentModule == null) {
return globalSeenNames.contains(fullyQualifiedName);
} else {
return moduleSeenNames.contains(fullyQualifiedName);
}
}

private void markNameProcessed(String fullyQualifiedName) {
if (currentModule == null) {
globalSeenNames.add(fullyQualifiedName);
} else {
moduleSeenNames.add(fullyQualifiedName);
}
}

private void processConstructor(final Node function) {
final String className = getClassName(function);
if (className == null) {
return;
}
final Node insertionPoint = NodeUtil.getEnclosingStatement(function);
NodeTraversal.traverseEs6(
compiler, function.getLastChild(), new AbstractShallowStatementCallback() {
compiler,
function.getLastChild(),
new AbstractShallowStatementCallback() {
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.isExprResult()) {
Expand All @@ -314,7 +350,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
}
String pname = name.getLastChild().getString();
String fullyQualifiedName = className + ".prototype." + pname;
if (seenNames.contains(fullyQualifiedName)) {
if (isNameProcessed(fullyQualifiedName)) {
return;
}
JSDocInfo jsdoc = NodeUtil.getBestJSDocInfo(name);
Expand All @@ -329,7 +365,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
// TODO(blickly): Preserve the declaration order of the this properties.
insertionPoint.getParent().addChildAfter(newProtoAssignStmt, insertionPoint);
compiler.reportCodeChange();
seenNames.add(fullyQualifiedName);
markNameProcessed(fullyQualifiedName);
}
}
});
Expand All @@ -345,7 +381,6 @@ private RemovalType shouldRemove(Node nameNode) {
Node jsdocNode = NodeUtil.getBestJSDocInfoNode(nameNode);
JSDocInfo jsdoc = jsdocNode.getJSDocInfo();
Node rhs = NodeUtil.getRValueOfLValue(nameNode);
// System.err.println("RHS of " + nameNode + " is " + rhs);
if (rhs == null
|| rhs.isFunction()
|| (rhs.isQualifiedName() && rhs.matchesQualifiedName("goog.abstractMethod"))
Expand All @@ -357,7 +392,7 @@ private RemovalType shouldRemove(Node nameNode) {
}
if (jsdoc == null
|| !jsdoc.containsDeclaration()) {
if (seenNames.contains(nameNode.getQualifiedName())) {
if (isNameProcessed(nameNode.getQualifiedName())) {
return RemovalType.REMOVE_ALL;
}
jsdocNode.setJSDocInfo(getAllTypeJSDoc());
Expand Down Expand Up @@ -387,7 +422,7 @@ private void processName(Node nameNode, Node statement) {
maybeRemoveRhs(nameNode, statement, jsdocNode.getJSDocInfo());
break;
}
seenNames.add(nameNode.getQualifiedName());
markNameProcessed(nameNode.getQualifiedName());
}

private void removeNode(Node n) {
Expand Down
68 changes: 68 additions & 0 deletions test/com/google/javascript/jscomp/ConvertToTypedInterfaceTest.java
Expand Up @@ -39,6 +39,10 @@ public void testInferAnnotatedTypeFromTypeInference() {
"/** @constructor */ function Foo() {} \n /** @const {number} */ Foo.prototype.x;");
}

public void testExternsDefinitionsRespected() {
test("/** @type {number} */ var x;", "x = 7;", "", null, null);
}

public void testSimpleConstJsdocPropagation() {
test("/** @const */ var x = 5;", "/** @const {number} */ var x;");
test("/** @const */ var x = true;", "/** @const {boolean} */ var x;");
Expand Down Expand Up @@ -216,6 +220,70 @@ public void testRemoveUnnecessaryBodies() {
"class Foo { method(/** string */ s) {} }");
}

public void testGoogModules() {
testSame(
LINE_JOINER.join(
"goog.module('x.y.z');",
"",
"/** @constructor */ function Foo() {};",
"",
"exports = Foo;"));

testSame(
new String[] {
LINE_JOINER.join(
"goog.module('a.b.c');",
"/** @constructor */ function Foo() {}",
"Foo.prototoype.display = function() {};",
"exports = Foo;"),
LINE_JOINER.join(
"goog.module('x.y.z');",
"/** @constructor */ function Foo() {}",
"Foo.prototoype.display = function() {};",
"exports = Foo;"),
});

testSame(
new String[] {
LINE_JOINER.join(
"/** @constructor */ function Foo() {}",
"Foo.prototoype.display = function() {};"),
LINE_JOINER.join(
"goog.module('x.y.z');",
"/** @constructor */ function Foo() {}",
"Foo.prototoype.display = function() {};",
"exports = Foo;"),
});

test(
new String[] {
LINE_JOINER.join(
"goog.module('a.b.c');",
"/** @constructor */ function Foo() {",
" /** @type {number} */ this.x = 5;",
"}",
"exports = Foo;"),
LINE_JOINER.join(
"goog.module('x.y.z');",
"/** @constructor */ function Foo() {",
" /** @type {number} */ this.x = 99;",
"}",
"exports = Foo;"),
},
new String[] {
LINE_JOINER.join(
"goog.module('a.b.c');",
"/** @constructor */ function Foo() {}",
"/** @type {number} */ Foo.prototype.x;",
"exports = Foo;"),
LINE_JOINER.join(
"goog.module('x.y.z');",
"/** @constructor */ function Foo() {}",
"/** @type {number} */ Foo.prototype.x;",
"exports = Foo;"),
});
}

public void testRemoveCalls() {
test("alert('hello'); window.clearTimeout();", "");

Expand Down

0 comments on commit 120864d

Please sign in to comment.