| Index: pkg/analyzer2dart/lib/src/tree_shaker.dart
|
| diff --git a/pkg/analyzer2dart/lib/src/tree_shaker.dart b/pkg/analyzer2dart/lib/src/tree_shaker.dart
|
| index 0ea41dadc54a7785c1b9277d0d83fb5a9edeb116..14a90c7009899e1a7678d8547c3da9945cdc7b25 100644
|
| --- a/pkg/analyzer2dart/lib/src/tree_shaker.dart
|
| +++ b/pkg/analyzer2dart/lib/src/tree_shaker.dart
|
| @@ -8,9 +8,12 @@ import 'dart:collection';
|
|
|
| import 'package:analyzer/analyzer.dart';
|
| import 'package:analyzer/src/generated/element.dart';
|
| +import 'package:analyzer/src/generated/source.dart';
|
| import 'package:compiler/implementation/universe/universe.dart';
|
|
|
| import 'closed_world.dart';
|
| +import 'util.dart';
|
| +import 'semantic_visitor.dart';
|
| import 'package:analyzer2dart/src/identifier_semantics.dart';
|
|
|
| /**
|
| @@ -28,6 +31,12 @@ class MethodAnalysis {
|
| final List<ExecutableElement> calls = <ExecutableElement>[];
|
|
|
| /**
|
| + * The fields and top-level variables statically accessed by the method.
|
| + */
|
| + // TODO(johnniwinther): Should we split this into reads and writes?
|
| + final List<PropertyInducingElement> accesses = <PropertyInducingElement>[];
|
| +
|
| + /**
|
| * The selectors used by the method to perform dynamic invocation.
|
| */
|
| final List<Selector> invokes = <Selector>[];
|
| @@ -174,6 +183,7 @@ class TreeShaker {
|
| analysis.calls.forEach(_addElement);
|
| analysis.invokes.forEach(_addSelector);
|
| analysis.instantiates.forEach(_addElement);
|
| + analysis.accesses.forEach(_addElement);
|
| } else if (element is ClassElement) {
|
| ClassAnalysis analysis = _localComputer.analyzeClass(element);
|
| _world.instantiatedClasses[element] = analysis.declaration;
|
| @@ -183,8 +193,13 @@ class TreeShaker {
|
| } else if (element is FieldElement) {
|
| VariableDeclaration declaration = element.node;
|
| _world.fields[element] = declaration;
|
| + } else if (element is TopLevelVariableElement) {
|
| + VariableDeclaration declaration = element.node;
|
| + _world.variables[element] = declaration;
|
| } else {
|
| - throw new Exception('Unexpected element type while tree shaking');
|
| + throw new Exception(
|
| + 'Unexpected element type while tree shaking: '
|
| + '$element (${element.runtimeType})');
|
| }
|
| }
|
| print('Tree shaking done');
|
| @@ -192,24 +207,13 @@ class TreeShaker {
|
| }
|
| }
|
|
|
| -Selector createSelectorFromMethodInvocation(MethodInvocation node) {
|
| - int arity = 0;
|
| - List<String> namedArguments = <String>[];
|
| - for (var x in node.argumentList.arguments) {
|
| - if (x is NamedExpression) {
|
| - namedArguments.add(x.name.label.name);
|
| - } else {
|
| - arity++;
|
| - }
|
| - }
|
| - return new Selector.call(node.methodName.name, null, arity, namedArguments);
|
| -}
|
| -
|
| -class TreeShakingVisitor extends RecursiveAstVisitor {
|
| +class TreeShakingVisitor extends SemanticVisitor {
|
| final MethodAnalysis analysis;
|
|
|
| TreeShakingVisitor(this.analysis);
|
|
|
| + Source get currentSource => analysis.declaration.element.source;
|
| +
|
| @override
|
| void visitInstanceCreationExpression(InstanceCreationExpression node) {
|
| ConstructorElement staticElement = node.staticElement;
|
| @@ -227,87 +231,84 @@ class TreeShakingVisitor extends RecursiveAstVisitor {
|
| }
|
|
|
| @override
|
| - void visitMethodInvocation(MethodInvocation node) {
|
| - if (node.target != null) {
|
| - node.target.accept(this);
|
| - }
|
| - node.argumentList.accept(this);
|
| - AccessSemantics semantics = classifyMethodInvocation(node);
|
| - switch (semantics.kind) {
|
| - case AccessKind.DYNAMIC:
|
| - analysis.invokes.add(createSelectorFromMethodInvocation(node));
|
| - break;
|
| - case AccessKind.LOCAL_FUNCTION:
|
| - case AccessKind.LOCAL_VARIABLE:
|
| - case AccessKind.PARAMETER:
|
| - // Locals don't need to be tree shaken.
|
| - break;
|
| - case AccessKind.STATIC_FIELD:
|
| - // Invocation of a field. TODO(paulberry): handle this.
|
| - throw new UnimplementedError();
|
| - case AccessKind.STATIC_METHOD:
|
| - analysis.calls.add(semantics.element);
|
| - break;
|
| - case AccessKind.STATIC_PROPERTY:
|
| - // Invocation of a property. TODO(paulberry): handle this.
|
| - throw new UnimplementedError();
|
| - default:
|
| - // Unexpected access kind.
|
| - throw new UnimplementedError();
|
| - }
|
| + void visitDynamicInvocation(MethodInvocation node,
|
| + AccessSemantics semantics) {
|
| + analysis.invokes.add(
|
| + createSelectorFromMethodInvocation(node, node.methodName.name));
|
| }
|
|
|
| @override
|
| - void visitPropertyAccess(PropertyAccess node) {
|
| - if (node.target != null) {
|
| - node.target.accept(this);
|
| - }
|
| - _handlePropertyAccess(classifyPropertyAccess(node));
|
| + void visitLocalFunctionInvocation(MethodInvocation node,
|
| + AccessSemantics semantics) {
|
| + // Locals don't need to be tree shaken.
|
| }
|
|
|
| @override
|
| - visitPrefixedIdentifier(PrefixedIdentifier node) {
|
| - node.prefix.accept(this);
|
| - _handlePropertyAccess(classifyPrefixedIdentifier(node));
|
| + void visitLocalVariableInvocation(MethodInvocation node,
|
| + AccessSemantics semantics) {
|
| + // Locals don't need to be tree shaken.
|
| }
|
|
|
| @override
|
| - visitSimpleIdentifier(SimpleIdentifier node) {
|
| - AccessSemantics semantics = classifySimpleIdentifier(node);
|
| - if (semantics != null) {
|
| - _handlePropertyAccess(semantics);
|
| - }
|
| + void visitParameterInvocation(MethodInvocation node,
|
| + AccessSemantics semantics) {
|
| + // Locals don't need to be tree shaken.
|
| }
|
|
|
| - void _handlePropertyAccess(AccessSemantics semantics) {
|
| - switch (semantics.kind) {
|
| - case AccessKind.DYNAMIC:
|
| - if (semantics.isRead) {
|
| - analysis.invokes.add(
|
| - new Selector.getter(semantics.identifier.name, null));
|
| - }
|
| - if (semantics.isWrite) {
|
| - // TODO(paulberry): implement.
|
| - throw new UnimplementedError();
|
| - }
|
| - break;
|
| - case AccessKind.LOCAL_FUNCTION:
|
| - case AccessKind.LOCAL_VARIABLE:
|
| - case AccessKind.PARAMETER:
|
| - // Locals don't need to be tree shaken.
|
| - break;
|
| - case AccessKind.STATIC_FIELD:
|
| - // TODO(paulberry): implement.
|
| - throw new UnimplementedError();
|
| - case AccessKind.STATIC_METHOD:
|
| - // Method tear-off. TODO(paulberry): implement.
|
| - break;
|
| - case AccessKind.STATIC_PROPERTY:
|
| - // TODO(paulberry): implement.
|
| - throw new UnimplementedError();
|
| - default:
|
| - // Unexpected access kind.
|
| - throw new UnimplementedError();
|
| + @override
|
| + void visitStaticFieldInvocation(MethodInvocation node,
|
| + AccessSemantics semantics) {
|
| + // Invocation of a static field.
|
| + analysis.accesses.add(semantics.element);
|
| + analysis.invokes.add(
|
| + createSelectorFromMethodInvocation(node, 'call'));
|
| + }
|
| +
|
| + void visitStaticMethodInvocation(MethodInvocation node,
|
| + AccessSemantics semantics) {
|
| + analysis.calls.add(semantics.element);
|
| + }
|
| +
|
| + void visitStaticPropertyInvocation(MethodInvocation node,
|
| + AccessSemantics semantics) {
|
| + // Invocation of a property. TODO(paulberry): handle this.
|
| + super.visitStaticPropertyInvocation(node, semantics);
|
| + }
|
| +
|
| + void visitDynamicAccess(AstNode node, AccessSemantics semantics) {
|
| + if (semantics.isRead) {
|
| + analysis.invokes.add(
|
| + new Selector.getter(semantics.identifier.name, null));
|
| }
|
| + if (semantics.isWrite) {
|
| + // TODO(paulberry): implement.
|
| + return giveUp(node, '_handlePropertyAccess of ${semantics}.');
|
| + }
|
| + }
|
| +
|
| + void visitLocalFunctionAccess(AstNode node, AccessSemantics semantics) {
|
| + // Locals don't need to be tree shaken.
|
| + }
|
| +
|
| + void visitLocalVariableAccess(AstNode node, AccessSemantics semantics) {
|
| + // Locals don't need to be tree shaken.
|
| + }
|
| +
|
| + void visitParameterAccess(AstNode node, AccessSemantics semantics) {
|
| + // Locals don't need to be tree shaken.
|
| + }
|
| +
|
| + void visitStaticFieldAccess(AstNode node, AccessSemantics semantics) {
|
| + analysis.accesses.add(semantics.element);
|
| + }
|
| +
|
| + void visitStaticMethodAccess(AstNode node, AccessSemantics semantics) {
|
| + // Method tear-off. TODO(paulberry): implement.
|
| + super.visitStaticMethodAccess(node, semantics);
|
| + }
|
| +
|
| + void visitStaticPropertyAccess(AstNode node, AccessSemantics semantics) {
|
| + // TODO(paulberry): implement.
|
| + super.visitStaticPropertyAccess(node, semantics);
|
| }
|
| }
|
|
|