[CFE] Fixup outline extraction
The outline extraction suite - as it turns out - wasn't run.
This has caused the tests to start fail for various reasons without
anyone noticing.
This CL enabled the suite; fixes up the failures; adds a few more tests
and fixes issues shown by those as well.
Change-Id: Iba2145abc319609e03c07d9a5141402b811b4959
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/245981
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
diff --git a/pkg/front_end/lib/src/fasta/util/outline_extractor.dart b/pkg/front_end/lib/src/fasta/util/outline_extractor.dart
index d1f5d0a..011171f 100644
--- a/pkg/front_end/lib/src/fasta/util/outline_extractor.dart
+++ b/pkg/front_end/lib/src/fasta/util/outline_extractor.dart
@@ -78,9 +78,18 @@
..packagesFileUri = packages
..sdkSummary = platform
..sdkRoot = sdk;
- ProcessedOptions pOptions =
+ ProcessedOptions processedOptions =
new ProcessedOptions(options: options, inputs: entryPointUris);
- return CompilerContext.runWithOptions(pOptions, (CompilerContext c) async {
+ return extractOutlineWithProcessedOptions(entryPointUris,
+ verbosityLevel: verbosityLevel, processedOptions: processedOptions);
+}
+
+Future<Map<Uri, String>> extractOutlineWithProcessedOptions(
+ List<Uri> entryPointUris,
+ {int verbosityLevel: 0,
+ required ProcessedOptions processedOptions}) {
+ return CompilerContext.runWithOptions(processedOptions,
+ (CompilerContext c) async {
FileSystem fileSystem = c.options.fileSystem;
UriTranslator uriTranslator = await c.options.getUriTranslator();
_Processor processor =
@@ -208,17 +217,26 @@
await _premarkTopLevel(worklist, closed, partTopLevel);
}
} else if (child is Export) {
- for (Uri importedUri in child.uris) {
- if (!importedUri.isScheme("dart")) {
- TopLevel exportTopLevel =
- parsed[importedUri] ?? await preprocessUri(importedUri);
- await _premarkTopLevel(worklist, closed, exportTopLevel);
- }
+ for (Uri exportedUri in child.uris) {
+ if (exportedUri.isScheme("dart")) continue;
+ // E.g. conditional exports could point to non-existing files.
+ if (!await _exists(exportedUri)) continue;
+ TopLevel exportTopLevel =
+ parsed[exportedUri] ?? await preprocessUri(exportedUri);
+ await _premarkTopLevel(worklist, closed, exportTopLevel);
}
}
}
}
+ Future<bool> _exists(Uri uri) {
+ Uri fileUri = uri;
+ if (fileUri.isScheme("package")) {
+ fileUri = uriTranslator.translate(fileUri)!;
+ }
+ return fileSystem.entityForUri(fileUri).exists();
+ }
+
Future<List<TopLevel>> _preprocessImportsAsNeeded(
Map<TopLevel, List<TopLevel>> imports, TopLevel topLevel) async {
List<TopLevel>? imported = imports[topLevel];
@@ -230,11 +248,13 @@
if (child is Import) {
child.marked = Coloring.Marked;
for (Uri importedUri in child.uris) {
- if (!importedUri.isScheme("dart")) {
- TopLevel importedTopLevel =
- parsed[importedUri] ?? await preprocessUri(importedUri);
- imported.add(importedTopLevel);
- }
+ if (importedUri.isScheme("dart")) continue;
+ // E.g. conditional imports could point to non-existing files.
+ if (!await _exists(importedUri)) continue;
+
+ TopLevel importedTopLevel =
+ parsed[importedUri] ?? await preprocessUri(importedUri);
+ imported.add(importedTopLevel);
}
} else if (child is PartOf) {
child.marked = Coloring.Marked;
@@ -399,10 +419,11 @@
} else if (child is Export) {
child.marked = Coloring.Marked;
// do stuff to export.
- for (Uri importedUri in child.uris) {
- if (!importedUri.isScheme("dart")) {
- other = parsed[importedUri] ?? await preprocessUri(importedUri);
- }
+ for (Uri exportedUri in child.uris) {
+ if (exportedUri.isScheme("dart")) continue;
+ // E.g. conditional exports could point to non-existing files.
+ if (!await _exists(exportedUri)) continue;
+ other = parsed[exportedUri] ?? await preprocessUri(exportedUri);
}
} else if (child is Extension) {
// TODO: Maybe put on a list to process later and only include if
@@ -645,16 +666,12 @@
currentContainer.addChild(classFactoryMethod, map);
log("Hello from factory method ${ids.first.token}.${ids.last.token}");
} else {
- Container findTopLevel = currentContainer;
- while (findTopLevel is! TopLevel) {
- findTopLevel = findTopLevel.parent!;
- }
- String src = findTopLevel.sourceText
- .substring(startInclusive.charOffset, endInclusive.charEnd);
- throw "Unexpected identifiers in class factory method: $ids "
- "(${ids.map((e) => e.token.lexeme).toList()}) --- "
- "error on source ${src} --- "
- "${node.children}";
+ debugDumpSource(
+ startInclusive,
+ endInclusive,
+ node,
+ "Unexpected identifiers in class factory method: $ids "
+ "(${ids.map((e) => e.token.lexeme).toList()}).");
}
super.visitClassFactoryMethod(node, startInclusive, endInclusive);
@@ -678,20 +695,7 @@
ClassMethodEnd node, Token startInclusive, Token endInclusive) {
assert(currentContainer is Class);
- String identifier;
- try {
- identifier = node.getNameIdentifier();
- } catch (e) {
- Container findTopLevel = currentContainer;
- while (findTopLevel is! TopLevel) {
- findTopLevel = findTopLevel.parent!;
- }
- String src = findTopLevel.sourceText
- .substring(startInclusive.charOffset, endInclusive.charEnd);
- throw "Unexpected identifiers in visitClassMethod --- "
- "error on source ${src} --- "
- "${node.children}";
- }
+ String identifier = node.getNameIdentifier();
ClassMethod classMethod =
new ClassMethod(node, identifier, startInclusive, endInclusive);
currentContainer.addChild(classMethod, map);
@@ -701,18 +705,16 @@
@override
void visitEnum(EnumEnd node, Token startInclusive, Token endInclusive) {
+ TopLevelDeclarationEnd parent = node.parent! as TopLevelDeclarationEnd;
+ IdentifierHandle identifier = parent.getIdentifier();
List<IdentifierHandle> ids = node.getIdentifiers();
- Enum e = new Enum(
- node,
- ids.first.token.lexeme,
- ids.skip(1).map((e) => e.token.lexeme).toList(),
- startInclusive,
- endInclusive);
+ Enum e = new Enum(node, identifier.token.lexeme,
+ ids.map((e) => e.token.lexeme).toList(), startInclusive, endInclusive);
currentContainer.addChild(e, map);
- log("Hello from enum ${ids.first.token} with content "
- "${ids.skip(1).map((e) => e.token).join(", ")}");
+ log("Hello from enum ${identifier.token} with content "
+ "${ids.map((e) => e.token).join(", ")}");
super.visitEnum(node, startInclusive, endInclusive);
}
@@ -790,6 +792,19 @@
super.visitExtensionMethod(node, startInclusive, endInclusive);
}
+ void debugDumpSource(Token startInclusive, Token endInclusive,
+ ParserAstNode node, String message) {
+ Container findTopLevel = currentContainer;
+ while (findTopLevel is! TopLevel) {
+ findTopLevel = findTopLevel.parent!;
+ }
+ String src = findTopLevel.sourceText
+ .substring(startInclusive.charOffset, endInclusive.charEnd);
+ throw "Error on source ${src} --- \n\n"
+ "$message ---\n\n"
+ "${node.children}";
+ }
+
@override
void visitImport(ImportEnd node, Token startInclusive, Token? endInclusive) {
IdentifierHandle? prefix = node.getImportPrefix();
@@ -904,6 +919,7 @@
void visitPartOf(PartOfEnd node, Token startInclusive, Token endInclusive) {
// We'll assume we've gotten here via a "part" so we'll ignore that for now.
// TODO: partOfUri could - in an error case - be null.
+ if (partOfUri == null) throw "partOfUri is null -- uri $uri";
PartOf partof = new PartOf(node, partOfUri!, startInclusive, endInclusive);
partof.marked = Coloring.Marked;
currentContainer.addChild(partof, map);
diff --git a/pkg/front_end/lib/src/fasta/util/parser_ast.dart b/pkg/front_end/lib/src/fasta/util/parser_ast.dart
index 3b131cf..f30a4a8 100644
--- a/pkg/front_end/lib/src/fasta/util/parser_ast.dart
+++ b/pkg/front_end/lib/src/fasta/util/parser_ast.dart
@@ -1293,7 +1293,8 @@
for (ParserAstNode child in children!) {
if (child is TypeHandle ||
child is NoTypeHandle ||
- child is VoidKeywordHandle) {
+ child is VoidKeywordHandle ||
+ child is FunctionTypeEnd) {
foundType = true;
}
if (foundType && child is IdentifierHandle) {
@@ -1312,7 +1313,8 @@
for (ParserAstNode child in children!) {
if (child is TypeHandle ||
child is NoTypeHandle ||
- child is VoidKeywordHandle) {
+ child is VoidKeywordHandle ||
+ child is FunctionTypeEnd) {
foundType = true;
}
if (foundType && child is IdentifierHandle) {
diff --git a/pkg/front_end/outline_extraction_testcases/.packages b/pkg/front_end/outline_extraction_testcases/.packages
new file mode 100644
index 0000000..68325fa
--- /dev/null
+++ b/pkg/front_end/outline_extraction_testcases/.packages
@@ -0,0 +1 @@
+# dummy
\ No newline at end of file
diff --git a/pkg/front_end/outline_extraction_testcases/conditional_imports_exports_2/exists.dart b/pkg/front_end/outline_extraction_testcases/conditional_imports_exports_2/exists.dart
new file mode 100644
index 0000000..45a8112
--- /dev/null
+++ b/pkg/front_end/outline_extraction_testcases/conditional_imports_exports_2/exists.dart
@@ -0,0 +1,3 @@
+export 'nonexisting.dart' if (dart.library.io) 'exists2.dart';
+
+class Foo {}
diff --git a/pkg/front_end/outline_extraction_testcases/conditional_imports_exports_2/exists2.dart b/pkg/front_end/outline_extraction_testcases/conditional_imports_exports_2/exists2.dart
new file mode 100644
index 0000000..8c26988
--- /dev/null
+++ b/pkg/front_end/outline_extraction_testcases/conditional_imports_exports_2/exists2.dart
@@ -0,0 +1 @@
+class Foo2 {}
diff --git a/pkg/front_end/outline_extraction_testcases/conditional_imports_exports_2/main.dart b/pkg/front_end/outline_extraction_testcases/conditional_imports_exports_2/main.dart
new file mode 100644
index 0000000..90e030f
--- /dev/null
+++ b/pkg/front_end/outline_extraction_testcases/conditional_imports_exports_2/main.dart
@@ -0,0 +1,8 @@
+import 'nonexisting.dart' if (dart.library.io) 'exists.dart';
+export 'nonexisting.dart'
+ if (dart.library.html) 'exists2.dart'
+ if (dart.library.io) 'exists.dart';
+
+Foo x() {
+ return new Foo();
+}
diff --git a/pkg/front_end/outline_extraction_testcases/conditional_imports_exports_2/main.dart.outline_extracted b/pkg/front_end/outline_extraction_testcases/conditional_imports_exports_2/main.dart.outline_extracted
new file mode 100644
index 0000000..b26416d
--- /dev/null
+++ b/pkg/front_end/outline_extraction_testcases/conditional_imports_exports_2/main.dart.outline_extracted
@@ -0,0 +1,17 @@
+org-dartlang-testcase:///main.dart:
+import 'nonexisting.dart' if (dart.library.io) 'exists.dart';
+export 'nonexisting.dart' if (dart.library.html) 'exists2.dart' if (dart.library.io) 'exists.dart';
+Foo x() {}
+
+
+
+
+org-dartlang-testcase:///exists2.dart:
+class Foo2 {}
+
+
+
+
+org-dartlang-testcase:///exists.dart:
+export 'nonexisting.dart' if (dart.library.io) 'exists2.dart';
+class Foo {}
diff --git a/pkg/front_end/outline_extraction_testcases/factories/.packages b/pkg/front_end/outline_extraction_testcases/factories/.packages
new file mode 100644
index 0000000..6607aec
--- /dev/null
+++ b/pkg/front_end/outline_extraction_testcases/factories/.packages
@@ -0,0 +1 @@
+foo:.
\ No newline at end of file
diff --git a/pkg/front_end/outline_extraction_testcases/named_import_with_export_and_named_constructor_and_class_type_parameter/.packages b/pkg/front_end/outline_extraction_testcases/named_import_with_export_and_named_constructor_and_class_type_parameter/.packages
new file mode 100644
index 0000000..6607aec
--- /dev/null
+++ b/pkg/front_end/outline_extraction_testcases/named_import_with_export_and_named_constructor_and_class_type_parameter/.packages
@@ -0,0 +1 @@
+foo:.
\ No newline at end of file
diff --git a/pkg/front_end/outline_extraction_testcases/split_import_export_part/.packages b/pkg/front_end/outline_extraction_testcases/split_import_export_part/.packages
new file mode 100644
index 0000000..d19a7e0
--- /dev/null
+++ b/pkg/front_end/outline_extraction_testcases/split_import_export_part/.packages
@@ -0,0 +1 @@
+foobar:.
\ No newline at end of file
diff --git a/pkg/front_end/outline_extraction_testcases/use_of_imported_extension_2/foo.dart b/pkg/front_end/outline_extraction_testcases/use_of_imported_extension_2/foo.dart
index bd036e7..e48bd35 100644
--- a/pkg/front_end/outline_extraction_testcases/use_of_imported_extension_2/foo.dart
+++ b/pkg/front_end/outline_extraction_testcases/use_of_imported_extension_2/foo.dart
@@ -10,6 +10,8 @@
int get giveInt => 42;
}
+// The below doesn't have to be included.
+
extension BarExtension on Bar {
int get giveInt => 42;
}
diff --git a/pkg/front_end/outline_extraction_testcases/use_of_imported_extension_3/foo.dart b/pkg/front_end/outline_extraction_testcases/use_of_imported_extension_3/foo.dart
new file mode 100644
index 0000000..b6168cc
--- /dev/null
+++ b/pkg/front_end/outline_extraction_testcases/use_of_imported_extension_3/foo.dart
@@ -0,0 +1,19 @@
+enum Foo {
+ a,
+ b,
+ c,
+ d,
+ e,
+}
+
+extension FooExtension on Foo {
+ Function(int) get foobar => (int value) => 42;
+}
+
+// The below doesn't have to be included.
+
+extension BarExtension on Bar {
+ Function(int) get foobar => (int value) => 42;
+}
+
+class Bar {}
diff --git a/pkg/front_end/outline_extraction_testcases/use_of_imported_extension_3/main.dart b/pkg/front_end/outline_extraction_testcases/use_of_imported_extension_3/main.dart
new file mode 100644
index 0000000..cf29838
--- /dev/null
+++ b/pkg/front_end/outline_extraction_testcases/use_of_imported_extension_3/main.dart
@@ -0,0 +1,5 @@
+import "foo.dart";
+
+final foo = [Foo.d, Foo.b];
+
+final foo2 = foo.map((f) => f.foobar).toList();
diff --git a/pkg/front_end/outline_extraction_testcases/use_of_imported_extension_3/main.dart.outline_extracted b/pkg/front_end/outline_extraction_testcases/use_of_imported_extension_3/main.dart.outline_extracted
new file mode 100644
index 0000000..29e4991
--- /dev/null
+++ b/pkg/front_end/outline_extraction_testcases/use_of_imported_extension_3/main.dart.outline_extracted
@@ -0,0 +1,17 @@
+org-dartlang-testcase:///main.dart:
+import "foo.dart";
+final foo = [Foo.d, Foo.b];
+final foo2 = foo.map((f) => f.foobar).toList();
+
+
+
+
+org-dartlang-testcase:///foo.dart:
+enum Foo { a, b, c, d, e, }
+extension FooExtension on Foo {
+ Function(int) get foobar => (int value) => 42;
+}
+extension BarExtension on Bar {
+ Function(int) get foobar => (int value) => 42;
+}
+class Bar {}
diff --git a/pkg/front_end/test/outline_extractor_suite.dart b/pkg/front_end/test/outline_extractor_suite.dart
index 02be7f5..4548f0c 100644
--- a/pkg/front_end/test/outline_extractor_suite.dart
+++ b/pkg/front_end/test/outline_extractor_suite.dart
@@ -100,13 +100,12 @@
@override
Future<Result<TestDescription>> run(
TestDescription description, Context context) async {
- Uri? packages = description.uri.resolve(".dart_tool/package_config.json");
+ Uri? packages = description.uri.resolve(".packages");
if (!new File.fromUri(packages).existsSync()) {
packages = null;
}
Map<Uri, String> result =
await extractOutline([description.uri], packages: packages);
-
StringBuffer sb = new StringBuffer();
Uri uri = description.uri;
Uri base = uri.resolve(".");
@@ -142,7 +141,7 @@
@override
Future<Result<TestDescription>> run(
TestDescription description, Context context) async {
- Uri? packages = description.uri.resolve(".dart_tool/package_config.json");
+ Uri? packages = description.uri.resolve(".packages");
if (!new File.fromUri(packages).existsSync()) {
packages = null;
}
diff --git a/pkg/front_end/test/unit_test_suites.dart b/pkg/front_end/test/unit_test_suites.dart
index c9acb09..20fd455 100644
--- a/pkg/front_end/test/unit_test_suites.dart
+++ b/pkg/front_end/test/unit_test_suites.dart
@@ -31,9 +31,10 @@
show createContext;
import 'incremental_suite.dart' as incremental show createContext;
import 'lint_suite.dart' as lint show createContext;
-import 'parser_suite.dart' as parser show createContext;
-import 'parser_equivalence_suite.dart' as parserEquivalence show createContext;
+import 'outline_extractor_suite.dart' as outline_extractor show createContext;
import 'parser_all_suite.dart' as parserAll show createContext;
+import 'parser_equivalence_suite.dart' as parserEquivalence show createContext;
+import 'parser_suite.dart' as parser show createContext;
import 'spelling_test_not_src_suite.dart' as spelling_not_src
show createContext;
import 'spelling_test_src_suite.dart' as spelling_src show createContext;
@@ -473,6 +474,12 @@
"../../testing.json",
shardCount: 1,
),
+ const Suite(
+ "outline_extractor",
+ outline_extractor.createContext,
+ "../testing.json",
+ shardCount: 1,
+ ),
];
const Duration timeoutDuration = Duration(minutes: 30);