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

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

Issue 587323004: Classify method and property accesses semantically. (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
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';
11 import 'package:compiler/implementation/universe/universe.dart'; 11 import 'package:compiler/implementation/universe/universe.dart';
12 12
13 import 'closed_world.dart'; 13 import 'closed_world.dart';
14 import 'package:analyzer2dart/src/identifier_semantics.dart';
14 15
15 /** 16 /**
16 * The result of performing local reachability analysis on a method. 17 * The result of performing local reachability analysis on a method.
17 */ 18 */
18 class MethodAnalysis { 19 class MethodAnalysis {
19 /** 20 /**
20 * The AST for the method. 21 * The AST for the method.
21 */ 22 */
22 final Declaration declaration; 23 final Declaration declaration;
23 24
24 /** 25 /**
25 * The functions statically called by the method. 26 * The functions statically called by the method.
26 */ 27 */
27 final List<LocalElement> calls = <LocalElement>[]; 28 final List<ExecutableElement> calls = <ExecutableElement>[];
28 29
29 /** 30 /**
30 * The selectors used by the method to perform dynamic invocation. 31 * The selectors used by the method to perform dynamic invocation.
31 */ 32 */
32 final List<Selector> invokes = <Selector>[]; 33 final List<Selector> invokes = <Selector>[];
33 34
34 /** 35 /**
35 * The classes that are instantiated by the method. 36 * The classes that are instantiated by the method.
36 */ 37 */
37 final List<ClassElement> instantiates = <ClassElement>[]; 38 final List<ClassElement> instantiates = <ClassElement>[];
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 } 203 }
203 } 204 }
204 return new Selector.call(node.methodName.name, null, arity, namedArguments); 205 return new Selector.call(node.methodName.name, null, arity, namedArguments);
205 } 206 }
206 207
207 class TreeShakingVisitor extends RecursiveAstVisitor { 208 class TreeShakingVisitor extends RecursiveAstVisitor {
208 final MethodAnalysis analysis; 209 final MethodAnalysis analysis;
209 210
210 TreeShakingVisitor(this.analysis); 211 TreeShakingVisitor(this.analysis);
211 212
212 /**
213 * Handle a true method call (a MethodInvocation that represents a call to
214 * a non-static method).
215 */
216 void handleMethodCall(MethodInvocation node) {
217 analysis.invokes.add(createSelectorFromMethodInvocation(node));
218 }
219
220 @override
221 void visitFunctionDeclaration(FunctionDeclaration node) {
222 super.visitFunctionDeclaration(node);
223 }
224
225 @override 213 @override
226 void visitInstanceCreationExpression(InstanceCreationExpression node) { 214 void visitInstanceCreationExpression(InstanceCreationExpression node) {
227 ConstructorElement staticElement = node.staticElement; 215 ConstructorElement staticElement = node.staticElement;
228 if (staticElement != null) { 216 if (staticElement != null) {
229 // TODO(paulberry): Really we should enqueue the constructor, and then 217 // TODO(paulberry): Really we should enqueue the constructor, and then
230 // when we visit it add the class to the class bucket. 218 // when we visit it add the class to the class bucket.
231 ClassElement classElement = staticElement.enclosingElement; 219 ClassElement classElement = staticElement.enclosingElement;
232 analysis.instantiates.add(classElement); 220 analysis.instantiates.add(classElement);
233 } else { 221 } else {
234 // TODO(paulberry): deal with this situation. This can happen, for 222 // TODO(paulberry): deal with this situation. This can happen, for
235 // example, in the case "main() => new Unresolved();" (which is a 223 // example, in the case "main() => new Unresolved();" (which is a
236 // warning, not an error). 224 // warning, not an error).
237 } 225 }
238 super.visitInstanceCreationExpression(node); 226 super.visitInstanceCreationExpression(node);
239 } 227 }
240 228
241 @override 229 @override
242 void visitMethodInvocation(MethodInvocation node) { 230 void visitMethodInvocation(MethodInvocation node) {
243 super.visitMethodInvocation(node); 231 if (node.target != null) {
244 Element staticElement = node.methodName.staticElement; 232 node.target.accept(this);
245 if (staticElement == null) { 233 }
246 if (node.realTarget != null) { 234 node.argumentList.accept(this);
247 // Calling a method that has no known element, e.g.: 235 MethodInvocationSemantics semantics = classifyMethodInvocation(node);
248 // dynamic x; 236 if (semantics is StaticMethodInvocation) {
249 // x.foo(); 237 analysis.calls.add(semantics.methodElement);
250 handleMethodCall(node); 238 } else if (semantics is LocalFunctionInvocation) {
251 } else { 239 // Tree shaking doesn't need to deal with local functions.
252 // Calling a toplevel function which has no known element, e.g. 240 } else if (semantics is DynamicMethodInvocation) {
253 // main() { 241 analysis.invokes.add(createSelectorFromMethodInvocation(node));
254 // foo(); 242 } else {
255 // } 243 // Unexpected method invocation semantics.
256 // TODO(paulberry): deal with this case. May need to notify the back
257 // end in case this makes it want to drag in some helper code.
258 throw new UnimplementedError();
259 }
260 } else if (staticElement is MethodElement) {
261 // Invoking a method, e.g.:
262 // class A {
263 // f() {}
264 // }
265 // main() {
266 // new A().f();
267 // }
268 // or via implicit this, i.e.:
269 // class A {
270 // f() {}
271 // foo() {
272 // f();
273 // }
274 // }
275 // TODO(paulberry): if user-provided types are wrong, this may actually
276 // be the PropertyAccessorElement case.
277 // TODO(paulberry): do we need to do something different for static
278 // methods?
279 handleMethodCall(node);
280 } else if (staticElement is PropertyAccessorElement) {
281 // Invoking a callable getter, e.g.:
282 // typedef FunctionType();
283 // class A {
284 // FunctionType get f { ... }
285 // }
286 // main() {
287 // new A().f();
288 // }
289 // or via implicit this, i.e.:
290 // typedef FunctionType();
291 // class A {
292 // FunctionType get f { ... }
293 // foo() {
294 // f();
295 // }
296 // }
297 // This also covers the case where the getter is synthetic, because we
298 // are getting a field (TODO(paulberry): verify that this is the case).
299 // TODO(paulberry): deal with this case.
300 // TODO(paulberry): if user-provided types are wrong, this may actually
301 // be the MethodElement case.
302 throw new UnimplementedError();
303 } else if (staticElement is MultiplyInheritedExecutableElement) {
304 // TODO(paulberry): deal with this case.
305 throw new UnimplementedError();
306 } else if (staticElement is LocalElement) {
307 // Invoking a callable local, e.g.:
308 // typedef FunctionType();
309 // main() {
310 // FunctionType f = ...;
311 // f();
312 // }
313 // or:
314 // main() {
315 // f() { ... }
316 // f();
317 // }
318 // or:
319 // f() {}
320 // main() {
321 // f();
322 // }
323 // TODO(paulberry): for the moment we are assuming it's a toplevel
324 // function.
325 analysis.calls.add(staticElement);
326 } else if (staticElement is MultiplyDefinedElement) {
327 // TODO(paulberry): do we have to deal with this case?
328 throw new UnimplementedError(); 244 throw new UnimplementedError();
329 } 245 }
330 // TODO(paulberry): I believe all the other possibilities are errors, but
331 // we should double check.
332 } 246 }
333 247
334 @override 248 @override
335 void visitPropertyAccess(PropertyAccess node) { 249 void visitPropertyAccess(PropertyAccess node) {
336 // Accessing a getter or setter, e.g.: 250 if (node.target != null) {
337 // class A { 251 node.target.accept(this);
338 // get g() => ...; 252 }
339 // } 253 _handlePropertyAccess(classifyPropertyAccess(node));
340 // main() { 254 }
341 // new A().g; 255
342 // } 256 @override
343 // TODO(paulberry): do setters go through this path as well? 257 visitPrefixedIdentifier(PrefixedIdentifier node) {
344 // TODO(paulberry): handle cases where the property access is represented 258 node.prefix.accept(this);
345 // as a PrefixedIdentifier. 259 _handlePropertyAccess(classifyPrefixedIdentifier(node));
346 super.visitPropertyAccess(node); 260 }
347 analysis.invokes.add(new Selector.getter(node.propertyName.name, null)); 261
262 @override
263 visitSimpleIdentifier(SimpleIdentifier node) {
264 AccessSemantics semantics = classifyBareIdentifier(node);
265 if (semantics != null) {
266 _handlePropertyAccess(semantics);
267 }
268 }
269
270 void _handlePropertyAccess(AccessSemantics semantics) {
271 if (semantics is StaticFieldAccess) {
272 // TODO(paulberry): implement.
273 throw new UnimplementedError();
274 } else if (semantics is StaticPropertyAccess) {
275 // TODO(paulberry): implement.
276 throw new UnimplementedError();
277 } else if (semantics is DynamicPropertyAccess) {
278 if (semantics.isRead) {
279 analysis.invokes.add(
280 new Selector.getter(semantics.propertyName.name, null));
281 }
282 if (semantics.isWrite) {
283 // TODO(paulberry): implement.
284 throw new UnimplementedError();
285 }
286 } else if (semantics is LocalVariableAccess) {
287 // Tree shaking doesn't need to deal with local variables.
288 } else {
289 // Unexpected property access semantics.
290 }
348 } 291 }
349 } 292 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698