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

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: Comment fix 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 | 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';
Johnni Winther 2014/09/25 12:09:36 What is the motivation for using a package and not
Paul Berry 2014/09/25 18:22:48 Hmm, I hadn't actually given it much thought. Thi
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 AccessSemantics semantics = classifyMethodInvocation(node);
248 // dynamic x; 236 switch (semantics.kind) {
249 // x.foo(); 237 case AccessKind.DYNAMIC:
250 handleMethodCall(node); 238 analysis.invokes.add(createSelectorFromMethodInvocation(node));
251 } else { 239 break;
252 // Calling a toplevel function which has no known element, e.g. 240 case AccessKind.LOCAL_FUNCTION:
253 // main() { 241 case AccessKind.LOCAL_VARIABLE:
254 // foo(); 242 case AccessKind.PARAMETER:
255 // } 243 // Locals don't need to be tree shaken.
256 // TODO(paulberry): deal with this case. May need to notify the back 244 break;
257 // end in case this makes it want to drag in some helper code. 245 case AccessKind.STATIC_FIELD:
246 // Invocation of a field. TODO(paulberry): handle this.
258 throw new UnimplementedError(); 247 throw new UnimplementedError();
259 } 248 case AccessKind.STATIC_METHOD:
260 } else if (staticElement is MethodElement) { 249 analysis.calls.add(semantics.element);
261 // Invoking a method, e.g.: 250 break;
262 // class A { 251 case AccessKind.STATIC_PROPERTY:
263 // f() {} 252 // Invocation of a property. TODO(paulberry): handle this.
264 // } 253 throw new UnimplementedError();
265 // main() { 254 default:
266 // new A().f(); 255 // Unexpected access kind.
267 // } 256 throw new UnimplementedError();
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();
329 } 257 }
330 // TODO(paulberry): I believe all the other possibilities are errors, but
331 // we should double check.
332 } 258 }
333 259
334 @override 260 @override
335 void visitPropertyAccess(PropertyAccess node) { 261 void visitPropertyAccess(PropertyAccess node) {
336 // Accessing a getter or setter, e.g.: 262 if (node.target != null) {
337 // class A { 263 node.target.accept(this);
338 // get g() => ...; 264 }
339 // } 265 _handlePropertyAccess(classifyPropertyAccess(node));
340 // main() { 266 }
341 // new A().g; 267
342 // } 268 @override
343 // TODO(paulberry): do setters go through this path as well? 269 visitPrefixedIdentifier(PrefixedIdentifier node) {
344 // TODO(paulberry): handle cases where the property access is represented 270 node.prefix.accept(this);
345 // as a PrefixedIdentifier. 271 _handlePropertyAccess(classifyPrefixedIdentifier(node));
346 super.visitPropertyAccess(node); 272 }
347 analysis.invokes.add(new Selector.getter(node.propertyName.name, null)); 273
274 @override
275 visitSimpleIdentifier(SimpleIdentifier node) {
276 AccessSemantics semantics = classifyBareIdentifier(node);
277 if (semantics != null) {
278 _handlePropertyAccess(semantics);
279 }
280 }
281
282 void _handlePropertyAccess(AccessSemantics semantics) {
283 switch (semantics.kind) {
284 case AccessKind.DYNAMIC:
285 if (semantics.isRead) {
286 analysis.invokes.add(
287 new Selector.getter(semantics.identifier.name, null));
288 }
289 if (semantics.isWrite) {
290 // TODO(paulberry): implement.
291 throw new UnimplementedError();
292 }
293 break;
294 case AccessKind.LOCAL_FUNCTION:
295 case AccessKind.LOCAL_VARIABLE:
296 case AccessKind.PARAMETER:
297 // Locals don't need to be tree shaken.
298 break;
299 case AccessKind.STATIC_FIELD:
300 // TODO(paulberry): implement.
301 throw new UnimplementedError();
302 case AccessKind.STATIC_METHOD:
303 // Method tear-off. TODO(paulberry): implement.
304 break;
305 case AccessKind.STATIC_PROPERTY:
306 // TODO(paulberry): implement.
307 throw new UnimplementedError();
308 default:
309 // Unexpected access kind.
310 throw new UnimplementedError();
311 }
348 } 312 }
349 } 313 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698