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

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

Issue 453783006: Handle cr.exportPath() in compiler pass, declare every object only once (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@C_define_property
Patch Set: Created 6 years, 4 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package com.google.javascript.jscomp; 5 package com.google.javascript.jscomp;
6 6
7 import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; 7 import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
8 import com.google.javascript.rhino.IR; 8 import com.google.javascript.rhino.IR;
9 import com.google.javascript.rhino.JSDocInfoBuilder; 9 import com.google.javascript.rhino.JSDocInfoBuilder;
10 import com.google.javascript.rhino.JSTypeExpression; 10 import com.google.javascript.rhino.JSTypeExpression;
11 import com.google.javascript.rhino.Node; 11 import com.google.javascript.rhino.Node;
12 import com.google.javascript.rhino.Token; 12 import com.google.javascript.rhino.Token;
13 13
14 import java.util.ArrayList; 14 import java.util.ArrayList;
15 import java.util.HashMap; 15 import java.util.HashMap;
16 import java.util.HashSet;
16 import java.util.List; 17 import java.util.List;
17 import java.util.Map; 18 import java.util.Map;
19 import java.util.Set;
18 20
19 /** 21 /**
20 * Compiler pass for Chrome-specific needs. It handles the following Chrome JS f eatures: 22 * Compiler pass for Chrome-specific needs. It handles the following Chrome JS f eatures:
21 * <ul> 23 * <ul>
22 * <li>namespace declaration using {@code cr.define()}, 24 * <li>namespace declaration using {@code cr.define()},
23 * <li>unquoted property declaration using {@code {cr|Object}.defineProperty()}. 25 * <li>unquoted property declaration using {@code {cr|Object}.defineProperty()}.
24 * </ul> 26 * </ul>
25 * 27 *
26 * <p>For the details, see tests inside ChromePassTest.java. 28 * <p>For the details, see tests inside ChromePassTest.java.
27 */ 29 */
28 public class ChromePass extends AbstractPostOrderCallback implements CompilerPas s { 30 public class ChromePass extends AbstractPostOrderCallback implements CompilerPas s {
29 final AbstractCompiler compiler; 31 final AbstractCompiler compiler;
30 32
33 private Set<String> createdObjects;
34
31 private static final String CR_DEFINE = "cr.define"; 35 private static final String CR_DEFINE = "cr.define";
32 36 private static final String CR_EXPORT_PATH = "cr.exportPath";
33 private static final String OBJECT_DEFINE_PROPERTY = "Object.defineProperty" ; 37 private static final String OBJECT_DEFINE_PROPERTY = "Object.defineProperty" ;
34
35 private static final String CR_DEFINE_PROPERTY = "cr.defineProperty"; 38 private static final String CR_DEFINE_PROPERTY = "cr.defineProperty";
36 39
37 private static final String CR_DEFINE_COMMON_EXPLANATION = "It should be cal led like this: " + 40 private static final String CR_DEFINE_COMMON_EXPLANATION = "It should be cal led like this: " +
38 "cr.define('name.space', function() '{ ... return {Export: Internal} ; }');"; 41 "cr.define('name.space', function() '{ ... return {Export: Internal} ; }');";
39 42
40 static final DiagnosticType CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS = 43 static final DiagnosticType CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS =
41 DiagnosticType.error("JSC_CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS", 44 DiagnosticType.error("JSC_CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS",
42 "cr.define() should have exactly 2 arguments. " + CR_DEFINE_ COMMON_EXPLANATION); 45 "cr.define() should have exactly 2 arguments. " + CR_DEFINE_ COMMON_EXPLANATION);
43 46
47 static final DiagnosticType CR_EXPORT_PATH_WRONG_NUMBER_OF_ARGUMENTS =
48 DiagnosticType.error("JSC_CR_EXPORT_PATH_WRONG_NUMBER_OF_ARGUMENTS",
49 "cr.exportPath() should have exactly 1 argument: namespace n ame.");
50
44 static final DiagnosticType CR_DEFINE_INVALID_FIRST_ARGUMENT = 51 static final DiagnosticType CR_DEFINE_INVALID_FIRST_ARGUMENT =
45 DiagnosticType.error("JSC_CR_DEFINE_INVALID_FIRST_ARGUMENT", 52 DiagnosticType.error("JSC_CR_DEFINE_INVALID_FIRST_ARGUMENT",
46 "Invalid first argument for cr.define(). " + CR_DEFINE_COMMO N_EXPLANATION); 53 "Invalid first argument for cr.define(). " + CR_DEFINE_COMMO N_EXPLANATION);
47 54
48 static final DiagnosticType CR_DEFINE_INVALID_SECOND_ARGUMENT = 55 static final DiagnosticType CR_DEFINE_INVALID_SECOND_ARGUMENT =
49 DiagnosticType.error("JSC_CR_DEFINE_INVALID_SECOND_ARGUMENT", 56 DiagnosticType.error("JSC_CR_DEFINE_INVALID_SECOND_ARGUMENT",
50 "Invalid second argument for cr.define(). " + CR_DEFINE_COMM ON_EXPLANATION); 57 "Invalid second argument for cr.define(). " + CR_DEFINE_COMM ON_EXPLANATION);
51 58
52 static final DiagnosticType CR_DEFINE_INVALID_RETURN_IN_FUNCTION = 59 static final DiagnosticType CR_DEFINE_INVALID_RETURN_IN_FUNCTION =
53 DiagnosticType.error("JSC_CR_DEFINE_INVALID_RETURN_IN_SECOND_ARGUMEN T", 60 DiagnosticType.error("JSC_CR_DEFINE_INVALID_RETURN_IN_SECOND_ARGUMEN T",
54 "Function passed as second argument of cr.define() should re turn the " + 61 "Function passed as second argument of cr.define() should re turn the " +
55 "dictionary in its last statement. " + CR_DEFINE_COMMON_EXPL ANATION); 62 "dictionary in its last statement. " + CR_DEFINE_COMMON_EXPL ANATION);
56 63
57 static final DiagnosticType CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND = 64 static final DiagnosticType CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND =
58 DiagnosticType.error("JSC_CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND", 65 DiagnosticType.error("JSC_CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND",
59 "Invalid cr.PropertyKind passed to cr.defineProperty(): expe cted ATTR, " + 66 "Invalid cr.PropertyKind passed to cr.defineProperty(): expe cted ATTR, " +
60 "BOOL_ATTR or JS, found \"{0}\"."); 67 "BOOL_ATTR or JS, found \"{0}\".");
61 68
62 public ChromePass(AbstractCompiler compiler) { 69 public ChromePass(AbstractCompiler compiler) {
63 this.compiler = compiler; 70 this.compiler = compiler;
71 this.createdObjects = new HashSet<>();
Dan Beam 2014/08/14 02:23:02 nit: this.createdObjects = new HashSet<>(Arrays.as
Vitaly Pavlenko 2014/08/14 02:40:59 Done.
72 // This variable is declared in ui/webui/resources/js/cr.js
Dan Beam 2014/08/14 02:23:01 nit: end with .
Vitaly Pavlenko 2014/08/14 02:40:59 Done.
73 createdObjects.add("cr");
64 } 74 }
65 75
66 @Override 76 @Override
67 public void process(Node externs, Node root) { 77 public void process(Node externs, Node root) {
68 NodeTraversal.traverse(compiler, root, this); 78 NodeTraversal.traverse(compiler, root, this);
69 } 79 }
70 80
71 @Override 81 @Override
72 public void visit(NodeTraversal t, Node node, Node parent) { 82 public void visit(NodeTraversal t, Node node, Node parent) {
73 if (node.isCall()) { 83 if (node.isCall()) {
74 Node callee = node.getFirstChild(); 84 Node callee = node.getFirstChild();
75 if (callee.matchesQualifiedName(CR_DEFINE)) { 85 if (callee.matchesQualifiedName(CR_DEFINE)) {
76 visitNamespaceDefinition(node, parent); 86 visitNamespaceDefinition(node, parent);
77 compiler.reportCodeChange(); 87 compiler.reportCodeChange();
88 } else if (callee.matchesQualifiedName(CR_EXPORT_PATH)) {
89 visitExportPath(node, parent);
90 compiler.reportCodeChange();
78 } else if (callee.matchesQualifiedName(OBJECT_DEFINE_PROPERTY) || 91 } else if (callee.matchesQualifiedName(OBJECT_DEFINE_PROPERTY) ||
79 callee.matchesQualifiedName(CR_DEFINE_PROPERTY)) { 92 callee.matchesQualifiedName(CR_DEFINE_PROPERTY)) {
80 visitPropertyDefinition(node, parent); 93 visitPropertyDefinition(node, parent);
81 compiler.reportCodeChange(); 94 compiler.reportCodeChange();
82 } 95 }
83 } 96 }
84 } 97 }
85 98
86 private void visitPropertyDefinition(Node call, Node parent) { 99 private void visitPropertyDefinition(Node call, Node parent) {
87 Node callee = call.getFirstChild(); 100 Node callee = call.getFirstChild();
(...skipping 27 matching lines...) Expand all
115 return null; 128 return null;
116 } 129 }
117 } 130 }
118 131
119 private void setJsDocWithType(Node target, Node type) { 132 private void setJsDocWithType(Node target, Node type) {
120 JSDocInfoBuilder builder = new JSDocInfoBuilder(false); 133 JSDocInfoBuilder builder = new JSDocInfoBuilder(false);
121 builder.recordType(new JSTypeExpression(type, "")); 134 builder.recordType(new JSTypeExpression(type, ""));
122 target.setJSDocInfo(builder.build(target)); 135 target.setJSDocInfo(builder.build(target));
123 } 136 }
124 137
138 private void visitExportPath(Node crExportPathNode, Node parent) {
139 if (crExportPathNode.getChildCount() != 2) {
140 compiler.report(JSError.make(crExportPathNode,
141 CR_EXPORT_PATH_WRONG_NUMBER_OF_ARGUMENTS));
142 return;
143 }
144
145 createAndInsertObjectsForQualifiedName(parent,
146 crExportPathNode.getChildAtIndex(1).getString());
147 }
148
149 private void createAndInsertObjectsForQualifiedName(Node scriptChild, String namespace) {
150 List<Node> objectsForQualifiedName = createObjectsForQualifiedName(names pace);
151 for (Node n : objectsForQualifiedName) {
152 scriptChild.getParent().addChildBefore(n, scriptChild);
153 }
154 }
155
125 private void visitNamespaceDefinition(Node crDefineCallNode, Node parent) { 156 private void visitNamespaceDefinition(Node crDefineCallNode, Node parent) {
126 if (crDefineCallNode.getChildCount() != 3) { 157 if (crDefineCallNode.getChildCount() != 3) {
127 compiler.report(JSError.make(crDefineCallNode, CR_DEFINE_WRONG_NUMBE R_OF_ARGUMENTS)); 158 compiler.report(JSError.make(crDefineCallNode, CR_DEFINE_WRONG_NUMBE R_OF_ARGUMENTS));
128 } 159 }
129 160
130 Node namespaceArg = crDefineCallNode.getChildAtIndex(1); 161 Node namespaceArg = crDefineCallNode.getChildAtIndex(1);
131 Node function = crDefineCallNode.getChildAtIndex(2); 162 Node function = crDefineCallNode.getChildAtIndex(2);
132 163
133 if (!namespaceArg.isString()) { 164 if (!namespaceArg.isString()) {
134 compiler.report(JSError.make(namespaceArg, CR_DEFINE_INVALID_FIRST_A RGUMENT)); 165 compiler.report(JSError.make(namespaceArg, CR_DEFINE_INVALID_FIRST_A RGUMENT));
135 return; 166 return;
136 } 167 }
137 168
138 // TODO(vitalyp): Check namespace name for validity here. It should be a valid chain of 169 // TODO(vitalyp): Check namespace name for validity here. It should be a valid chain of
139 // identifiers. 170 // identifiers.
140 String namespace = namespaceArg.getString(); 171 String namespace = namespaceArg.getString();
141 172
142 List<Node> objectsForQualifiedName = createObjectsForQualifiedName(names pace); 173 createAndInsertObjectsForQualifiedName(parent, namespace);
143 for (Node n : objectsForQualifiedName) {
144 parent.getParent().addChildBefore(n, parent);
145 }
146 174
147 Node returnNode, functionBlock, objectLit; 175 Node returnNode, functionBlock, objectLit;
148 if (!function.isFunction()) { 176 if (!function.isFunction()) {
149 compiler.report(JSError.make(namespaceArg, CR_DEFINE_INVALID_SECOND_ ARGUMENT)); 177 compiler.report(JSError.make(namespaceArg, CR_DEFINE_INVALID_SECOND_ ARGUMENT));
150 return; 178 return;
151 } 179 }
152 180
153 if ((functionBlock = function.getLastChild()) == null || 181 if ((functionBlock = function.getLastChild()) == null ||
154 (returnNode = functionBlock.getLastChild()) == null || 182 (returnNode = functionBlock.getLastChild()) == null ||
155 !returnNode.isReturn() || 183 !returnNode.isReturn() ||
(...skipping 30 matching lines...) Expand all
186 * 214 *
187 * <p><pre> 215 * <p><pre>
188 * var a = a || {}; 216 * var a = a || {};
189 * a.b = a.b || {}; 217 * a.b = a.b || {};
190 * a.b.c = a.b.c || {};</pre> 218 * a.b.c = a.b.c || {};</pre>
191 */ 219 */
192 private List<Node> createObjectsForQualifiedName(String namespace) { 220 private List<Node> createObjectsForQualifiedName(String namespace) {
193 List<Node> objects = new ArrayList<>(); 221 List<Node> objects = new ArrayList<>();
194 String[] parts = namespace.split("\\."); 222 String[] parts = namespace.split("\\.");
195 223
196 objects.add(createJsNode("var " + parts[0] + " = " + parts[0] + " || {}; ")); 224 createObjectIfNew(objects, parts[0], true);
197 225
198 if (parts.length >= 2) { 226 if (parts.length >= 2) {
199 StringBuilder currPrefix = new StringBuilder().append(parts[0]); 227 StringBuilder currPrefix = new StringBuilder().append(parts[0]);
200 for (int i = 1; i < parts.length; ++i) { 228 for (int i = 1; i < parts.length; ++i) {
201 currPrefix.append(".").append(parts[i]); 229 currPrefix.append(".").append(parts[i]);
202 String code = currPrefix + " = " + currPrefix + " || {};"; 230 createObjectIfNew(objects, currPrefix.toString(), false);
203 objects.add(createJsNode(code));
204 } 231 }
205 } 232 }
206 233
207 return objects; 234 return objects;
208 } 235 }
209 236
237 private void createObjectIfNew(List<Node> objects, String name, boolean need Var) {
238 if (!createdObjects.contains(name)) {
239 objects.add(createJsNode((needVar ? "var " : "") + name + " = " + na me + " || {};"));
240 createdObjects.add(name);
241 }
242 }
243
210 private Node createJsNode(String code) { 244 private Node createJsNode(String code) {
211 // The parent node after parseSyntheticCode() is SCRIPT node, we need to get rid of it. 245 // The parent node after parseSyntheticCode() is SCRIPT node, we need to get rid of it.
212 return compiler.parseSyntheticCode(code).removeFirstChild(); 246 return compiler.parseSyntheticCode(code).removeFirstChild();
213 } 247 }
214 248
215 private class RenameInternalsToExternalsCallback extends AbstractPostOrderCa llback { 249 private class RenameInternalsToExternalsCallback extends AbstractPostOrderCa llback {
216 final private String namespaceName; 250 final private String namespaceName;
217 final private Map<String, String> exports; 251 final private Map<String, String> exports;
218 final private Node namespaceBlock; 252 final private Node namespaceBlock;
219 253
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 } 330 }
297 331
298 private Node buildQualifiedName(Node internalName) { 332 private Node buildQualifiedName(Node internalName) {
299 String externalName = this.exports.get(internalName.getString()); 333 String externalName = this.exports.get(internalName.getString());
300 return NodeUtil.newQualifiedNameNode(compiler.getCodingConvention(), 334 return NodeUtil.newQualifiedNameNode(compiler.getCodingConvention(),
301 this.namespaceName + "." + externalName).srcrefTree(internal Name); 335 this.namespaceName + "." + externalName).srcrefTree(internal Name);
302 } 336 }
303 } 337 }
304 338
305 } 339 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698