diff --git a/pkg/kernel/lib/src/tool/find_referenced_libraries.dart b/pkg/kernel/lib/src/tool/find_referenced_libraries.dart index dca5f78e641..c0174fbe181 100644 --- a/pkg/kernel/lib/src/tool/find_referenced_libraries.dart +++ b/pkg/kernel/lib/src/tool/find_referenced_libraries.dart @@ -4,8 +4,10 @@ import 'package:kernel/ast.dart'; -Set findAllReferencedLibraries(List from) { - _LibraryCollector collector = new _LibraryCollector(); +Set findAllReferencedLibraries(List from, + {bool collectViaReferencesToo = false}) { + _LibraryCollector collector = + new _LibraryCollector(collectViaReferencesToo: collectViaReferencesToo); for (Library library in from) { collector.visitLibrary(library); } @@ -21,13 +23,23 @@ bool duplicateLibrariesReachable(List from) { } class _LibraryCollector extends RecursiveVisitor { + final bool collectViaReferencesToo; Set allSeenLibraries = {}; + _LibraryCollector({required this.collectViaReferencesToo}); + @override void defaultNode(Node node) { if (node is NamedNode) { // Named nodes can be linked to. seen(node); + if (collectViaReferencesToo) { + TreeNode? refNode = node.reference.node; + if (refNode != null && !identical(refNode, node)) { + // This is generally pretty bad. + seen(refNode); + } + } } else if (node is Name) { if (node.library != null) { seen(node.library!); diff --git a/pkg/kernel/test/binary/relink_platform_test.dart b/pkg/kernel/test/binary/relink_platform_test.dart new file mode 100644 index 00000000000..ee303d86d7f --- /dev/null +++ b/pkg/kernel/test/binary/relink_platform_test.dart @@ -0,0 +1,87 @@ +// Copyright (c) 2024, 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:io'; + +import 'package:kernel/binary/ast_from_binary.dart'; +import 'package:kernel/kernel.dart'; +import 'package:kernel/src/tool/find_referenced_libraries.dart'; + +import '../relink_test.dart'; +import 'find_sdk_dills.dart'; + +void main() { + List dills = findSdkDills(); + print("Found ${dills.length} dills!"); + + for (File dill in dills) { + readAndRelink(dill); + } +} + +void readAndRelink(File dill) { + print("Reading $dill"); + List bytes = dill.readAsBytesSync(); + + try { + // Loading a component it should be self-contained. + Component component1 = new Component(); + new BinaryBuilder(bytes, + alwaysCreateNewNamedNodes: true, disableLazyReading: true) + .readComponent(component1); + checkReachable(component1); + + // Loading a component it should be self-contained. + Component component2 = new Component(nameRoot: component1.root); + new BinaryBuilder(bytes, + alwaysCreateNewNamedNodes: true, disableLazyReading: true) + .readComponent(component2); + checkReachable(component2); + + // Now that we read "component 2" on top of "component 1" the 1-version is + // no longer self-contained. + try { + checkReachable(component1); + throw "Expected this one to fail."; + } catch (e) { + // Expected. + } + + // Relinking it it should be back to being self contained though. + component1.relink(); + checkReachable(component1); + + // Now that component 1 is relinked component 2 is no longer self contained. + try { + checkReachable(component2); + throw "Expected this one to fail."; + } catch (e) { + // Expected. + } + + // But relinking makes it self-contained again. + component2.relink(); + checkReachable(component2); + } catch (e, st) { + print("Error for $dill:"); + print(e); + print(st); + print(""); + print("--------------------"); + print(""); + exitCode = 1; + } +} + +void checkReachable(Component component) { + expectReachable( + findAllReferencedLibraries(component.libraries), component.libraries); + expectReachable( + findAllReferencedLibraries(component.libraries, + collectViaReferencesToo: true), + component.libraries); + if (duplicateLibrariesReachable(component.libraries)) { + throw "Didn't expect duplicates libraries!"; + } +} diff --git a/pkg/kernel/test/relink_test.dart b/pkg/kernel/test/relink_test.dart index cbb64a4f5ae..adbaf8f56a2 100644 --- a/pkg/kernel/test/relink_test.dart +++ b/pkg/kernel/test/relink_test.dart @@ -80,6 +80,10 @@ void main() { // After the relink only the libs from component1Prime are reachable! expectReachable(findAllReferencedLibraries(component1Prime.libraries), component1Prime.libraries); + expectReachable( + findAllReferencedLibraries(component1Prime.libraries, + collectViaReferencesToo: true), + component1Prime.libraries); if (duplicateLibrariesReachable(component1Prime.libraries)) { throw "Didn't expect duplicates libraries!"; } @@ -103,6 +107,10 @@ void main() { // After the relink only the libs from component1Prime are reachable! expectReachable(findAllReferencedLibraries(component2Prime.libraries), component2Prime.libraries); + expectReachable( + findAllReferencedLibraries(component2Prime.libraries, + collectViaReferencesToo: true), + component2Prime.libraries); if (duplicateLibrariesReachable(component2Prime.libraries)) { throw "Didn't expect duplicates libraries!"; } @@ -160,6 +168,21 @@ Component createComponent(int literal) { fileUri: libUri); lib.addProcedure(libProcedure); + ExtensionTypeDeclaration extensionTypeDeclaration = + new ExtensionTypeDeclaration(name: "Foo", fileUri: libUri); + extensionTypeDeclaration.declaredRepresentationType = DynamicType(); + extensionTypeDeclaration.representationName = "extensionTypeMethod"; + final Block extensionTypeProcedureBody = + new Block([new ReturnStatement(new IntLiteral(literal))]); + final Procedure extensionTypeProcedure = new Procedure( + new Name("extensionTypeMethod"), + ProcedureKind.Method, + new FunctionNode(extensionTypeProcedureBody, + returnType: new DynamicType()), + fileUri: libUri); + extensionTypeDeclaration.addProcedure(extensionTypeProcedure); + lib.addExtensionTypeDeclaration(extensionTypeDeclaration); + final Uri mainUri = Uri.parse('org-dartlang:///main.dart'); final Library main = new Library(mainUri, fileUri: mainUri); final Block mainProcedureBody = new Block([