Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(377)

Unified Diff: third_party/closure_compiler/runner/src/com/google/javascript/jscomp/ChromePass.java

Issue 2629323002: Remove Chromium's custom closure runner. (Closed)
Patch Set: merge Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/closure_compiler/runner/src/com/google/javascript/jscomp/ChromePass.java
diff --git a/third_party/closure_compiler/runner/src/com/google/javascript/jscomp/ChromePass.java b/third_party/closure_compiler/runner/src/com/google/javascript/jscomp/ChromePass.java
deleted file mode 100644
index b15d0b67d05f0bab239cfc7c8df66165671c8ff4..0000000000000000000000000000000000000000
--- a/third_party/closure_compiler/runner/src/com/google/javascript/jscomp/ChromePass.java
+++ /dev/null
@@ -1,456 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.google.javascript.jscomp;
-
-import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
-import com.google.javascript.rhino.IR;
-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 java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Compiler pass for Chrome-specific needs. It handles the following Chrome JS features:
- * <ul>
- * <li>namespace declaration using {@code cr.define()},
- * <li>unquoted property declaration using {@code {cr|Object}.defineProperty()}.
- * </ul>
- *
- * <p>For the details, see tests inside ChromePassTest.java.
- */
-public class ChromePass extends AbstractPostOrderCallback implements CompilerPass {
- final AbstractCompiler compiler;
-
- private Set<String> createdObjects;
-
- private static final String CR_DEFINE = "cr.define";
- private static final String CR_EXPORT_PATH = "cr.exportPath";
- private static final String OBJECT_DEFINE_PROPERTY = "Object.defineProperty";
- private static final String CR_DEFINE_PROPERTY = "cr.defineProperty";
- private static final String CR_MAKE_PUBLIC = "cr.makePublic";
-
- private static final String CR_DEFINE_COMMON_EXPLANATION = "It should be called like this:"
- + " cr.define('name.space', function() '{ ... return {Export: Internal}; }');";
-
- static final DiagnosticType CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS =
- DiagnosticType.error("JSC_CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS",
- "cr.define() should have exactly 2 arguments. " + CR_DEFINE_COMMON_EXPLANATION);
-
- static final DiagnosticType CR_EXPORT_PATH_TOO_FEW_ARGUMENTS =
- DiagnosticType.error("JSC_CR_EXPORT_PATH_TOO_FEW_ARGUMENTS",
- "cr.exportPath() should have at least 1 argument: path name.");
-
- static final DiagnosticType CR_DEFINE_INVALID_FIRST_ARGUMENT =
- DiagnosticType.error("JSC_CR_DEFINE_INVALID_FIRST_ARGUMENT",
- "Invalid first argument for cr.define(). " + CR_DEFINE_COMMON_EXPLANATION);
-
- static final DiagnosticType CR_DEFINE_INVALID_SECOND_ARGUMENT =
- DiagnosticType.error("JSC_CR_DEFINE_INVALID_SECOND_ARGUMENT",
- "Invalid second argument for cr.define(). " + CR_DEFINE_COMMON_EXPLANATION);
-
- static final DiagnosticType CR_DEFINE_INVALID_RETURN_IN_FUNCTION =
- DiagnosticType.error("JSC_CR_DEFINE_INVALID_RETURN_IN_SECOND_ARGUMENT",
- "Function passed as second argument of cr.define() should return the"
- + " dictionary in its last statement. " + CR_DEFINE_COMMON_EXPLANATION);
-
- static final DiagnosticType CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND =
- DiagnosticType.error("JSC_CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND",
- "Invalid cr.PropertyKind passed to cr.defineProperty(): expected ATTR,"
- + " BOOL_ATTR or JS, found \"{0}\".");
-
- static final DiagnosticType CR_MAKE_PUBLIC_HAS_NO_JSDOC =
- DiagnosticType.error("JSC_CR_MAKE_PUBLIC_HAS_NO_JSDOC",
- "Private method exported by cr.makePublic() has no JSDoc.");
-
- static final DiagnosticType CR_MAKE_PUBLIC_MISSED_DECLARATION =
- DiagnosticType.error("JSC_CR_MAKE_PUBLIC_MISSED_DECLARATION",
- "Method \"{1}_\" exported by cr.makePublic() on \"{0}\" has no declaration.");
-
- static final DiagnosticType CR_MAKE_PUBLIC_INVALID_SECOND_ARGUMENT =
- DiagnosticType.error("JSC_CR_MAKE_PUBLIC_INVALID_SECOND_ARGUMENT",
- "Invalid second argument passed to cr.makePublic(): should be array of " +
- "strings.");
-
- public ChromePass(AbstractCompiler compiler) {
- this.compiler = compiler;
- // The global variable "cr" is declared in ui/webui/resources/js/cr.js.
- this.createdObjects = new HashSet<>(Arrays.asList("cr"));
- }
-
- @Override
- public void process(Node externs, Node root) {
- NodeTraversal.traverse(compiler, root, this);
- }
-
- @Override
- public void visit(NodeTraversal t, Node node, Node parent) {
- if (node.isCall()) {
- Node callee = node.getFirstChild();
- if (callee.matchesQualifiedName(CR_DEFINE)) {
- visitNamespaceDefinition(node, parent);
- compiler.reportCodeChange();
- } else if (callee.matchesQualifiedName(CR_EXPORT_PATH)) {
- visitExportPath(node, parent);
- compiler.reportCodeChange();
- } else if (callee.matchesQualifiedName(OBJECT_DEFINE_PROPERTY) ||
- callee.matchesQualifiedName(CR_DEFINE_PROPERTY)) {
- visitPropertyDefinition(node, parent);
- compiler.reportCodeChange();
- } else if (callee.matchesQualifiedName(CR_MAKE_PUBLIC)) {
- if (visitMakePublic(node, parent)) {
- compiler.reportCodeChange();
- }
- }
- }
- }
-
- private void visitPropertyDefinition(Node call, Node parent) {
- Node callee = call.getFirstChild();
- String target = call.getChildAtIndex(1).getQualifiedName();
- if (callee.matchesQualifiedName(CR_DEFINE_PROPERTY) && !target.endsWith(".prototype")) {
- target += ".prototype";
- }
-
- Node property = call.getChildAtIndex(2);
-
- Node getPropNode = NodeUtil.newQName(
- compiler, target + "." + property.getString()).srcrefTree(call);
-
- if (callee.matchesQualifiedName(CR_DEFINE_PROPERTY)) {
- setJsDocWithType(getPropNode, getTypeByCrPropertyKind(call.getChildAtIndex(3)));
- } else {
- setJsDocWithType(getPropNode, new Node(Token.QMARK));
- }
-
- Node definitionNode = IR.exprResult(getPropNode).srcref(parent);
-
- parent.getParent().addChildAfter(definitionNode, parent);
- }
-
- private Node getTypeByCrPropertyKind(Node propertyKind) {
- if (propertyKind == null || propertyKind.matchesQualifiedName("cr.PropertyKind.JS")) {
- return new Node(Token.QMARK);
- }
- if (propertyKind.matchesQualifiedName("cr.PropertyKind.ATTR")) {
- return IR.string("string");
- }
- if (propertyKind.matchesQualifiedName("cr.PropertyKind.BOOL_ATTR")) {
- return IR.string("boolean");
- }
- compiler.report(JSError.make(propertyKind, CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND,
- propertyKind.getQualifiedName()));
- return null;
- }
-
- private void setJsDocWithType(Node target, Node type) {
- JSDocInfoBuilder builder = new JSDocInfoBuilder(false);
- builder.recordType(new JSTypeExpression(type, ""));
- target.setJSDocInfo(builder.build());
- }
-
- private boolean visitMakePublic(Node call, Node exprResult) {
- boolean changesMade = false;
- Node scope = exprResult.getParent();
- String className = call.getChildAtIndex(1).getQualifiedName();
- String prototype = className + ".prototype";
- Node methods = call.getChildAtIndex(2);
-
- if (methods == null || !methods.isArrayLit()) {
- compiler.report(JSError.make(exprResult, CR_MAKE_PUBLIC_INVALID_SECOND_ARGUMENT));
- return changesMade;
- }
-
- Set<String> methodNames = new HashSet<>();
- for (Node methodName: methods.children()) {
- if (!methodName.isString()) {
- compiler.report(JSError.make(methodName, CR_MAKE_PUBLIC_INVALID_SECOND_ARGUMENT));
- return changesMade;
- }
- methodNames.add(methodName.getString());
- }
-
- for (Node child: scope.children()) {
- if (isAssignmentToPrototype(child, prototype)) {
- Node objectLit = child.getFirstChild().getChildAtIndex(1);
- for (Node stringKey : objectLit.children()) {
- String field = stringKey.getString();
- changesMade |= maybeAddPublicDeclaration(field, methodNames, className,
- stringKey, scope, exprResult);
- }
- } else if (isAssignmentToPrototypeMethod(child, prototype)) {
- Node assignNode = child.getFirstChild();
- String qualifiedName = assignNode.getFirstChild().getQualifiedName();
- String field = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1);
- changesMade |= maybeAddPublicDeclaration(field, methodNames, className,
- assignNode, scope, exprResult);
- } else if (isDummyPrototypeMethodDeclaration(child, prototype)) {
- String qualifiedName = child.getFirstChild().getQualifiedName();
- String field = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1);
- changesMade |= maybeAddPublicDeclaration(field, methodNames, className,
- child.getFirstChild(), scope, exprResult);
- }
- }
-
- for (String missedDeclaration : methodNames) {
- compiler.report(JSError.make(exprResult, CR_MAKE_PUBLIC_MISSED_DECLARATION, className,
- missedDeclaration));
- }
-
- return changesMade;
- }
-
- private boolean isAssignmentToPrototype(Node node, String prototype) {
- Node assignNode;
- return node.isExprResult() && (assignNode = node.getFirstChild()).isAssign() &&
- assignNode.getFirstChild().getQualifiedName().equals(prototype);
- }
-
- private boolean isAssignmentToPrototypeMethod(Node node, String prototype) {
- Node assignNode;
- return node.isExprResult() && (assignNode = node.getFirstChild()).isAssign() &&
- assignNode.getFirstChild().getQualifiedName().startsWith(prototype + ".");
- }
-
- private boolean isDummyPrototypeMethodDeclaration(Node node, String prototype) {
- Node getPropNode;
- return node.isExprResult() && (getPropNode = node.getFirstChild()).isGetProp() &&
- getPropNode.getQualifiedName().startsWith(prototype + ".");
- }
-
- private boolean maybeAddPublicDeclaration(String field, Set<String> publicAPIStrings,
- String className, Node jsDocSourceNode, Node scope, Node exprResult) {
- boolean changesMade = false;
- if (field.endsWith("_")) {
- String publicName = field.substring(0, field.length() - 1);
- if (publicAPIStrings.contains(publicName)) {
- Node methodDeclaration = NodeUtil.newQName(compiler, className + "." + publicName);
- if (jsDocSourceNode.getJSDocInfo() != null) {
- methodDeclaration.setJSDocInfo(jsDocSourceNode.getJSDocInfo());
- scope.addChildBefore(
- IR.exprResult(methodDeclaration).srcrefTree(exprResult),
- exprResult);
- changesMade = true;
- } else {
- compiler.report(JSError.make(jsDocSourceNode, CR_MAKE_PUBLIC_HAS_NO_JSDOC));
- }
- publicAPIStrings.remove(publicName);
- }
- }
- return changesMade;
- }
-
- private void visitExportPath(Node crExportPathNode, Node parent) {
- if (crExportPathNode.getChildCount() < 2) {
- compiler.report(JSError.make(crExportPathNode, CR_EXPORT_PATH_TOO_FEW_ARGUMENTS));
- return;
- }
-
- Node pathArg = crExportPathNode.getChildAtIndex(1);
- if (pathArg.isString()) {
- // TODO(dbeam): support cr.exportPath('ns').value.
- createAndInsertObjectsForQualifiedName(parent, pathArg.getString());
- }
- }
-
- private void createAndInsertObjectsForQualifiedName(Node scriptChild, String namespace) {
- List<Node> objectsForQualifiedName = createObjectsForQualifiedName(namespace);
- for (Node n : objectsForQualifiedName) {
- scriptChild.getParent().addChildBefore(n, scriptChild);
- }
- }
-
- private void visitNamespaceDefinition(Node crDefineCallNode, Node parent) {
- if (crDefineCallNode.getChildCount() != 3) {
- compiler.report(JSError.make(crDefineCallNode, CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS));
- }
-
- Node namespaceArg = crDefineCallNode.getChildAtIndex(1);
- Node function = crDefineCallNode.getChildAtIndex(2);
-
- if (!namespaceArg.isString()) {
- compiler.report(JSError.make(namespaceArg, CR_DEFINE_INVALID_FIRST_ARGUMENT));
- return;
- }
-
- // TODO(vitalyp): Check namespace name for validity here. It should be a valid chain of
- // identifiers.
- String namespace = namespaceArg.getString();
-
- createAndInsertObjectsForQualifiedName(parent, namespace);
-
- if (!function.isFunction()) {
- compiler.report(JSError.make(namespaceArg, CR_DEFINE_INVALID_SECOND_ARGUMENT));
- return;
- }
-
- Node returnNode, objectLit;
- Node functionBlock = function.getLastChild();
- if ((returnNode = functionBlock.getLastChild()) == null ||
- !returnNode.isReturn() ||
- (objectLit = returnNode.getFirstChild()) == null ||
- !objectLit.isObjectLit()) {
- compiler.report(JSError.make(namespaceArg, CR_DEFINE_INVALID_RETURN_IN_FUNCTION));
- return;
- }
-
- Map<String, String> exports = objectLitToMap(objectLit);
-
- NodeTraversal.traverse(compiler, functionBlock, new RenameInternalsToExternalsCallback(
- namespace, exports, functionBlock));
- }
-
- private Map<String, String> objectLitToMap(Node objectLit) {
- Map<String, String> res = new HashMap<String, String>();
-
- for (Node keyNode : objectLit.children()) {
- String key = keyNode.getString();
-
- Node valueNode = keyNode.getFirstChild();
- if (valueNode.isName()) {
- String value = keyNode.getFirstChild().getString();
- res.put(value, key);
- }
- }
-
- return res;
- }
-
- /**
- * For a string "a.b.c" produce the following JS IR:
- *
- * <p><pre>
- * var a = a || {};
- * a.b = a.b || {};
- * a.b.c = a.b.c || {};</pre>
- */
- private List<Node> createObjectsForQualifiedName(String namespace) {
- List<Node> objects = new ArrayList<>();
- String[] parts = namespace.split("\\.");
-
- createObjectIfNew(objects, parts[0], true);
-
- if (parts.length >= 2) {
- StringBuilder currPrefix = new StringBuilder().append(parts[0]);
- for (int i = 1; i < parts.length; ++i) {
- currPrefix.append(".").append(parts[i]);
- createObjectIfNew(objects, currPrefix.toString(), false);
- }
- }
-
- return objects;
- }
-
- private void createObjectIfNew(List<Node> objects, String name, boolean needVar) {
- if (!createdObjects.contains(name)) {
- objects.add(createJsNode((needVar ? "var " : "") + name + " = " + name + " || {};"));
- createdObjects.add(name);
- }
- }
-
- private Node createJsNode(String code) {
- // The parent node after parseSyntheticCode() is SCRIPT node, we need to get rid of it.
- return compiler.parseSyntheticCode(code).removeFirstChild();
- }
-
- private class RenameInternalsToExternalsCallback extends AbstractPostOrderCallback {
- private final String namespaceName;
- private final Map<String, String> exports;
- private final Node namespaceBlock;
-
- public RenameInternalsToExternalsCallback(String namespaceName,
- Map<String, String> exports, Node namespaceBlock) {
- this.namespaceName = namespaceName;
- this.exports = exports;
- this.namespaceBlock = namespaceBlock;
- }
-
- @Override
- public void visit(NodeTraversal t, Node n, Node parent) {
- if (n.isFunction() && parent == this.namespaceBlock &&
- this.exports.containsKey(n.getFirstChild().getString())) {
- // It's a top-level function/constructor definition.
- //
- // Change
- //
- // /** Some doc */
- // function internalName() {}
- //
- // to
- //
- // /** Some doc */
- // my.namespace.name.externalName = function internalName() {};
- //
- // by looking up in this.exports for internalName to find the correspondent
- // externalName.
- Node functionTree = n.cloneTree();
- Node exprResult = IR.exprResult(
- IR.assign(buildQualifiedName(n.getFirstChild()), functionTree).srcref(n)
- ).srcref(n);
-
- if (n.getJSDocInfo() != null) {
- exprResult.getFirstChild().setJSDocInfo(n.getJSDocInfo());
- functionTree.removeProp(Node.JSDOC_INFO_PROP);
- }
- this.namespaceBlock.replaceChild(n, exprResult);
- } else if (n.isName() && this.exports.containsKey(n.getString()) &&
- !parent.isFunction()) {
- if (parent.isVar()) {
- if (parent.getParent() == this.namespaceBlock) {
- // It's a top-level exported variable definition (maybe without an
- // assignment).
- // Change
- //
- // var enum = { 'one': 1, 'two': 2 };
- //
- // to
- //
- // my.namespace.name.enum = { 'one': 1, 'two': 2 };
- Node varContent = n.removeFirstChild();
- Node exprResult;
- if (varContent == null) {
- exprResult = IR.exprResult(buildQualifiedName(n)).srcref(parent);
- } else {
- exprResult = IR.exprResult(
- IR.assign(buildQualifiedName(n), varContent).srcref(parent)
- ).srcref(parent);
- }
- if (parent.getJSDocInfo() != null) {
- exprResult.getFirstChild().setJSDocInfo(parent.getJSDocInfo().clone());
- }
- this.namespaceBlock.replaceChild(parent, exprResult);
- }
- } else {
- // It's a local name referencing exported entity. Change to its global name.
- Node newNode = buildQualifiedName(n);
- if (n.getJSDocInfo() != null) {
- newNode.setJSDocInfo(n.getJSDocInfo().clone());
- }
-
- // If we alter the name of a called function, then it gets an explicit "this"
- // value.
- if (parent.isCall()) {
- parent.putBooleanProp(Node.FREE_CALL, false);
- }
-
- parent.replaceChild(n, newNode);
- }
- }
- }
-
- private Node buildQualifiedName(Node internalName) {
- String externalName = this.exports.get(internalName.getString());
- return NodeUtil.newQName(compiler, this.namespaceName + "." + externalName).srcrefTree(
- internalName);
- }
- }
-}

Powered by Google App Engine
This is Rietveld 408576698