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

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

Issue 609783002: Support static field access in analyzer2dart. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Updated cf. comments. 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 | « pkg/analyzer2dart/lib/src/semantic_visitor.dart ('k') | pkg/analyzer2dart/lib/src/util.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';
11 import 'package:analyzer/src/generated/source.dart';
11 import 'package:compiler/implementation/universe/universe.dart'; 12 import 'package:compiler/implementation/universe/universe.dart';
12 13
13 import 'closed_world.dart'; 14 import 'closed_world.dart';
15 import 'util.dart';
16 import 'semantic_visitor.dart';
14 import 'package:analyzer2dart/src/identifier_semantics.dart'; 17 import 'package:analyzer2dart/src/identifier_semantics.dart';
15 18
16 /** 19 /**
17 * The result of performing local reachability analysis on a method. 20 * The result of performing local reachability analysis on a method.
18 */ 21 */
19 class MethodAnalysis { 22 class MethodAnalysis {
20 /** 23 /**
21 * The AST for the method. 24 * The AST for the method.
22 */ 25 */
23 final Declaration declaration; 26 final Declaration declaration;
24 27
25 /** 28 /**
26 * The functions statically called by the method. 29 * The functions statically called by the method.
27 */ 30 */
28 final List<ExecutableElement> calls = <ExecutableElement>[]; 31 final List<ExecutableElement> calls = <ExecutableElement>[];
29 32
30 /** 33 /**
34 * The fields and top-level variables statically accessed by the method.
35 */
36 // TODO(johnniwinther): Should we split this into reads and writes?
37 final List<PropertyInducingElement> accesses = <PropertyInducingElement>[];
38
39 /**
31 * The selectors used by the method to perform dynamic invocation. 40 * The selectors used by the method to perform dynamic invocation.
32 */ 41 */
33 final List<Selector> invokes = <Selector>[]; 42 final List<Selector> invokes = <Selector>[];
34 43
35 /** 44 /**
36 * The classes that are instantiated by the method. 45 * The classes that are instantiated by the method.
37 */ 46 */
38 final List<ClassElement> instantiates = <ClassElement>[]; 47 final List<ClassElement> instantiates = <ClassElement>[];
39 48
40 MethodAnalysis(this.declaration); 49 MethodAnalysis(this.declaration);
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 _addElement(_world.mainFunction); 176 _addElement(_world.mainFunction);
168 while (_queue.isNotEmpty) { 177 while (_queue.isNotEmpty) {
169 Element element = _queue.removeLast(); 178 Element element = _queue.removeLast();
170 print('Tree shaker handling $element'); 179 print('Tree shaker handling $element');
171 if (element is ExecutableElement) { 180 if (element is ExecutableElement) {
172 MethodAnalysis analysis = _localComputer.analyzeMethod(element); 181 MethodAnalysis analysis = _localComputer.analyzeMethod(element);
173 _world.executableElements[element] = analysis.declaration; 182 _world.executableElements[element] = analysis.declaration;
174 analysis.calls.forEach(_addElement); 183 analysis.calls.forEach(_addElement);
175 analysis.invokes.forEach(_addSelector); 184 analysis.invokes.forEach(_addSelector);
176 analysis.instantiates.forEach(_addElement); 185 analysis.instantiates.forEach(_addElement);
186 analysis.accesses.forEach(_addElement);
177 } else if (element is ClassElement) { 187 } else if (element is ClassElement) {
178 ClassAnalysis analysis = _localComputer.analyzeClass(element); 188 ClassAnalysis analysis = _localComputer.analyzeClass(element);
179 _world.instantiatedClasses[element] = analysis.declaration; 189 _world.instantiatedClasses[element] = analysis.declaration;
180 for (Selector selector in _selectors) { 190 for (Selector selector in _selectors) {
181 _matchClassToSelector(element, selector); 191 _matchClassToSelector(element, selector);
182 } 192 }
183 } else if (element is FieldElement) { 193 } else if (element is FieldElement) {
184 VariableDeclaration declaration = element.node; 194 VariableDeclaration declaration = element.node;
185 _world.fields[element] = declaration; 195 _world.fields[element] = declaration;
196 } else if (element is TopLevelVariableElement) {
197 VariableDeclaration declaration = element.node;
198 _world.variables[element] = declaration;
186 } else { 199 } else {
187 throw new Exception('Unexpected element type while tree shaking'); 200 throw new Exception(
201 'Unexpected element type while tree shaking: '
202 '$element (${element.runtimeType})');
188 } 203 }
189 } 204 }
190 print('Tree shaking done'); 205 print('Tree shaking done');
191 return _world; 206 return _world;
192 } 207 }
193 } 208 }
194 209
195 Selector createSelectorFromMethodInvocation(MethodInvocation node) { 210 class TreeShakingVisitor extends SemanticVisitor {
196 int arity = 0;
197 List<String> namedArguments = <String>[];
198 for (var x in node.argumentList.arguments) {
199 if (x is NamedExpression) {
200 namedArguments.add(x.name.label.name);
201 } else {
202 arity++;
203 }
204 }
205 return new Selector.call(node.methodName.name, null, arity, namedArguments);
206 }
207
208 class TreeShakingVisitor extends RecursiveAstVisitor {
209 final MethodAnalysis analysis; 211 final MethodAnalysis analysis;
210 212
211 TreeShakingVisitor(this.analysis); 213 TreeShakingVisitor(this.analysis);
212 214
215 Source get currentSource => analysis.declaration.element.source;
216
213 @override 217 @override
214 void visitInstanceCreationExpression(InstanceCreationExpression node) { 218 void visitInstanceCreationExpression(InstanceCreationExpression node) {
215 ConstructorElement staticElement = node.staticElement; 219 ConstructorElement staticElement = node.staticElement;
216 if (staticElement != null) { 220 if (staticElement != null) {
217 // TODO(paulberry): Really we should enqueue the constructor, and then 221 // TODO(paulberry): Really we should enqueue the constructor, and then
218 // when we visit it add the class to the class bucket. 222 // when we visit it add the class to the class bucket.
219 ClassElement classElement = staticElement.enclosingElement; 223 ClassElement classElement = staticElement.enclosingElement;
220 analysis.instantiates.add(classElement); 224 analysis.instantiates.add(classElement);
221 } else { 225 } else {
222 // TODO(paulberry): deal with this situation. This can happen, for 226 // TODO(paulberry): deal with this situation. This can happen, for
223 // example, in the case "main() => new Unresolved();" (which is a 227 // example, in the case "main() => new Unresolved();" (which is a
224 // warning, not an error). 228 // warning, not an error).
225 } 229 }
226 super.visitInstanceCreationExpression(node); 230 super.visitInstanceCreationExpression(node);
227 } 231 }
228 232
229 @override 233 @override
230 void visitMethodInvocation(MethodInvocation node) { 234 void visitDynamicInvocation(MethodInvocation node,
231 if (node.target != null) { 235 AccessSemantics semantics) {
232 node.target.accept(this); 236 analysis.invokes.add(
237 createSelectorFromMethodInvocation(node, node.methodName.name));
238 }
239
240 @override
241 void visitLocalFunctionInvocation(MethodInvocation node,
242 AccessSemantics semantics) {
243 // Locals don't need to be tree shaken.
244 }
245
246 @override
247 void visitLocalVariableInvocation(MethodInvocation node,
248 AccessSemantics semantics) {
249 // Locals don't need to be tree shaken.
250 }
251
252 @override
253 void visitParameterInvocation(MethodInvocation node,
254 AccessSemantics semantics) {
255 // Locals don't need to be tree shaken.
256 }
257
258 @override
259 void visitStaticFieldInvocation(MethodInvocation node,
260 AccessSemantics semantics) {
261 // Invocation of a static field.
262 analysis.accesses.add(semantics.element);
263 analysis.invokes.add(
264 createSelectorFromMethodInvocation(node, 'call'));
265 }
266
267 void visitStaticMethodInvocation(MethodInvocation node,
268 AccessSemantics semantics) {
269 analysis.calls.add(semantics.element);
270 }
271
272 void visitStaticPropertyInvocation(MethodInvocation node,
273 AccessSemantics semantics) {
274 // Invocation of a property. TODO(paulberry): handle this.
275 super.visitStaticPropertyInvocation(node, semantics);
276 }
277
278 void visitDynamicAccess(AstNode node, AccessSemantics semantics) {
279 if (semantics.isRead) {
280 analysis.invokes.add(
281 new Selector.getter(semantics.identifier.name, null));
233 } 282 }
234 node.argumentList.accept(this); 283 if (semantics.isWrite) {
235 AccessSemantics semantics = classifyMethodInvocation(node); 284 // TODO(paulberry): implement.
236 switch (semantics.kind) { 285 return giveUp(node, '_handlePropertyAccess of ${semantics}.');
237 case AccessKind.DYNAMIC:
238 analysis.invokes.add(createSelectorFromMethodInvocation(node));
239 break;
240 case AccessKind.LOCAL_FUNCTION:
241 case AccessKind.LOCAL_VARIABLE:
242 case AccessKind.PARAMETER:
243 // Locals don't need to be tree shaken.
244 break;
245 case AccessKind.STATIC_FIELD:
246 // Invocation of a field. TODO(paulberry): handle this.
247 throw new UnimplementedError();
248 case AccessKind.STATIC_METHOD:
249 analysis.calls.add(semantics.element);
250 break;
251 case AccessKind.STATIC_PROPERTY:
252 // Invocation of a property. TODO(paulberry): handle this.
253 throw new UnimplementedError();
254 default:
255 // Unexpected access kind.
256 throw new UnimplementedError();
257 } 286 }
258 } 287 }
259 288
260 @override 289 void visitLocalFunctionAccess(AstNode node, AccessSemantics semantics) {
261 void visitPropertyAccess(PropertyAccess node) { 290 // Locals don't need to be tree shaken.
262 if (node.target != null) {
263 node.target.accept(this);
264 }
265 _handlePropertyAccess(classifyPropertyAccess(node));
266 } 291 }
267 292
268 @override 293 void visitLocalVariableAccess(AstNode node, AccessSemantics semantics) {
269 visitPrefixedIdentifier(PrefixedIdentifier node) { 294 // Locals don't need to be tree shaken.
270 node.prefix.accept(this);
271 _handlePropertyAccess(classifyPrefixedIdentifier(node));
272 } 295 }
273 296
274 @override 297 void visitParameterAccess(AstNode node, AccessSemantics semantics) {
275 visitSimpleIdentifier(SimpleIdentifier node) { 298 // Locals don't need to be tree shaken.
276 AccessSemantics semantics = classifySimpleIdentifier(node);
277 if (semantics != null) {
278 _handlePropertyAccess(semantics);
279 }
280 } 299 }
281 300
282 void _handlePropertyAccess(AccessSemantics semantics) { 301 void visitStaticFieldAccess(AstNode node, AccessSemantics semantics) {
283 switch (semantics.kind) { 302 analysis.accesses.add(semantics.element);
284 case AccessKind.DYNAMIC: 303 }
285 if (semantics.isRead) { 304
286 analysis.invokes.add( 305 void visitStaticMethodAccess(AstNode node, AccessSemantics semantics) {
287 new Selector.getter(semantics.identifier.name, null)); 306 // Method tear-off. TODO(paulberry): implement.
288 } 307 super.visitStaticMethodAccess(node, semantics);
289 if (semantics.isWrite) { 308 }
290 // TODO(paulberry): implement. 309
291 throw new UnimplementedError(); 310 void visitStaticPropertyAccess(AstNode node, AccessSemantics semantics) {
292 } 311 // TODO(paulberry): implement.
293 break; 312 super.visitStaticPropertyAccess(node, semantics);
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 }
312 } 313 }
313 } 314 }
OLDNEW
« no previous file with comments | « pkg/analyzer2dart/lib/src/semantic_visitor.dart ('k') | pkg/analyzer2dart/lib/src/util.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698