[CFE] Check class hierarchy in incremental compiler test
Change-Id: I963716d36bec213739bbc266f9494885edd0aa08 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/133104 Commit-Queue: Jens Johansen <jensj@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
5e38b59740
commit
3f3d3dfa12
@@ -40,12 +40,14 @@ import 'package:front_end/src/fasta/incremental_compiler.dart'
|
||||
|
||||
import 'package:front_end/src/fasta/incremental_serializer.dart'
|
||||
show IncrementalSerializer;
|
||||
import 'package:front_end/src/fasta/kernel/kernel_api.dart';
|
||||
|
||||
import 'package:front_end/src/fasta/kernel/utils.dart' show ByteSink;
|
||||
|
||||
import 'package:kernel/binary/ast_from_binary.dart' show BinaryBuilder;
|
||||
|
||||
import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
|
||||
import 'package:kernel/class_hierarchy.dart';
|
||||
|
||||
import 'package:kernel/kernel.dart'
|
||||
show
|
||||
@@ -55,6 +57,7 @@ import 'package:kernel/kernel.dart'
|
||||
Field,
|
||||
Library,
|
||||
LibraryDependency,
|
||||
Member,
|
||||
Name,
|
||||
Procedure;
|
||||
|
||||
@@ -608,25 +611,8 @@ Future<Null> newWorldTest(
|
||||
}
|
||||
}
|
||||
|
||||
Uri uri = data.loadedFrom
|
||||
.resolve(data.loadedFrom.pathSegments.last + ".world.$worldNum.expect");
|
||||
String expected;
|
||||
File file = new File.fromUri(uri);
|
||||
if (context.updateExpectations) {
|
||||
file.writeAsStringSync(actualSerialized);
|
||||
}
|
||||
if (file.existsSync()) {
|
||||
expected = file.readAsStringSync();
|
||||
}
|
||||
if (context.updateExpectations) {
|
||||
file.writeAsStringSync(actualSerialized);
|
||||
} else if (expected != actualSerialized) {
|
||||
String extra = "";
|
||||
if (expected == null) extra = "Expect file did not exist.\n";
|
||||
throw "${extra}Unexpected serialized representation. "
|
||||
"Fix or update $uri to contain the below:\n\n"
|
||||
"$actualSerialized";
|
||||
}
|
||||
checkExpectFile(data, worldNum, context, actualSerialized);
|
||||
checkClassHierarchy(compiler, component, data, worldNum, context);
|
||||
|
||||
int nonSyntheticLibraries = countNonSyntheticLibraries(component);
|
||||
int nonSyntheticPlatformLibraries =
|
||||
@@ -848,6 +834,166 @@ Future<Null> newWorldTest(
|
||||
}
|
||||
}
|
||||
|
||||
void checkExpectFile(
|
||||
TestData data, int worldNum, Context context, String actualSerialized) {
|
||||
Uri uri = data.loadedFrom
|
||||
.resolve(data.loadedFrom.pathSegments.last + ".world.$worldNum.expect");
|
||||
String expected;
|
||||
File file = new File.fromUri(uri);
|
||||
if (file.existsSync()) {
|
||||
expected = file.readAsStringSync();
|
||||
}
|
||||
if (expected != actualSerialized) {
|
||||
if (context.updateExpectations) {
|
||||
file.writeAsStringSync(actualSerialized);
|
||||
} else {
|
||||
String extra = "";
|
||||
if (expected == null) extra = "Expect file did not exist.\n";
|
||||
throw "${extra}Unexpected serialized representation. "
|
||||
"Fix or update $uri to contain the below:\n\n"
|
||||
"$actualSerialized";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that the class hierarchy is up-to-date with reality.
|
||||
///
|
||||
/// This has the option to do expect files, but it's disabled by default
|
||||
/// while we're trying to figure out if it's useful or not.
|
||||
void checkClassHierarchy(TestIncrementalCompiler compiler, Component component,
|
||||
TestData data, int worldNum, Context context,
|
||||
{bool checkExpectFile: false}) {
|
||||
ClassHierarchy classHierarchy = compiler.getClassHierarchy();
|
||||
if (classHierarchy is! ClosedWorldClassHierarchy) {
|
||||
throw "Expected the class hierarchy to be ClosedWorldClassHierarchy "
|
||||
"but it wasn't. It was ${classHierarchy.runtimeType}";
|
||||
}
|
||||
List<ForTestingClassInfo> classHierarchyData =
|
||||
(classHierarchy as ClosedWorldClassHierarchy).getTestingClassInfo();
|
||||
Map<Class, ForTestingClassInfo> classHierarchyMap =
|
||||
new Map<Class, ForTestingClassInfo>();
|
||||
for (ForTestingClassInfo info in classHierarchyData) {
|
||||
if (classHierarchyMap[info.classNode] != null) {
|
||||
throw "Two entries for ${info.classNode}";
|
||||
}
|
||||
classHierarchyMap[info.classNode] = info;
|
||||
}
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (Library library in component.libraries) {
|
||||
if (library.importUri.scheme == "dart") continue;
|
||||
sb.writeln("Library ${library.importUri}");
|
||||
for (Class c in library.classes) {
|
||||
sb.writeln(" - Class ${c.name}");
|
||||
ForTestingClassInfo info = classHierarchyMap[c];
|
||||
if (info == null) {
|
||||
throw "Didn't find any class hierarchy info for $c";
|
||||
}
|
||||
if (info.lazyDeclaredGettersAndCalls != null) {
|
||||
sb.writeln(" - lazyDeclaredGettersAndCalls:");
|
||||
for (Member member in info.lazyDeclaredGettersAndCalls) {
|
||||
sb.writeln(" - ${member.name.name}");
|
||||
}
|
||||
|
||||
// Expect these to be the same as in the class.
|
||||
Set<Member> members = info.lazyDeclaredGettersAndCalls.toSet();
|
||||
for (Field f in c.fields) {
|
||||
if (f.isStatic) continue;
|
||||
if (!f.hasImplicitGetter) continue;
|
||||
if (!members.remove(f)) {
|
||||
throw "Didn't find ${f.name.name} in lazyDeclaredGettersAndCalls "
|
||||
"for ${c.name} in ${library.importUri}";
|
||||
}
|
||||
}
|
||||
for (Procedure p in c.procedures) {
|
||||
if (p.isStatic) continue;
|
||||
if (p.isSetter) continue;
|
||||
if (!members.remove(p)) {
|
||||
throw "Didn't find ${p.name.name} in lazyDeclaredGettersAndCalls "
|
||||
"for ${c.name} in ${library.importUri}";
|
||||
}
|
||||
}
|
||||
if (members.isNotEmpty) {
|
||||
throw "Still have ${members.map((m) => m.name.name)} left "
|
||||
"for ${c.name} in ${library.importUri}";
|
||||
}
|
||||
}
|
||||
if (info.lazyDeclaredSetters != null) {
|
||||
sb.writeln(" - lazyDeclaredSetters:");
|
||||
for (Member member in info.lazyDeclaredSetters) {
|
||||
sb.writeln(" - ${member.name.name}");
|
||||
}
|
||||
|
||||
// Expect these to be the same as in the class.
|
||||
Set<Member> members = info.lazyDeclaredSetters.toSet();
|
||||
for (Field f in c.fields) {
|
||||
if (f.isStatic) continue;
|
||||
if (!f.hasImplicitSetter) continue;
|
||||
if (!members.remove(f)) {
|
||||
throw "Didn't find $f in lazyDeclaredSetters for $c";
|
||||
}
|
||||
}
|
||||
for (Procedure p in c.procedures) {
|
||||
if (p.isStatic) continue;
|
||||
if (!p.isSetter) continue;
|
||||
if (!members.remove(p)) {
|
||||
throw "Didn't find $p in lazyDeclaredSetters for $c";
|
||||
}
|
||||
}
|
||||
if (members.isNotEmpty) {
|
||||
throw "Still have ${members.map((m) => m.name.name)} left "
|
||||
"for ${c.name} in ${library.importUri}";
|
||||
}
|
||||
}
|
||||
if (info.lazyImplementedGettersAndCalls != null) {
|
||||
sb.writeln(" - lazyImplementedGettersAndCalls:");
|
||||
for (Member member in info.lazyImplementedGettersAndCalls) {
|
||||
sb.writeln(" - ${member.name.name}");
|
||||
}
|
||||
}
|
||||
if (info.lazyImplementedSetters != null) {
|
||||
sb.writeln(" - lazyImplementedSetters:");
|
||||
for (Member member in info.lazyImplementedSetters) {
|
||||
sb.writeln(" - ${member.name.name}");
|
||||
}
|
||||
}
|
||||
if (info.lazyInterfaceGettersAndCalls != null) {
|
||||
sb.writeln(" - lazyInterfaceGettersAndCalls:");
|
||||
for (Member member in info.lazyInterfaceGettersAndCalls) {
|
||||
sb.writeln(" - ${member.name.name}");
|
||||
}
|
||||
}
|
||||
if (info.lazyInterfaceSetters != null) {
|
||||
sb.writeln(" - lazyInterfaceSetters:");
|
||||
for (Member member in info.lazyInterfaceSetters) {
|
||||
sb.writeln(" - ${member.name.name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (checkExpectFile) {
|
||||
String actualClassHierarchy = sb.toString();
|
||||
Uri uri = data.loadedFrom.resolve(data.loadedFrom.pathSegments.last +
|
||||
".world.$worldNum.class_hierarchy.expect");
|
||||
String expected;
|
||||
File file = new File.fromUri(uri);
|
||||
if (file.existsSync()) {
|
||||
expected = file.readAsStringSync();
|
||||
}
|
||||
if (expected != actualClassHierarchy) {
|
||||
if (context.updateExpectations) {
|
||||
file.writeAsStringSync(actualClassHierarchy);
|
||||
} else {
|
||||
String extra = "";
|
||||
if (expected == null) extra = "Expect file did not exist.\n";
|
||||
throw "${extra}Unexpected serialized representation. "
|
||||
"Fix or update $uri to contain the below:\n\n"
|
||||
"$actualClassHierarchy";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkErrorsAndWarnings(
|
||||
Set<String> prevFormattedErrors,
|
||||
Set<String> formattedErrors,
|
||||
@@ -899,14 +1045,14 @@ List<int> checkIncrementalSerialization(
|
||||
throw "Incremental serialization didn't remove any libraries!";
|
||||
}
|
||||
if (librariesAfter < librariesBefore && sink.builder.isEmpty) {
|
||||
throw "Incremental serialization din't output any bytes, "
|
||||
throw "Incremental serialization didn't output any bytes, "
|
||||
"but did remove libraries";
|
||||
} else if (librariesAfter == librariesBefore && !sink.builder.isEmpty) {
|
||||
throw "Incremental serialization did output bytes, "
|
||||
"but didn't remove libraries";
|
||||
}
|
||||
if (librariesAfter < librariesBefore) {
|
||||
// If we actually did incremenally serialize anything, check the output!
|
||||
// If we actually did incrementally serialize anything, check the output!
|
||||
BinaryPrinter printer = new BinaryPrinter(sink);
|
||||
printer.writeComponentFile(c);
|
||||
List<int> bytes = sink.builder.takeBytes();
|
||||
@@ -1389,10 +1535,10 @@ class TestIncrementalCompiler extends IncrementalCompiler {
|
||||
void doSimulateTransformer(Component c) {
|
||||
for (Library lib in c.libraries) {
|
||||
if (lib.fields
|
||||
.where((f) => f.name.name == "lalala_SimulateTransformer")
|
||||
.where((f) => f.name.name == "unique_SimulateTransformer")
|
||||
.toList()
|
||||
.isNotEmpty) continue;
|
||||
Name fieldName = new Name("lalala_SimulateTransformer");
|
||||
Name fieldName = new Name("unique_SimulateTransformer");
|
||||
Field field = new Field(fieldName,
|
||||
isFinal: true,
|
||||
reference: lib.reference.canonicalName
|
||||
@@ -1401,10 +1547,10 @@ void doSimulateTransformer(Component c) {
|
||||
lib.addMember(field);
|
||||
for (Class c in lib.classes) {
|
||||
if (c.fields
|
||||
.where((f) => f.name.name == "lalala_SimulateTransformer")
|
||||
.where((f) => f.name.name == "unique_SimulateTransformer")
|
||||
.toList()
|
||||
.isNotEmpty) continue;
|
||||
fieldName = new Name("lalala_SimulateTransformer");
|
||||
fieldName = new Name("unique_SimulateTransformer");
|
||||
field = new Field(fieldName,
|
||||
isFinal: true,
|
||||
reference: c.reference.canonicalName
|
||||
|
||||
@@ -57,6 +57,7 @@ boo
|
||||
bootstrap
|
||||
bots
|
||||
bowtie
|
||||
brand
|
||||
brave
|
||||
brown
|
||||
builddir
|
||||
@@ -111,6 +112,7 @@ dartfile
|
||||
dashes
|
||||
day
|
||||
db
|
||||
debugger
|
||||
decrease
|
||||
decrements
|
||||
def
|
||||
@@ -190,6 +192,7 @@ func
|
||||
futures
|
||||
gallery
|
||||
gamma
|
||||
gave
|
||||
gc
|
||||
gen
|
||||
generators
|
||||
@@ -201,6 +204,7 @@ gulp
|
||||
gunk
|
||||
hackish
|
||||
harness
|
||||
helper2
|
||||
hest
|
||||
heuristics
|
||||
hi
|
||||
@@ -276,6 +280,8 @@ moo
|
||||
mx
|
||||
mysdk
|
||||
negatable
|
||||
newest
|
||||
newworld
|
||||
ninja
|
||||
nonexisting
|
||||
noo
|
||||
@@ -359,6 +365,8 @@ shipped
|
||||
shortest
|
||||
shot
|
||||
signalled
|
||||
slight
|
||||
smoke
|
||||
somehow
|
||||
spans
|
||||
spell
|
||||
@@ -434,6 +442,7 @@ whitelist
|
||||
whitelisting
|
||||
wins
|
||||
workflow
|
||||
worlds
|
||||
ws
|
||||
x's
|
||||
xxx
|
||||
|
||||
@@ -35,10 +35,10 @@ worlds:
|
||||
expectedContent:
|
||||
org-dartlang-test:///main.dart:
|
||||
- Procedure main
|
||||
- Field lalala_SimulateTransformer
|
||||
- Field unique_SimulateTransformer
|
||||
package:foo/foo.dart:
|
||||
- Field foo
|
||||
- Field lalala_SimulateTransformer
|
||||
- Field unique_SimulateTransformer
|
||||
neededDillLibraries:
|
||||
- package:foo/foo.dart
|
||||
- entry: main.dart
|
||||
@@ -61,7 +61,7 @@ worlds:
|
||||
expectedContent:
|
||||
org-dartlang-test:///main.dart:
|
||||
- Procedure main
|
||||
- Field lalala_SimulateTransformer
|
||||
- Field unique_SimulateTransformer
|
||||
package:foo/foo.dart:
|
||||
- Field foo2
|
||||
- Field lalala_SimulateTransformer
|
||||
- Field unique_SimulateTransformer
|
||||
|
||||
+2
-2
@@ -2,13 +2,13 @@ main = <No Member>;
|
||||
library from "package:foo/foo.dart" as foo {
|
||||
|
||||
static field dart.core::bool* foo = true;
|
||||
final field dynamic lalala_SimulateTransformer /* from null */;
|
||||
final field dynamic unique_SimulateTransformer /* from null */;
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "package:foo/foo.dart";
|
||||
|
||||
final field dynamic lalala_SimulateTransformer /* from null */;
|
||||
final field dynamic unique_SimulateTransformer /* from null */;
|
||||
static method main() → dynamic {
|
||||
dart.core::print(foo::foo);
|
||||
}
|
||||
|
||||
+2
-2
@@ -2,13 +2,13 @@ main = <No Member>;
|
||||
library from "package:foo/foo.dart" as foo {
|
||||
|
||||
static field dart.core::bool* foo2 = true;
|
||||
final field dynamic lalala_SimulateTransformer /* from null */;
|
||||
final field dynamic unique_SimulateTransformer /* from null */;
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "package:foo/foo.dart";
|
||||
|
||||
final field dynamic lalala_SimulateTransformer /* from null */;
|
||||
final field dynamic unique_SimulateTransformer /* from null */;
|
||||
static method main() → dynamic {
|
||||
dart.core::print(foo::foo2);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
# Status file for the test suite ../test/incremental_load_from_dill_test.dart.
|
||||
|
||||
ffi_01: Crash # Class hierarchy is out of date.
|
||||
ffi_02: Crash # Class hierarchy is out of date.
|
||||
|
||||
no_outline_change_1: Crash # Doesn't work on DillLibraryBuilders.
|
||||
no_outline_change_2: Crash # Doesn't work on DillLibraryBuilders.
|
||||
no_outline_change_6: Crash # Doesn't work on DillLibraryBuilders.
|
||||
|
||||
@@ -284,8 +284,6 @@
|
||||
"test/fasta/super_mixins_test\\.dart$",
|
||||
"test/fasta/types/subtypes_benchmark\\.dart$",
|
||||
"test/fasta/unlinked_scope_test\\.dart$",
|
||||
"test/incremental_load_from_dill_suite\\.dart$",
|
||||
"test/incremental_load_from_invalid_dill_test\\.dart$",
|
||||
"test/memory_file_system_test\\.dart$",
|
||||
"test/scanner_fasta_test\\.dart$",
|
||||
"test/scanner_test\\.dart$",
|
||||
|
||||
@@ -451,6 +451,14 @@ class ClosedWorldClassHierarchy implements ClassHierarchy {
|
||||
final Map<Class, _ClassInfo> _infoMap =
|
||||
new LinkedHashMap<Class, _ClassInfo>();
|
||||
|
||||
List<ForTestingClassInfo> getTestingClassInfo() {
|
||||
List<ForTestingClassInfo> result = new List<ForTestingClassInfo>();
|
||||
for (_ClassInfo info in _infoMap.values) {
|
||||
result.add(new ForTestingClassInfo._(info));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
_ClassInfo infoFor(Class c) {
|
||||
_ClassInfo info = _infoMap[c];
|
||||
info?.used = true;
|
||||
@@ -1444,6 +1452,25 @@ int _intervalListSize(Uint32List intervalList) {
|
||||
return size;
|
||||
}
|
||||
|
||||
class ForTestingClassInfo {
|
||||
final Class classNode;
|
||||
final List<Member> lazyDeclaredGettersAndCalls;
|
||||
final List<Member> lazyDeclaredSetters;
|
||||
final List<Member> lazyImplementedGettersAndCalls;
|
||||
final List<Member> lazyImplementedSetters;
|
||||
final List<Member> lazyInterfaceGettersAndCalls;
|
||||
final List<Member> lazyInterfaceSetters;
|
||||
|
||||
ForTestingClassInfo._(_ClassInfo c)
|
||||
: classNode = c.classNode,
|
||||
lazyDeclaredGettersAndCalls = c.lazyDeclaredGettersAndCalls,
|
||||
lazyDeclaredSetters = c.lazyDeclaredSetters,
|
||||
lazyImplementedGettersAndCalls = c.lazyImplementedGettersAndCalls,
|
||||
lazyImplementedSetters = c.lazyImplementedSetters,
|
||||
lazyInterfaceGettersAndCalls = c.lazyInterfaceGettersAndCalls,
|
||||
lazyInterfaceSetters = c.lazyInterfaceSetters;
|
||||
}
|
||||
|
||||
class _ClassInfo {
|
||||
bool used = false;
|
||||
final Class classNode;
|
||||
|
||||
Reference in New Issue
Block a user