4f2bdff90b
Change-Id: I1a3cc03fba9783807fa637a9d42fdbad68ee7686 Reviewed-on: https://dart-review.googlesource.com/31040 Commit-Queue: Peter von der Ahé <ahe@google.com> Reviewed-by: Kevin Millikin <kmillikin@google.com>
107 lines
3.0 KiB
Dart
107 lines
3.0 KiB
Dart
// 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 '../../../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(Component component,
|
|
{LibraryFilter analyzeLibrary: _analyzeAll}) {
|
|
ProgramKnowledge knowledge = new ProgramKnowledge();
|
|
component.accept(new ProgramAnalysis(knowledge, analyzeLibrary));
|
|
return knowledge;
|
|
}
|