Fix Directory.current setter compatibility with IOOverrides

The `Directory.current` setter has a `dynamic` parameter so that it
can accept either `String` or `Directory` arguments. (This is
asymmetric with the getter, which always returns a `Directory`.)

The corresponding `IOOverrides` callback, however, assumes that the
argument is always a `String`, and `Directory.current` passed its
`dynamic` argument through unchanged.  Consequently, overriding
the `Directory.current` setter would result in a `TypeError` when
setting `Directory.current` to a `Directory` object.

Changing `IOOverrides.setCurrentDirectory` to use a `dynamic`
parameter would be a breaking change, so instead make the
`Directory.current` setter check the argument's runtime type before
passing it along.

Bug: https://github.com/dart-lang/sdk/issues/52140
Change-Id: I3c5bba6b442b314c798bd7949dfeb5eb6251dc6e
CoreLibraryReviewExempt: No API changes and VM-only.
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/336604
Reviewed-by: Brian Quinlan <bquinlan@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
Auto-Submit: James Lin <jamesdlin@gmail.com>
Commit-Queue: Brian Quinlan <bquinlan@google.com>
This commit is contained in:
James Lin
2023-12-18 20:23:21 +00:00
committed by Commit Queue
parent c84edaefe9
commit 48ac398f11
3 changed files with 41 additions and 21 deletions
+15 -2
View File
@@ -162,13 +162,26 @@ abstract interface class Directory implements FileSystemEntity {
/// operations and multiple isolates. Changing the working directory,
/// while asynchronous operations are pending or when other isolates
/// are working with the file system, can lead to unexpected results.
static void set current(path) {
static void set current(dynamic path) {
// Disallow implicit casts to avoid bugs like
// <https://github.com/dart-lang/sdk/issues/52140>.
//
// This can be removed if `strict-casts` is enabled.
path as Object?;
final IOOverrides? overrides = IOOverrides.current;
if (overrides == null) {
_Directory.current = path;
return;
}
overrides.setCurrentDirectory(path);
// IOOverrides.setCurrentDirectory accepts only a [String].
overrides.setCurrentDirectory(switch (path) {
String s => s,
Directory d => d.path,
_ => throw ArgumentError('${Error.safeToString(path)} is not a String or'
' Directory'),
});
}
/// Creates the directory if it doesn't exist.
+10 -15
View File
@@ -45,23 +45,18 @@ class _Directory extends FileSystemEntity implements Directory {
return new _Directory(result);
}
static void set current(path) {
late Uint8List _rawPath;
if (path is _Directory) {
static void set current(Object? path) {
var _rawPath = switch (path) {
// For our internal Directory implementation, go ahead and use the raw
// path.
_rawPath = path._rawPath;
} else if (path is Directory) {
// FIXME(bkonyi): package:file passes in instances of classes which do
// not have _path defined, so we will fallback to using the existing
// path String for now.
_rawPath = FileSystemEntity._toUtf8Array(path.path);
} else if (path is String) {
_rawPath = FileSystemEntity._toUtf8Array(path);
} else {
throw new ArgumentError('${Error.safeToString(path)} is not a String or'
' Directory');
}
_Directory d => d._rawPath,
// Fall back to the String-based path.
Directory d => FileSystemEntity._toUtf8Array(d.path),
String s => FileSystemEntity._toUtf8Array(s),
_ => throw ArgumentError('${Error.safeToString(path)} is not a String or'
' Directory')
};
if (!_EmbedderConfig._mayChdir) {
throw new UnsupportedError(
"This embedder disallows setting Directory.current");
+16 -4
View File
@@ -12,13 +12,16 @@ import "package:expect/expect.dart";
class DirectoryMock extends FileSystemEntity implements Directory {
static final _mockUri = Uri.parse('http:///mockdir/');
final String path = "/mockdir";
final String path;
DirectoryMock(String path);
DirectoryMock(this.path);
static DirectoryMock _currentDirectory = DirectoryMock("");
static DirectoryMock createDirectory(String path) => new DirectoryMock(path);
static DirectoryMock getCurrent() => new DirectoryMock("");
static void setCurrent(String path) {}
static DirectoryMock getCurrent() => _currentDirectory;
static void setCurrent(String path) =>
_currentDirectory = DirectoryMock(path);
static DirectoryMock getSystemTemp() => new DirectoryMock("");
Uri get uri => _mockUri;
@@ -207,6 +210,15 @@ Future<Null> ioOverridesRunTest() async {
() async {
Expect.isTrue(new Directory("directory") is DirectoryMock);
Expect.isTrue(Directory.current is DirectoryMock);
const mockDirectoryPath1 = "/mockDirectory1";
const mockDirectoryPath2 = "/mockDirectory2";
Directory.current = mockDirectoryPath1;
Expect.isTrue(Directory.current.path == mockDirectoryPath1);
Directory.current = Directory(mockDirectoryPath2);
Expect.isTrue(Directory.current.path == mockDirectoryPath2);
Expect.identical(Uri.base, DirectoryMock._mockUri);
Expect.isTrue(Directory.systemTemp is DirectoryMock);
Expect.isTrue(new File("file") is FileMock);