ed390e7bad
R=dmitryas@google.com Change-Id: If2e1f735de9f3879fcf321af5d5fa00e291e28a8 Reviewed-on: https://dart-review.googlesource.com/16460 Reviewed-by: Dmitry Stefantsov <dmitryas@google.com> Commit-Queue: Karl Klose <karlklose@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(Program program,
|
|
{LibraryFilter analyzeLibrary: _analyzeAll}) {
|
|
ProgramKnowledge knowledge = new ProgramKnowledge();
|
|
program.accept(new ProgramAnalysis(knowledge, analyzeLibrary));
|
|
return knowledge;
|
|
}
|