// 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> _usedTypeVariables = >{}; Map> isTests = >{}; Set _classTests; /// Contains all classes that are used as the declaration of a type expression /// in a type test. Set 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 usedParameters(Member member) { return _usedTypeVariables[member] ?? new Set(); } void recordIsTest(IsExpression node, DartType type) { add(isTests, getEnclosingMember(node), type); } add(Map 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; }