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

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

Issue 557633002: Add public API generation with cr.makePublic() and handle it in compiler pass (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@H_options_errors_3
Patch Set: handle methods declared directly on prototype Created 6 years, 3 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;
(...skipping 19 matching lines...) Expand all
30 */ 30 */
31 public class ChromePass extends AbstractPostOrderCallback implements CompilerPas s { 31 public class ChromePass extends AbstractPostOrderCallback implements CompilerPas s {
32 final AbstractCompiler compiler; 32 final AbstractCompiler compiler;
33 33
34 private Set<String> createdObjects; 34 private Set<String> createdObjects;
35 35
36 private static final String CR_DEFINE = "cr.define"; 36 private static final String CR_DEFINE = "cr.define";
37 private static final String CR_EXPORT_PATH = "cr.exportPath"; 37 private static final String CR_EXPORT_PATH = "cr.exportPath";
38 private static final String OBJECT_DEFINE_PROPERTY = "Object.defineProperty" ; 38 private static final String OBJECT_DEFINE_PROPERTY = "Object.defineProperty" ;
39 private static final String CR_DEFINE_PROPERTY = "cr.defineProperty"; 39 private static final String CR_DEFINE_PROPERTY = "cr.defineProperty";
40 private static final String CR_MAKE_PUBLIC = "cr.makePublic";
40 41
41 private static final String CR_DEFINE_COMMON_EXPLANATION = "It should be cal led like this:" 42 private static final String CR_DEFINE_COMMON_EXPLANATION = "It should be cal led like this:"
42 + " cr.define('name.space', function() '{ ... return {Export: Intern al}; }');"; 43 + " cr.define('name.space', function() '{ ... return {Export: Intern al}; }');";
43 44
44 static final DiagnosticType CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS = 45 static final DiagnosticType CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS =
45 DiagnosticType.error("JSC_CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS", 46 DiagnosticType.error("JSC_CR_DEFINE_WRONG_NUMBER_OF_ARGUMENTS",
46 "cr.define() should have exactly 2 arguments. " + CR_DEFINE_ COMMON_EXPLANATION); 47 "cr.define() should have exactly 2 arguments. " + CR_DEFINE_ COMMON_EXPLANATION);
47 48
48 static final DiagnosticType CR_EXPORT_PATH_WRONG_NUMBER_OF_ARGUMENTS = 49 static final DiagnosticType CR_EXPORT_PATH_WRONG_NUMBER_OF_ARGUMENTS =
49 DiagnosticType.error("JSC_CR_EXPORT_PATH_WRONG_NUMBER_OF_ARGUMENTS", 50 DiagnosticType.error("JSC_CR_EXPORT_PATH_WRONG_NUMBER_OF_ARGUMENTS",
(...skipping 10 matching lines...) Expand all
60 static final DiagnosticType CR_DEFINE_INVALID_RETURN_IN_FUNCTION = 61 static final DiagnosticType CR_DEFINE_INVALID_RETURN_IN_FUNCTION =
61 DiagnosticType.error("JSC_CR_DEFINE_INVALID_RETURN_IN_SECOND_ARGUMEN T", 62 DiagnosticType.error("JSC_CR_DEFINE_INVALID_RETURN_IN_SECOND_ARGUMEN T",
62 "Function passed as second argument of cr.define() should re turn the" 63 "Function passed as second argument of cr.define() should re turn the"
63 + " dictionary in its last statement. " + CR_DEFINE_COMMON_E XPLANATION); 64 + " dictionary in its last statement. " + CR_DEFINE_COMMON_E XPLANATION);
64 65
65 static final DiagnosticType CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND = 66 static final DiagnosticType CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND =
66 DiagnosticType.error("JSC_CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND", 67 DiagnosticType.error("JSC_CR_DEFINE_PROPERTY_INVALID_PROPERTY_KIND",
67 "Invalid cr.PropertyKind passed to cr.defineProperty(): expe cted ATTR," 68 "Invalid cr.PropertyKind passed to cr.defineProperty(): expe cted ATTR,"
68 + " BOOL_ATTR or JS, found \"{0}\"."); 69 + " BOOL_ATTR or JS, found \"{0}\".");
69 70
71 static final DiagnosticType CR_MAKE_PUBLIC_HAS_NO_JSDOC =
72 DiagnosticType.error("JSC_CR_MAKE_PUBLIC_HAS_NO_JSDOC",
73 "Private method exported by cr.makePublic() has no JSDoc.");
74
75 static final DiagnosticType CR_MAKE_PUBLIC_MISSED_DECLARATION =
76 DiagnosticType.error("CR_MAKE_PUBLIC_MISSED_DECLARATION",
77 "Method \"{1}_\" exported by cr.makePublic() on \"{0}\" has no declaration.");
78
70 public ChromePass(AbstractCompiler compiler) { 79 public ChromePass(AbstractCompiler compiler) {
71 this.compiler = compiler; 80 this.compiler = compiler;
72 // The global variable "cr" is declared in ui/webui/resources/js/cr.js. 81 // The global variable "cr" is declared in ui/webui/resources/js/cr.js.
73 this.createdObjects = new HashSet<>(Arrays.asList("cr")); 82 this.createdObjects = new HashSet<>(Arrays.asList("cr"));
74 } 83 }
75 84
76 @Override 85 @Override
77 public void process(Node externs, Node root) { 86 public void process(Node externs, Node root) {
78 NodeTraversal.traverse(compiler, root, this); 87 NodeTraversal.traverse(compiler, root, this);
79 } 88 }
80 89
81 @Override 90 @Override
82 public void visit(NodeTraversal t, Node node, Node parent) { 91 public void visit(NodeTraversal t, Node node, Node parent) {
83 if (node.isCall()) { 92 if (node.isCall()) {
84 Node callee = node.getFirstChild(); 93 Node callee = node.getFirstChild();
85 if (callee.matchesQualifiedName(CR_DEFINE)) { 94 if (callee.matchesQualifiedName(CR_DEFINE)) {
86 visitNamespaceDefinition(node, parent); 95 visitNamespaceDefinition(node, parent);
87 compiler.reportCodeChange(); 96 compiler.reportCodeChange();
88 } else if (callee.matchesQualifiedName(CR_EXPORT_PATH)) { 97 } else if (callee.matchesQualifiedName(CR_EXPORT_PATH)) {
89 visitExportPath(node, parent); 98 visitExportPath(node, parent);
90 compiler.reportCodeChange(); 99 compiler.reportCodeChange();
91 } else if (callee.matchesQualifiedName(OBJECT_DEFINE_PROPERTY) || 100 } else if (callee.matchesQualifiedName(OBJECT_DEFINE_PROPERTY) ||
92 callee.matchesQualifiedName(CR_DEFINE_PROPERTY)) { 101 callee.matchesQualifiedName(CR_DEFINE_PROPERTY)) {
93 visitPropertyDefinition(node, parent); 102 visitPropertyDefinition(node, parent);
94 compiler.reportCodeChange(); 103 compiler.reportCodeChange();
104 } else if (callee.matchesQualifiedName(CR_MAKE_PUBLIC)) {
105 if (visitMakePublic(node, parent)) {
106 compiler.reportCodeChange();
107 }
95 } 108 }
96 } 109 }
97 } 110 }
98 111
99 private void visitPropertyDefinition(Node call, Node parent) { 112 private void visitPropertyDefinition(Node call, Node parent) {
100 Node callee = call.getFirstChild(); 113 Node callee = call.getFirstChild();
101 String target = call.getChildAtIndex(1).getQualifiedName(); 114 String target = call.getChildAtIndex(1).getQualifiedName();
102 if (callee.matchesQualifiedName(CR_DEFINE_PROPERTY) && !target.endsWith( ".prototype")) { 115 if (callee.matchesQualifiedName(CR_DEFINE_PROPERTY) && !target.endsWith( ".prototype")) {
103 target += ".prototype"; 116 target += ".prototype";
104 } 117 }
(...skipping 28 matching lines...) Expand all
133 propertyKind.getQualifiedName())); 146 propertyKind.getQualifiedName()));
134 return null; 147 return null;
135 } 148 }
136 149
137 private void setJsDocWithType(Node target, Node type) { 150 private void setJsDocWithType(Node target, Node type) {
138 JSDocInfoBuilder builder = new JSDocInfoBuilder(false); 151 JSDocInfoBuilder builder = new JSDocInfoBuilder(false);
139 builder.recordType(new JSTypeExpression(type, "")); 152 builder.recordType(new JSTypeExpression(type, ""));
140 target.setJSDocInfo(builder.build(target)); 153 target.setJSDocInfo(builder.build(target));
141 } 154 }
142 155
156 private boolean visitMakePublic(Node call, Node exprResult) {
157 boolean changesMade = false;
158 Node scope = exprResult.getParent();
159 String className = call.getChildAtIndex(1).getQualifiedName();
160 String prototype = className + ".prototype";
161 Node publicAPI = call.getChildAtIndex(2);
162
163 assert publicAPI != null && publicAPI.isArrayLit();
Tyler Breisacher (Chromium) 2014/09/09 19:34:45 This should probably report an error to the user,
Vitaly Pavlenko 2014/09/09 20:31:57 Done.
164
165 Set<String> publicAPIStrings = new HashSet<>();
166 for (Node methodName: publicAPI.children()) {
167 assert methodName.isString();
Tyler Breisacher (Chromium) 2014/09/09 19:34:45 Same here.
Vitaly Pavlenko 2014/09/09 20:31:57 Done.
168 publicAPIStrings.add(methodName.getString());
169 }
170
171 for (Node child: scope.children()) {
172 if (isAssignmentToPrototype(child, prototype)) {
173 Node objectLit = child.getFirstChild().getChildAtIndex(1);
174 for (Node stringKey : objectLit.children()) {
175 String field = stringKey.getString();
176 changesMade |= maybeAddPublicDeclaration(field, publicAPIStr ings, className,
177 stringKey, scope, e xprResult);
178 }
179 } else if (isAssignmentToPrototypeMethod(child, prototype)) {
180 Node assignNode = child.getFirstChild();
181 String qualifiedName = assignNode.getFirstChild().getQualifiedNa me();
182 String field = qualifiedName.substring(qualifiedName.lastIndexOf ('.') + 1);
183 changesMade |= maybeAddPublicDeclaration(field, publicAPIStrings , className,
184 assignNode, scope, expr Result);
185 }
186 }
187
188 for (String missedDeclaration : publicAPIStrings) {
189 compiler.report(JSError.make(exprResult, CR_MAKE_PUBLIC_MISSED_DECLA RATION, className,
190 missedDeclaration));
191 }
192
193 return changesMade;
194 }
195
196 private boolean isAssignmentToPrototype(Node node, String prototype) {
197 Node assignNode;
198 return node.isExprResult() && (assignNode = node.getFirstChild()).isAssi gn() &&
199 assignNode.getFirstChild().getQualifiedName().equals(prototype);
200 }
201
202 private boolean isAssignmentToPrototypeMethod(Node node, String prototype) {
203 Node assignNode;
204 return node.isExprResult() && (assignNode = node.getFirstChild()).isAssi gn() &&
205 assignNode.getFirstChild().getQualifiedName().startsWith(prototy pe + ".");
206 }
207
208 private boolean maybeAddPublicDeclaration(String field, Set<String> publicAP IStrings,
209 String className, Node JSDocSourceNode, Node scope, Node exprResult) {
210 boolean changesMade = false;
211 if (field.endsWith("_")) {
212 String publicName = field.substring(0, field.length() - 1);
213 if (publicAPIStrings.contains(publicName)) {
214 Node methodDeclaration = NodeUtil.newQualifiedNameNode(
215 compiler.getCodingConvention(), className + "." + public Name);
216 if (JSDocSourceNode.getJSDocInfo() != null) {
217 methodDeclaration.setJSDocInfo(JSDocSourceNode.getJSDocInfo( ));
218 scope.addChildBefore(
219 IR.exprResult(methodDeclaration).srcrefTree(exprResu lt),
220 exprResult);
221 changesMade = true;
222 } else {
223 compiler.report(JSError.make(JSDocSourceNode, CR_MAKE_PUBLIC _HAS_NO_JSDOC));
224 }
225 publicAPIStrings.remove(publicName);
226 }
227 }
228 return changesMade;
229 }
230
143 private void visitExportPath(Node crExportPathNode, Node parent) { 231 private void visitExportPath(Node crExportPathNode, Node parent) {
144 if (crExportPathNode.getChildCount() != 2) { 232 if (crExportPathNode.getChildCount() != 2) {
145 compiler.report(JSError.make(crExportPathNode, 233 compiler.report(JSError.make(crExportPathNode,
146 CR_EXPORT_PATH_WRONG_NUMBER_OF_ARGUMENTS)); 234 CR_EXPORT_PATH_WRONG_NUMBER_OF_ARGUMENTS));
147 return; 235 return;
148 } 236 }
149 237
150 createAndInsertObjectsForQualifiedName(parent, 238 createAndInsertObjectsForQualifiedName(parent,
151 crExportPathNode.getChildAtIndex(1).getString()); 239 crExportPathNode.getChildAtIndex(1).getString());
152 } 240 }
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 } 423 }
336 } 424 }
337 } 425 }
338 426
339 private Node buildQualifiedName(Node internalName) { 427 private Node buildQualifiedName(Node internalName) {
340 String externalName = this.exports.get(internalName.getString()); 428 String externalName = this.exports.get(internalName.getString());
341 return NodeUtil.newQualifiedNameNode(compiler.getCodingConvention(), 429 return NodeUtil.newQualifiedNameNode(compiler.getCodingConvention(),
342 this.namespaceName + "." + externalName).srcrefTree(internal Name); 430 this.namespaceName + "." + externalName).srcrefTree(internal Name);
343 } 431 }
344 } 432 }
345
346 } 433 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698