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

Side by Side Diff: pkg/analyzer2dart/lib/src/tree_shaker.dart

Issue 611153003: Propertly tree shake factory constructors. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/analyzer2dart/test/tree_shaker_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library analyzer2dart.treeShaker; 5 library analyzer2dart.treeShaker;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import 'package:analyzer/analyzer.dart'; 9 import 'package:analyzer/analyzer.dart';
10 import 'package:analyzer/src/generated/element.dart'; 10 import 'package:analyzer/src/generated/element.dart';
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 68
69 /** 69 /**
70 * This class is responsible for performing local analysis of the source code 70 * This class is responsible for performing local analysis of the source code
71 * to provide the information needed to do tree shaking. 71 * to provide the information needed to do tree shaking.
72 */ 72 */
73 class LocalReachabilityComputer { 73 class LocalReachabilityComputer {
74 /** 74 /**
75 * Perform local reachability analysis of [method]. 75 * Perform local reachability analysis of [method].
76 */ 76 */
77 MethodAnalysis analyzeMethod(ExecutableElement method) { 77 MethodAnalysis analyzeMethod(ExecutableElement method) {
78 MethodAnalysis analysis = new MethodAnalysis(method.node); 78 Declaration declaration = method.node;
79 analysis.declaration.accept(new TreeShakingVisitor(analysis)); 79 MethodAnalysis analysis = new MethodAnalysis(declaration);
80 if (declaration != null) {
81 declaration.accept(new TreeShakingVisitor(analysis));
82 } else if (method is ConstructorElement) {
83 // This constructor has no associated declaration in the AST. Either it
84 // is a default constructor for an ordinary class, or it's a synthetic
85 // constructor associated with a mixin. For now we assume it's a default
86 // constructor, in which case all we need to do is record the class as
87 // being instantiated by this method. TODO(paulberry): handle the
88 // mixin case.
89 analysis.instantiates.add(method.enclosingElement);
90 } else {
91 // This is an executable element with no associated declaration in the
92 // AST, and it's not a constructor. TODO(paulberry): can this ever
93 // happen?
94 throw new UnimplementedError();
95 }
80 return analysis; 96 return analysis;
81 } 97 }
82 98
83 /** 99 /**
84 * Perform local reachability analysis of [classElement]. 100 * Perform local reachability analysis of [classElement].
85 */ 101 */
86 ClassAnalysis analyzeClass(ClassElement classElement) { 102 ClassAnalysis analyzeClass(ClassElement classElement) {
87 return new ClassAnalysis(classElement.node); 103 return new ClassAnalysis(classElement.node);
88 } 104 }
89 105
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 * and performing the global inferences necessary to determine which methods 146 * and performing the global inferences necessary to determine which methods
131 * in the source program are reachable. It makes use of 147 * in the source program are reachable. It makes use of
132 * [LocalReachabilityComputer] to do local analysis of individual classes and 148 * [LocalReachabilityComputer] to do local analysis of individual classes and
133 * methods. 149 * methods.
134 */ 150 */
135 class TreeShaker { 151 class TreeShaker {
136 List<Element> _queue = <Element>[]; 152 List<Element> _queue = <Element>[];
137 Set<Element> _alreadyEnqueued = new HashSet<Element>(); 153 Set<Element> _alreadyEnqueued = new HashSet<Element>();
138 ClosedWorld _world; 154 ClosedWorld _world;
139 Set<Selector> _selectors = new HashSet<Selector>(); 155 Set<Selector> _selectors = new HashSet<Selector>();
140 final LocalReachabilityComputer _localComputer = new LocalReachabilityComputer (); 156 final LocalReachabilityComputer _localComputer =
157 new LocalReachabilityComputer();
141 158
142 TreeShaker(FunctionElement mainFunction) 159 TreeShaker(FunctionElement mainFunction)
143 : _world = new ClosedWorld(mainFunction); 160 : _world = new ClosedWorld(mainFunction);
144 161
145 void _addElement(Element element) { 162 void _addElement(Element element) {
146 if (_alreadyEnqueued.add(element)) { 163 if (_alreadyEnqueued.add(element)) {
147 _queue.add(element); 164 _queue.add(element);
148 } 165 }
149 } 166 }
150 167
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 } 209 }
193 } else if (element is FieldElement) { 210 } else if (element is FieldElement) {
194 VariableDeclaration declaration = element.node; 211 VariableDeclaration declaration = element.node;
195 _world.fields[element] = declaration; 212 _world.fields[element] = declaration;
196 } else if (element is TopLevelVariableElement) { 213 } else if (element is TopLevelVariableElement) {
197 VariableDeclaration declaration = element.node; 214 VariableDeclaration declaration = element.node;
198 _world.variables[element] = declaration; 215 _world.variables[element] = declaration;
199 } else { 216 } else {
200 throw new Exception( 217 throw new Exception(
201 'Unexpected element type while tree shaking: ' 218 'Unexpected element type while tree shaking: '
202 '$element (${element.runtimeType})'); 219 '$element (${element.runtimeType})');
203 } 220 }
204 } 221 }
205 print('Tree shaking done'); 222 print('Tree shaking done');
206 return _world; 223 return _world;
207 } 224 }
208 } 225 }
209 226
210 class TreeShakingVisitor extends SemanticVisitor { 227 class TreeShakingVisitor extends SemanticVisitor {
211 final MethodAnalysis analysis; 228 final MethodAnalysis analysis;
212 229
213 TreeShakingVisitor(this.analysis); 230 TreeShakingVisitor(this.analysis);
214 231
215 Source get currentSource => analysis.declaration.element.source; 232 Source get currentSource => analysis.declaration.element.source;
216 233
217 @override 234 @override
218 void visitInstanceCreationExpression(InstanceCreationExpression node) { 235 void visitInstanceCreationExpression(InstanceCreationExpression node) {
219 ConstructorElement staticElement = node.staticElement; 236 ConstructorElement staticElement = node.staticElement;
220 if (staticElement != null) { 237 if (staticElement != null) {
221 // TODO(paulberry): Really we should enqueue the constructor, and then 238 analysis.calls.add(staticElement);
222 // when we visit it add the class to the class bucket.
223 ClassElement classElement = staticElement.enclosingElement;
224 analysis.instantiates.add(classElement);
225 } else { 239 } else {
226 // TODO(paulberry): deal with this situation. This can happen, for 240 // TODO(paulberry): deal with this situation. This can happen, for
227 // example, in the case "main() => new Unresolved();" (which is a 241 // example, in the case "main() => new Unresolved();" (which is a
228 // warning, not an error). 242 // warning, not an error).
229 } 243 }
230 super.visitInstanceCreationExpression(node); 244 super.visitInstanceCreationExpression(node);
231 } 245 }
232 246
233 @override 247 @override
234 void visitDynamicInvocation(MethodInvocation node, 248 void visitDynamicInvocation(MethodInvocation node,
235 AccessSemantics semantics) { 249 AccessSemantics semantics) {
236 analysis.invokes.add( 250 analysis.invokes.add(
237 createSelectorFromMethodInvocation(node, node.methodName.name)); 251 createSelectorFromMethodInvocation(node, node.methodName.name));
238 } 252 }
239 253
240 @override 254 @override
241 void visitLocalFunctionInvocation(MethodInvocation node, 255 void visitLocalFunctionInvocation(MethodInvocation node,
242 AccessSemantics semantics) { 256 AccessSemantics semantics) {
243 // Locals don't need to be tree shaken. 257 // Locals don't need to be tree shaken.
244 } 258 }
245 259
246 @override 260 @override
247 void visitLocalVariableInvocation(MethodInvocation node, 261 void visitLocalVariableInvocation(MethodInvocation node,
248 AccessSemantics semantics) { 262 AccessSemantics semantics) {
249 // Locals don't need to be tree shaken. 263 // Locals don't need to be tree shaken.
250 } 264 }
251 265
252 @override 266 @override
253 void visitParameterInvocation(MethodInvocation node, 267 void visitParameterInvocation(MethodInvocation node,
254 AccessSemantics semantics) { 268 AccessSemantics semantics) {
255 // Locals don't need to be tree shaken. 269 // Locals don't need to be tree shaken.
256 } 270 }
257 271
258 @override 272 @override
259 void visitStaticFieldInvocation(MethodInvocation node, 273 void visitStaticFieldInvocation(MethodInvocation node,
260 AccessSemantics semantics) { 274 AccessSemantics semantics) {
261 // Invocation of a static field. 275 // Invocation of a static field.
262 analysis.accesses.add(semantics.element); 276 analysis.accesses.add(semantics.element);
263 analysis.invokes.add( 277 analysis.invokes.add(createSelectorFromMethodInvocation(node, 'call'));
264 createSelectorFromMethodInvocation(node, 'call'));
265 } 278 }
266 279
267 void visitStaticMethodInvocation(MethodInvocation node, 280 void visitStaticMethodInvocation(MethodInvocation node,
268 AccessSemantics semantics) { 281 AccessSemantics semantics) {
269 analysis.calls.add(semantics.element); 282 analysis.calls.add(semantics.element);
270 } 283 }
271 284
272 void visitStaticPropertyInvocation(MethodInvocation node, 285 void visitStaticPropertyInvocation(MethodInvocation node,
273 AccessSemantics semantics) { 286 AccessSemantics semantics) {
274 // Invocation of a property. TODO(paulberry): handle this. 287 // Invocation of a property. TODO(paulberry): handle this.
275 super.visitStaticPropertyInvocation(node, semantics); 288 super.visitStaticPropertyInvocation(node, semantics);
276 } 289 }
277 290
278 void visitDynamicAccess(AstNode node, AccessSemantics semantics) { 291 void visitDynamicAccess(AstNode node, AccessSemantics semantics) {
279 if (semantics.isRead) { 292 if (semantics.isRead) {
280 analysis.invokes.add( 293 analysis.invokes.add(
281 new Selector.getter(semantics.identifier.name, null)); 294 new Selector.getter(semantics.identifier.name, null));
282 } 295 }
283 if (semantics.isWrite) { 296 if (semantics.isWrite) {
(...skipping 20 matching lines...) Expand all
304 317
305 void visitStaticMethodAccess(AstNode node, AccessSemantics semantics) { 318 void visitStaticMethodAccess(AstNode node, AccessSemantics semantics) {
306 // Method tear-off. TODO(paulberry): implement. 319 // Method tear-off. TODO(paulberry): implement.
307 super.visitStaticMethodAccess(node, semantics); 320 super.visitStaticMethodAccess(node, semantics);
308 } 321 }
309 322
310 void visitStaticPropertyAccess(AstNode node, AccessSemantics semantics) { 323 void visitStaticPropertyAccess(AstNode node, AccessSemantics semantics) {
311 // TODO(paulberry): implement. 324 // TODO(paulberry): implement.
312 super.visitStaticPropertyAccess(node, semantics); 325 super.visitStaticPropertyAccess(node, semantics);
313 } 326 }
327
328 @override
329 void visitConstructorDeclaration(ConstructorDeclaration node) {
Johnni Winther 2014/10/03 08:03:06 Currently we only mark classes as instantiated but
Paul Berry 2014/10/03 15:50:45 Ok. Currently I am only keeping track of what's b
330 // TODO(paulberry): handle parameter list.
331 node.initializers.accept(this);
332 node.body.accept(this);
333 if (node.factoryKeyword == null) {
334 // This is a generative constructor. Figure out if it is redirecting.
335 // If it isn't, then the constructor instantiates the class so we need to
336 // add the class to analysis.instantiates. (If it is redirecting, then
337 // we don't need to, because the redirected-to constructor will take care
338 // of that).
339 if (node.initializers.length != 1 || node.initializers[0] is! RedirectingC onstructorInvocation) {
340 analysis.instantiates.add(node.element.enclosingElement);
341 }
342 } else if (node.redirectedConstructor != null) {
343 if (node.redirectedConstructor.staticElement == null) {
344 // Factory constructor redirects to a non-existent constructor.
345 // TODO(paulberry): handle this.
346 throw new UnimplementedError();
347 } else {
348 analysis.calls.add(node.redirectedConstructor.staticElement);
349 }
350 }
351 }
352
353 @override
354 void
355 visitRedirectingConstructorInvocation(RedirectingConstructorInvocation nod e) {
356 // Note: we don't have to worry about node.staticElement being
357 // null, because that would have been detected by the analyzer and
358 // reported as a compile time error.
359 analysis.calls.add(node.staticElement);
360 }
314 } 361 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer2dart/test/tree_shaker_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698