Files
sdk/pkg/analyzer_fe_comparison/lib/src/kernel.dart
T
Kevin Millikin a8493e1b50 Flip the default value of the Kernel syncAsync flag
In Kernel's TargetFlags, this flag still defaulted to false.  Flip the
default to true and update all client code in the SDK.  The
expectation is that many of the places that now pass false explicitly
really just want the default, but that will be verified separately and
then the flag will be removed.

Change-Id: I2a38eb53f280f21f59bb1d2e88c42516f827fd39
Reviewed-on: https://dart-review.googlesource.com/c/85448
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Kevin Millikin <kmillikin@google.com>
2018-12-12 14:23:54 +00:00

359 lines
13 KiB
Dart

// Copyright (c) 2018, 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.
import 'dart:async';
import 'package:analyzer_fe_comparison/src/comparison_node.dart';
import 'package:front_end/src/api_prototype/compiler_options.dart'
show CompilerOptions;
import 'package:front_end/src/api_prototype/diagnostic_message.dart'
show DiagnosticMessage, DiagnosticMessageHandler, getMessageHeaderText;
import 'package:front_end/src/api_prototype/kernel_generator.dart';
import 'package:front_end/src/api_prototype/standard_file_system.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/target/targets.dart';
/// Compiles the given [inputs] to kernel using the front_end, and returns a
/// [ComparisonNode] representing them.
Future<ComparisonNode> analyzePackage(
List<Uri> inputs, Uri packagesFileUri, Uri platformUri) async {
var messages = <DiagnosticMessage>[];
var component = await kernelForComponent(
inputs, _makeCompilerOptions(packagesFileUri, platformUri, messages.add));
if (messages.isNotEmpty) {
return ComparisonNode(
'Error occurred', messages.map(_diagnosticMessageToNode).toList());
}
var libraryNodes = <ComparisonNode>[];
var visitor = _KernelVisitor(libraryNodes);
for (var library in component.libraries) {
if (inputs.contains(library.importUri)) {
library.accept(visitor);
}
}
return ComparisonNode.sorted('Component', libraryNodes);
}
/// Compiles the given [input] to kernel using the front_end, and returns a
/// [ComparisonNode] representing it.
///
/// Only libraries whose URI passes the [uriFilter] are included in the results.
Future<ComparisonNode> analyzeProgram(Uri input, Uri packagesFileUri,
Uri platformUri, bool uriFilter(Uri uri)) async {
var messages = <DiagnosticMessage>[];
var component = await kernelForProgram(
input, _makeCompilerOptions(packagesFileUri, platformUri, messages.add));
if (messages.isNotEmpty) {
return ComparisonNode(
'Error occurred', messages.map(_diagnosticMessageToNode).toList());
}
var libraryNodes = <ComparisonNode>[];
var visitor = _KernelVisitor(libraryNodes);
for (var library in component.libraries) {
if (uriFilter(library.importUri)) {
library.accept(visitor);
}
}
return ComparisonNode.sorted('Component', libraryNodes);
}
ComparisonNode _diagnosticMessageToNode(DiagnosticMessage message) {
return ComparisonNode(getMessageHeaderText(message));
}
CompilerOptions _makeCompilerOptions(Uri packagesFileUri, Uri platformUri,
DiagnosticMessageHandler onDiagnostic) {
var targetFlags = TargetFlags();
var target = NoneTarget(targetFlags);
var fileSystem = StandardFileSystem.instance;
return CompilerOptions()
..fileSystem = fileSystem
..packagesFileUri = packagesFileUri
..sdkSummary = platformUri
..target = target
..throwOnErrorsForDebugging = false
..embedSourceText = false
..onDiagnostic = onDiagnostic;
}
/// Visitor for serializing a kernel representation of a program into
/// ComparisonNodes.
///
/// Results are accumulated into [_resultNodes].
class _KernelVisitor extends TreeVisitor<void> {
final List<ComparisonNode> _resultNodes;
_KernelVisitor(this._resultNodes);
@override
void defaultTreeNode(TreeNode node) {
throw new UnimplementedError('KernelVisitor: ${node.runtimeType}');
}
@override
void visitClass(Class class_) {
if (class_.isAnonymousMixin) return null;
var kind = class_.isEnum
? 'Enum'
: class_.isMixinApplication
? 'MixinApplication'
: class_.isMixinDeclaration ? 'Mixin' : 'Class';
var children = <ComparisonNode>[];
var visitor = _KernelVisitor(children);
if (class_.isEnum) {
for (var field in class_.fields) {
if (!field.isStatic) continue;
if (field.name.name == 'values') continue;
// TODO(paulberry): handle index
children.add(ComparisonNode('EnumValue ${field.name.name}'));
}
} else {
visitor._visitTypeParameters(class_.typeParameters);
if (class_.supertype != null) {
var declaredSupertype = class_.supertype.asInterfaceType;
if (class_.isMixinDeclaration) {
var constraints = <DartType>[];
// Kernel represents a mixin declaration such as:
// mixin M on S0, S1, S2 {...}
// By desugaring it to:
// abstract class _M&S0&S1 implements S0, S1 {}
// abstract class _M&S0&S1&S2 implements _M&S0&S1 {}
// abstract class M extends M&S0&S1&S2 {...}
// (See dartbug.com/34783)
while (declaredSupertype.classNode.isAnonymousMixin) {
// Since we're walking up the class hierarchy, we encounter the
// mixins in the reverse order that they were declared, so we have
// to use [List.insert] to add them to [constraints].
constraints.insert(
0,
declaredSupertype
.classNode.implementedTypes[1].asInterfaceType);
declaredSupertype =
declaredSupertype.classNode.implementedTypes[0].asInterfaceType;
}
constraints.insert(0, declaredSupertype);
for (int i = 0; i < constraints.length; i++) {
children.add(_TypeVisitor.translate('On $i: ', constraints[i]));
}
} else {
var mixedInTypes = <DartType>[];
if (class_.isMixinApplication) {
mixedInTypes.add(class_.mixedInType.asInterfaceType);
}
while (declaredSupertype.classNode.isAnonymousMixin) {
// Since we're walking from the class to its declared supertype, we
// encounter the mixins in the reverse order that they were declared,
// so we have to use [List.insert] to add them to [mixedInTypes].
mixedInTypes.insert(
0, declaredSupertype.classNode.mixedInType.asInterfaceType);
declaredSupertype =
declaredSupertype.classNode.supertype.asInterfaceType;
}
children.add(_TypeVisitor.translate('Extends: ', declaredSupertype));
for (int i = 0; i < mixedInTypes.length; i++) {
children.add(_TypeVisitor.translate('Mixin $i: ', mixedInTypes[i]));
}
}
}
for (int i = 0; i < class_.implementedTypes.length; i++) {
children.add(_TypeVisitor.translate(
'Implements $i: ', class_.implementedTypes[i].asInterfaceType));
}
visitor._visitList(class_.fields);
visitor._visitList(class_.constructors);
visitor._visitList(class_.procedures);
}
// TODO(paulberry): handle more fields from Class
_resultNodes.add(ComparisonNode.sorted('$kind ${class_.name}', children));
}
@override
void visitConstructor(Constructor constructor) {
if (constructor.isSynthetic) return null;
var name = constructor.name.name;
if (name.isEmpty) {
name = '(unnamed)';
}
var children = <ComparisonNode>[];
var visitor = _KernelVisitor(children);
constructor.function.accept(visitor);
// TODO(paulberry): handle more fields from Constructor
_resultNodes.add(ComparisonNode.sorted('Constructor $name', children));
}
@override
void visitField(Field field) {
if (field.name.name == '_redirecting#') return null;
if (field.name.name == '_exports#') return null;
var children = <ComparisonNode>[];
children.add(_TypeVisitor.translate('Type: ', field.type));
// TODO(paulberry): handle more fields from Field
_resultNodes
.add(ComparisonNode.sorted('Field ${field.name.name}', children));
}
@override
void visitFunctionNode(FunctionNode node) {
var parent = node.parent;
if (!(parent is Constructor || parent is Procedure && parent.isFactory)) {
_visitTypeParameters(node.typeParameters);
_resultNodes
.add(_TypeVisitor.translate('Return type: ', node.returnType));
}
var parameterChildren = <ComparisonNode>[];
var parameterVisitor = _KernelVisitor(parameterChildren);
for (int i = 0; i < node.positionalParameters.length; i++) {
parameterVisitor._visitParameter(node.positionalParameters[i],
i < node.requiredParameterCount ? 'Required' : 'Optional');
}
for (int i = 0; i < node.namedParameters.length; i++) {
parameterVisitor._visitParameter(node.namedParameters[i], 'Named');
}
_resultNodes.add(ComparisonNode('Parameters', parameterChildren));
// TODO(paulberry): handle more fields from FunctionNode
}
@override
void visitLibrary(Library library) {
var children = <ComparisonNode>[];
if (library.name != null) {
children.add(ComparisonNode('name=${library.name}'));
}
var visitor = _KernelVisitor(children);
visitor._visitList(library.typedefs);
visitor._visitList(library.classes);
visitor._visitList(library.procedures);
visitor._visitList(library.fields);
// TODO(paulberry): handle more fields from Library
_resultNodes
.add(ComparisonNode.sorted(library.importUri.toString(), children));
}
@override
void visitProcedure(Procedure procedure) {
if (procedure.isSyntheticForwarder) {
return null;
}
if (procedure.name.name.startsWith('__loadLibrary_')) {
// Sometimes the front end generates procedures with this name that don't
// correspond to anything in the source file. Ignore them.
return null;
}
// TODO(paulberry): add an annotation to the ComparisonNode when the
// procedure is a factory.
var kind = procedure.isFactory
? 'Constructor'
: procedure.kind.toString().replaceAll('ProcedureKind.', '');
var name = procedure.name.name;
if (name.isEmpty) {
name = '(unnamed)';
}
var children = <ComparisonNode>[];
var visitor = _KernelVisitor(children);
procedure.function.accept(visitor);
// TODO(paulberry): handle more fields from Procedure
_resultNodes.add(ComparisonNode.sorted('$kind $name', children));
}
@override
void visitTypedef(Typedef typedef) {
var children = <ComparisonNode>[];
var visitor = _KernelVisitor(children);
visitor._visitTypeParameters(typedef.typeParameters);
children.add(_TypeVisitor.translate('Type: ', typedef.type));
// TODO(paulberry): handle more fields from Typedef
_resultNodes
.add(ComparisonNode.sorted('Typedef ${typedef.name}', children));
}
/// Visits all the nodes in [nodes].
void _visitList(List<TreeNode> nodes) {
for (var node in nodes) {
node.accept(this);
}
}
void _visitParameter(VariableDeclaration parameter, String kind) {
var children = <ComparisonNode>[];
children.add(_TypeVisitor.translate('Type: ', parameter.type));
// TODO(paulberry): handle more fields from VariableDeclaration
_resultNodes
.add(ComparisonNode.sorted('$kind: ${parameter.name}', children));
}
void _visitTypeParameters(List<TypeParameter> typeParameters) {
for (int i = 0; i < typeParameters.length; i++) {
_resultNodes.add(ComparisonNode(
'Type parameter $i: ${typeParameters[i].name}',
[_TypeVisitor.translate('Bound: ', typeParameters[i].bound)]));
}
}
}
/// Visitor for serializing a kernel representation of a type into
/// ComparisonNodes.
class _TypeVisitor extends DartTypeVisitor<ComparisonNode> {
/// Text to prepend to the node text.
String _prefix;
_TypeVisitor(this._prefix);
@override
ComparisonNode defaultDartType(DartType node) {
throw new UnimplementedError('_TypeVisitor: ${node.runtimeType}');
}
@override
ComparisonNode visitDynamicType(DynamicType node) {
return ComparisonNode('${_prefix}Dynamic');
}
@override
ComparisonNode visitFunctionType(FunctionType node) {
var children = <ComparisonNode>[];
var visitor = _KernelVisitor(children);
visitor._visitTypeParameters(node.typeParameters);
children.add(translate('Return type: ', node.returnType));
for (int i = 0; i < node.positionalParameters.length; i++) {
var kind = i < node.requiredParameterCount ? 'Required' : 'Optional';
children
.add(translate('$kind parameter $i: ', node.positionalParameters[i]));
}
for (var namedType in node.namedParameters) {
children.add(
translate('Named parameter ${namedType.name}: ', namedType.type));
}
return ComparisonNode.sorted('${_prefix}FunctionType', children);
}
@override
ComparisonNode visitInterfaceType(InterfaceType node) {
var children = <ComparisonNode>[];
children.add(ComparisonNode(
'Library: ${node.classNode.enclosingLibrary.importUri}'));
for (int i = 0; i < node.typeArguments.length; i++) {
children.add(translate('Type arg $i: ', node.typeArguments[i]));
}
return ComparisonNode(
'${_prefix}InterfaceType ${node.classNode.name}', children);
}
@override
ComparisonNode visitTypeParameterType(TypeParameterType node) {
// TODO(paulberry): disambiguate if needed.
return ComparisonNode(
'${_prefix}TypeParameterType: ${node.parameter.name}');
}
@override
ComparisonNode visitVoidType(VoidType node) {
return ComparisonNode('${_prefix}Void');
}
static ComparisonNode translate(String prefix, DartType type) {
return type.accept(new _TypeVisitor(prefix));
}
}