34fb48bb8a
Migrates libraries dependent only on already migrated libraries. Change-Id: I0e85ee8dbc2afce031b92e0009e71c206a55af28 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/179502 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Jens Johansen <jensj@google.com>
160 lines
5.8 KiB
Dart
160 lines
5.8 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.
|
|
|
|
// @dart = 2.9
|
|
|
|
import 'package:kernel/kernel.dart';
|
|
import 'package:kernel/class_hierarchy.dart';
|
|
import 'package:kernel/core_types.dart';
|
|
import 'package:test/test.dart';
|
|
import 'class_hierarchy_basic.dart';
|
|
import 'dart:io';
|
|
import 'dart:math';
|
|
import 'self_check_util.dart';
|
|
|
|
main(List<String> args) {
|
|
runSelfCheck(args, (String filename) {
|
|
testClassHierarchyOnComponent(loadComponentFromBinary(filename));
|
|
});
|
|
}
|
|
|
|
void testClassHierarchyOnComponent(Component component, {bool verbose: false}) {
|
|
BasicClassHierarchy basic = new BasicClassHierarchy(component);
|
|
CoreTypes coreTypes = new CoreTypes(component);
|
|
ClosedWorldClassHierarchy classHierarchy =
|
|
new ClassHierarchy(component, coreTypes);
|
|
int total = classHierarchy.numberOfClasses;
|
|
int progress = 0;
|
|
for (var class1 in classHierarchy.classes) {
|
|
for (var class2 in classHierarchy.classes) {
|
|
bool isSubclass = classHierarchy.isSubclassOf(class1, class2);
|
|
bool isSubtype = classHierarchy.isSubtypeOf(class1, class2);
|
|
var asInstance = classHierarchy.getClassAsInstanceOf(class1, class2);
|
|
if (isSubclass != basic.isSubclassOf(class1, class2)) {
|
|
fail('isSubclassOf(${class1.name}, ${class2.name}) returned '
|
|
'$isSubclass but should be ${!isSubclass}');
|
|
}
|
|
if (isSubtype != basic.isSubtypeOf(class1, class2)) {
|
|
fail('isSubtypeOf(${class1.name}, ${class2.name}) returned '
|
|
'$isSubtype but should be ${!isSubtype}');
|
|
}
|
|
if (asInstance != basic.getClassAsInstanceOf(class1, class2)) {
|
|
fail('asInstanceOf(${class1.name}, ${class2.name}) returned '
|
|
'$asInstance but should be '
|
|
'${basic.getClassAsInstanceOf(class1, class2)}');
|
|
}
|
|
}
|
|
++progress;
|
|
if (verbose) {
|
|
stdout.write('\rSubclass queries ${100 * progress ~/ total}%');
|
|
}
|
|
}
|
|
Set<Name> names = new Set<Name>();
|
|
for (var classNode in classHierarchy.classes) {
|
|
for (var member in classNode.members) {
|
|
names.add(member.name);
|
|
}
|
|
}
|
|
List<Name> nameList = names.toList();
|
|
progress = 0;
|
|
for (var classNode in classHierarchy.classes) {
|
|
Iterable<Name> candidateNames = <Iterable<Name>>[
|
|
basic.gettersAndCalls[classNode].keys,
|
|
basic.setters[classNode].keys,
|
|
pickRandom(nameList, 100)
|
|
].expand((x) => x);
|
|
for (Name name in candidateNames) {
|
|
Member expectedGetter =
|
|
basic.getDispatchTarget(classNode, name, setter: false);
|
|
Member expectedSetter =
|
|
basic.getDispatchTarget(classNode, name, setter: true);
|
|
Member actualGetter =
|
|
classHierarchy.getDispatchTarget(classNode, name, setter: false);
|
|
Member actualSetter =
|
|
classHierarchy.getDispatchTarget(classNode, name, setter: true);
|
|
if (actualGetter != expectedGetter) {
|
|
fail('lookupGetter($classNode, $name) returned '
|
|
'$actualGetter but should be $expectedGetter');
|
|
}
|
|
if (actualSetter != expectedSetter) {
|
|
fail('lookupSetter($classNode, $name) returned '
|
|
'$actualSetter but should be $expectedSetter');
|
|
}
|
|
}
|
|
++progress;
|
|
if (verbose) {
|
|
stdout.write('\rDispatch queries ${100 * progress ~/ total}%');
|
|
}
|
|
}
|
|
progress = 0;
|
|
for (var classNode in classHierarchy.classes) {
|
|
Iterable<Name> candidateNames = [
|
|
basic.interfaceGettersAndCalls[classNode].keys,
|
|
basic.interfaceSetters[classNode].keys,
|
|
pickRandom(nameList, 100)
|
|
].expand((x) => x);
|
|
for (Name name in candidateNames) {
|
|
Member expectedGetter =
|
|
basic.getInterfaceMember(classNode, name, setter: false);
|
|
Member expectedSetter =
|
|
basic.getInterfaceMember(classNode, name, setter: true);
|
|
Member actualGetter =
|
|
classHierarchy.getInterfaceMember(classNode, name, setter: false);
|
|
Member actualSetter =
|
|
classHierarchy.getInterfaceMember(classNode, name, setter: true);
|
|
if (actualGetter != expectedGetter) {
|
|
fail('getInterfaceMember($classNode, $name) returned '
|
|
'$actualGetter but should be $expectedGetter');
|
|
}
|
|
if (actualSetter != expectedSetter) {
|
|
fail('getInterfaceMember($classNode, $name, setter: true) '
|
|
'returned $actualSetter but should be $expectedSetter');
|
|
}
|
|
}
|
|
++progress;
|
|
if (verbose) {
|
|
stdout.write('\rInterface queries ${100 * progress ~/ total}%');
|
|
}
|
|
}
|
|
for (var classNode in classHierarchy.classes) {
|
|
String getHash(member, superMember, setter) {
|
|
String eq = setter ? '=' : '';
|
|
return '$member$eq overrides $superMember$eq';
|
|
}
|
|
|
|
Set<String> expectedOverrides = new Set<String>();
|
|
basic.forEachOverridePair(classNode, (member, superMember, setter) {
|
|
expectedOverrides.add(getHash(member, superMember, setter));
|
|
});
|
|
Set<String> actualOverrides = new Set<String>();
|
|
classHierarchy.forEachOverridePair(classNode,
|
|
(member, superMember, setter) {
|
|
actualOverrides.add(getHash(member, superMember, setter));
|
|
});
|
|
for (var actual in actualOverrides) {
|
|
if (!expectedOverrides.contains(actual)) {
|
|
fail("forEachOverridePair($classNode) should not report that $actual");
|
|
}
|
|
}
|
|
for (var expected in expectedOverrides) {
|
|
if (!actualOverrides.contains(expected)) {
|
|
fail("forEachOverridePair($classNode) did not report that $expected");
|
|
}
|
|
}
|
|
}
|
|
if (verbose) {
|
|
print('\rProgress 100%. Done.');
|
|
}
|
|
}
|
|
|
|
var random = new Random(12345);
|
|
|
|
List<T> pickRandom<T>(List<T> items, int n) {
|
|
var result = <T>[];
|
|
for (int i = 0; i < n; ++i) {
|
|
result.add(items[random.nextInt(items.length)]);
|
|
}
|
|
return result;
|
|
}
|