Index: pkg/kernel/lib/transformations/reify/analysis/program_analysis.dart |
diff --git a/pkg/kernel/lib/transformations/reify/analysis/program_analysis.dart b/pkg/kernel/lib/transformations/reify/analysis/program_analysis.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8e712d77c527ce2a5c779c9624f309c81533edc4 |
--- /dev/null |
+++ b/pkg/kernel/lib/transformations/reify/analysis/program_analysis.dart |
@@ -0,0 +1,106 @@ |
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+library kernel.transformation.reify.analysis.program_analysis; |
+ |
+import '../asts.dart'; |
+import 'package:kernel/ast.dart'; |
+ |
+// TODO(karlklose): keep all predicates and derived information here and move |
+// the actual data to a builder class. |
+class ProgramKnowledge { |
+ Map<Member, Set<TypeParameter>> _usedTypeVariables = |
+ <Member, Set<TypeParameter>>{}; |
+ |
+ Map<Member, Set<DartType>> isTests = <Member, Set<DartType>>{}; |
+ |
+ Set<Class> _classTests; |
+ |
+ /// Contains all classes that are used as the declaration of a type expression |
+ /// in a type test. |
+ Set<Class> get classTests { |
+ if (_classTests == null) { |
+ _classTests = isTests.values |
+ .expand((set) => set) |
+ .where((DartType type) => type is InterfaceType) |
+ .map((DartType type) => (type as InterfaceType).classNode) |
+ .toSet(); |
+ } |
+ return _classTests; |
+ } |
+ |
+ recordTypeVariableUse(Expression expression, TypeParameter parameter) { |
+ // TODO(karlklose): also record expression. |
+ add(_usedTypeVariables, getEnclosingMember(expression), parameter); |
+ } |
+ |
+ Set<TypeParameter> usedParameters(Member member) { |
+ return _usedTypeVariables[member] ?? new Set<TypeParameter>(); |
+ } |
+ |
+ void recordIsTest(IsExpression node, DartType type) { |
+ add(isTests, getEnclosingMember(node), type); |
+ } |
+ |
+ add(Map<dynamic, Set> map, key, value) { |
+ map.putIfAbsent(key, () => new Set()).add(value); |
+ } |
+} |
+ |
+typedef bool LibraryFilter(Library library); |
+ |
+class ProgramAnalysis extends Visitor { |
+ final ProgramKnowledge knowledge; |
+ final LibraryFilter analyzeLibrary; |
+ |
+ ProgramAnalysis(this.knowledge, this.analyzeLibrary); |
+ |
+ defaultTreeNode(TreeNode node) => node.visitChildren(this); |
+ |
+ visitLibrary(Library library) { |
+ if (!analyzeLibrary(library)) { |
+ return; |
+ } |
+ super.visitLibrary(library); |
+ } |
+ |
+ handleTypeReference(TreeNode node, DartType type) { |
+ typeVariables(type).forEach((TypeParameter parameter) { |
+ knowledge.recordTypeVariableUse(node, parameter); |
+ }); |
+ } |
+ |
+ handleInstantiation(InvocationExpression node) { |
+ node.arguments.types.forEach((DartType type) { |
+ handleTypeReference(node, type); |
+ }); |
+ } |
+ |
+ visitIsExpression(IsExpression node) { |
+ knowledge.recordIsTest(node, node.type); |
+ handleTypeReference(node, node.type); |
+ node.visitChildren(this); |
+ } |
+ |
+ visitConstructorInvocation(ConstructorInvocation node) { |
+ handleInstantiation(node); |
+ node.visitChildren(this); |
+ } |
+ |
+ visitStaticInvocation(StaticInvocation node) { |
+ if (node.target.kind == ProcedureKind.Factory) { |
+ handleInstantiation(node); |
+ } |
+ node.visitChildren(this); |
+ } |
+} |
+ |
+bool _analyzeAll(Library library) => true; |
+ |
+ProgramKnowledge analyze(Program program, |
+ {LibraryFilter analyzeLibrary: _analyzeAll}) { |
+ ProgramKnowledge knowledge = new ProgramKnowledge(); |
+ program.accept(new ProgramAnalysis(knowledge, analyzeLibrary)); |
+ return knowledge; |
+} |