blob: df259b6c8d5e5ec32e293ac12b4bb84f849f9177 [file] [log] [blame]
// 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;
}