d810c7d0c0
This commit was generated by the following steps: - Manually change the SDK constraint in `pkg/front_end/pubspec.yaml` - Run `gclient sync` - Run `find pkg/front_end/benchmarks pkg/front_end/lib pkg/front_end/presubmit_helper.dart pkg/front_end/presubmit_helper_spawn.dart pkg/front_end/test pkg/front_end/tool -iname '*.dart' | xargs tools/sdks/dart-sdk/bin/dart format` - Manually fix remaining long lines and add dead code ignore comments. - Fix coverage by running `dart --enable-asserts pkg/front_end/test/coverage_suite.dart --tasks=5 --add-and-remove-comments` - Fix `pkg/front_end/test/coverage_merger/assert_message_auto_ignored` by running `dart pkg/front_end/test/unit_test_suites.dart -p pkg/front_end/test/coverage_merger/assert_message_auto_ignored -DupdateExpectations=true` The diff is large because the version bump causes the formatter to switch into "tall mode". Change-Id: I6a6a696410da8b168060acfe0e4d6e91e294c4f0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/447628 Auto-Submit: Paul Berry <paulberry@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com>
229 lines
7.0 KiB
Dart
229 lines
7.0 KiB
Dart
// Copyright (c) 2017, 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:convert';
|
|
import 'dart:io' show File;
|
|
import 'dart:typed_data' show BytesBuilder, Uint8List;
|
|
|
|
import 'package:kernel/ast.dart';
|
|
import 'package:kernel/binary/ast_from_binary.dart';
|
|
import 'package:kernel/binary/ast_to_binary.dart';
|
|
import 'package:kernel/text/ast_to_text.dart';
|
|
import 'package:test/test.dart';
|
|
import 'package:front_end/src/compute_platform_binaries_location.dart'
|
|
show computePlatformBinariesLocation;
|
|
|
|
/// Test metadata: to each node we attach a metadata that contains
|
|
/// * node formatted as string
|
|
/// * reference to its enclosing member
|
|
/// * type representing the first type parameter of its enclosing function
|
|
class Metadata {
|
|
final String string;
|
|
final Reference? _memberRef;
|
|
final DartType type;
|
|
|
|
Member? get member => _memberRef?.asMember;
|
|
|
|
Metadata.forNode(TreeNode n)
|
|
: this(
|
|
n.leakingDebugToString(),
|
|
// Refers to the member, not about the function => use getter.
|
|
getMemberReferenceGetter(getMemberForMetadata(n)),
|
|
getTypeForMetadata(n),
|
|
);
|
|
|
|
Metadata(this.string, this._memberRef, this.type);
|
|
}
|
|
|
|
Member? getMemberForMetadata(TreeNode node) {
|
|
final parent = node.parent;
|
|
if (parent == null) return null;
|
|
if (parent is Member) return parent;
|
|
return getMemberForMetadata(parent);
|
|
}
|
|
|
|
DartType getTypeForMetadata(TreeNode node) {
|
|
final parent = node.parent;
|
|
if (parent == null) return const VoidType();
|
|
if (parent is FunctionNode) {
|
|
if (parent.typeParameters.isEmpty) {
|
|
return const VoidType();
|
|
}
|
|
return new TypeParameterType(
|
|
parent.typeParameters[0],
|
|
Nullability.nonNullable,
|
|
);
|
|
}
|
|
return getTypeForMetadata(parent);
|
|
}
|
|
|
|
class TestMetadataRepository extends MetadataRepository<Metadata> {
|
|
static const kTag = 'kernel.metadata.test';
|
|
|
|
@override
|
|
final String tag = kTag;
|
|
|
|
@override
|
|
final Map<TreeNode, Metadata> mapping = <TreeNode, Metadata>{};
|
|
|
|
@override
|
|
void writeToBinary(Metadata metadata, Node node, BinarySink sink) {
|
|
expect(metadata, equals(mapping[node]));
|
|
sink.writeByteList(utf8.encode(metadata.string));
|
|
sink.writeStringReference(metadata.string);
|
|
sink.writeNullAllowedCanonicalNameReference(metadata.member?.reference);
|
|
sink.writeDartType(metadata.type);
|
|
}
|
|
|
|
@override
|
|
Metadata readFromBinary(Node node, BinarySource source) {
|
|
final string1 = utf8.decode(source.readByteList());
|
|
final string2 = source.readStringReference();
|
|
final memberRef = source.readNullableCanonicalNameReference()?.reference;
|
|
final type = source.readDartType();
|
|
expect(string1, equals(string2));
|
|
return new Metadata(string2, memberRef, type);
|
|
}
|
|
}
|
|
|
|
class BytesBuilderSink implements Sink<List<int>> {
|
|
final builder = new BytesBuilder(copy: false);
|
|
|
|
@override
|
|
void add(List<int> bytes) {
|
|
builder.add(bytes);
|
|
}
|
|
|
|
@override
|
|
void close() {}
|
|
}
|
|
|
|
typedef NodePredicate = bool Function(TreeNode node);
|
|
|
|
/// Visitor calling [handle] function on every node which can have metadata
|
|
/// associated with it and also satisfies the given [predicate].
|
|
class Visitor extends RecursiveVisitor {
|
|
final NodePredicate predicate;
|
|
final void Function(TreeNode) handle;
|
|
|
|
Visitor(this.predicate, this.handle);
|
|
|
|
@override
|
|
void defaultTreeNode(TreeNode node) {
|
|
super.defaultTreeNode(node);
|
|
if (MetadataRepository.isSupported(node) && predicate(node)) {
|
|
handle(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Visit the given component assigning [Metadata] object created with
|
|
/// [Metadata.forNode] to each supported node in the component which matches
|
|
/// [shouldAnnotate] predicate.
|
|
void annotate(Component p, NodePredicate shouldAnnotate) {
|
|
globalDebuggingNames = new NameSystem();
|
|
final repository = p.metadata[TestMetadataRepository.kTag]!;
|
|
p.accept(
|
|
new Visitor(shouldAnnotate, (node) {
|
|
repository.mapping[node] = new Metadata.forNode(node);
|
|
}),
|
|
);
|
|
}
|
|
|
|
/// Visit the given component and checks that each supported node in the
|
|
/// component matching [shouldAnnotate] predicate has correct metadata.
|
|
void validate(Component p, NodePredicate shouldAnnotate) {
|
|
globalDebuggingNames = new NameSystem();
|
|
final repository = p.metadata[TestMetadataRepository.kTag]!;
|
|
p.accept(
|
|
new Visitor(shouldAnnotate, (node) {
|
|
final m = repository.mapping[node];
|
|
final expected = new Metadata.forNode(node);
|
|
|
|
expect(m, isNotNull);
|
|
expect(m.string, equals(expected.string));
|
|
expect(m.member, equals(expected.member));
|
|
expect(m.type, equals(expected.type));
|
|
}),
|
|
);
|
|
}
|
|
|
|
Component fromBinary(Uint8List bytes) {
|
|
var component = new Component();
|
|
component.addMetadataRepository(new TestMetadataRepository());
|
|
new BinaryBuilderWithMetadata(bytes).readComponent(component);
|
|
return component;
|
|
}
|
|
|
|
Uint8List toBinary(Component p) {
|
|
final sink = new BytesBuilderSink();
|
|
new BinaryPrinter(sink).writeComponentFile(p);
|
|
return sink.builder.takeBytes();
|
|
}
|
|
|
|
void main() async {
|
|
bool anyNode(TreeNode node) => true;
|
|
bool onlyMethods(TreeNode node) =>
|
|
node is Procedure &&
|
|
node.kind == ProcedureKind.Method &&
|
|
node.enclosingClass != null;
|
|
|
|
final Uri platform = computePlatformBinariesLocation(
|
|
forceBuildDir: true,
|
|
).resolve("vm_platform.dill");
|
|
final Uint8List platformBinary = await new File(
|
|
platform.toFilePath(),
|
|
).readAsBytes();
|
|
|
|
Future<void> testRoundTrip(
|
|
Uint8List Function(Uint8List) binaryTransformer,
|
|
NodePredicate shouldAnnotate,
|
|
) async {
|
|
final component = fromBinary(platformBinary);
|
|
annotate(component, shouldAnnotate);
|
|
validate(component, shouldAnnotate);
|
|
expect(
|
|
component.metadata[TestMetadataRepository.kTag]!.mapping.length,
|
|
greaterThan(0),
|
|
);
|
|
|
|
final annotatedComponentBinary = binaryTransformer(toBinary(component));
|
|
final annotatedComponentFromBinary = fromBinary(annotatedComponentBinary);
|
|
validate(annotatedComponentFromBinary, shouldAnnotate);
|
|
expect(
|
|
annotatedComponentFromBinary
|
|
.metadata[TestMetadataRepository.kTag]!
|
|
.mapping
|
|
.length,
|
|
greaterThan(0),
|
|
);
|
|
}
|
|
|
|
test('annotate-serialize-deserialize-validate', () async {
|
|
await testRoundTrip((binary) => binary, anyNode);
|
|
});
|
|
|
|
test('annotate-serialize-deserialize-validate-only-methods', () async {
|
|
await testRoundTrip((binary) => binary, onlyMethods);
|
|
});
|
|
|
|
test('annotate-serialize-deserialize-twice-then-validate', () async {
|
|
// This test validates that serializing a component that was just
|
|
// deserialized (without visiting anything) works.
|
|
await testRoundTrip((binary) => toBinary(fromBinary(binary)), anyNode);
|
|
});
|
|
|
|
test(
|
|
'annotate-serialize-deserialize-twice-then-validate-only-methods',
|
|
() async {
|
|
// This test validates that serializing a component that was just
|
|
// deserialized (without visiting anything) works.
|
|
await testRoundTrip(
|
|
(binary) => toBinary(fromBinary(binary)),
|
|
onlyMethods,
|
|
);
|
|
},
|
|
);
|
|
}
|