Version 2.16.0-23.0.dev
Merge commit '051c198bff018083fa42880330f139822518c1c8' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 01021bd..8e49630 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 2.17.0
+
+### Core libraries
+
+- **Breaking Change** [#47653](https://github.com/dart-lang/sdk/issues/47653):
+ On Windows, `Directory.rename` will no longer delete a directory if
+ `newPath` specifies one. Instead, a `FileSystemException` will be thrown.
+
## 2.16.0
### Core libraries
@@ -12,7 +20,8 @@
#### Dart command line
-- **Breaking Change** [#46100][]: The standalone `dartanalyzer` tool has been
+- **Breaking Change** [#46100](https://github.com/dart-lang/sdk/issues/46100):
+ The standalone `dartanalyzer` tool has been
marked deprecated as previously announced.
Its replacement is the `dart analyze` command.
Should you find any issues, or missing features, in the replacement
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
index ecb67b1..fae4e5e 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
@@ -3140,7 +3140,7 @@
// ```
static const HintCode UNDEFINED_REFERENCED_PARAMETER = HintCode(
'UNDEFINED_REFERENCED_PARAMETER',
- "The parameter '{0}' is not defined by '{1}'.",
+ "The parameter '{0}' isn't defined by '{1}'.",
hasPublishedDocs: true,
);
diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart
index 2dd25ca..be02c3e4 100644
--- a/pkg/analyzer/lib/src/error/codes.g.dart
+++ b/pkg/analyzer/lib/src/error/codes.g.dart
@@ -15938,7 +15938,7 @@
// `isEven` if `s` is `null`. In other words, if `s` is `null`, then neither
// `length` nor `isEven` will be invoked, and if `s` is non-`null`, then
// `length` can't return a `null` value. Either way, `isEven` can't be invoked
- // on a `null` value, so the null-aware operator is not necessary. See
+ // on a `null` value, so the null-aware operator isn't necessary. See
// [Understanding null safety](/null-safety/understanding-null-safety#smarter-null-aware-methods)
// for more details.
//
diff --git a/pkg/analyzer/lib/src/manifest/manifest_warning_code.g.dart b/pkg/analyzer/lib/src/manifest/manifest_warning_code.g.dart
index d988a94..0e1ee4c 100644
--- a/pkg/analyzer/lib/src/manifest/manifest_warning_code.g.dart
+++ b/pkg/analyzer/lib/src/manifest/manifest_warning_code.g.dart
@@ -76,7 +76,7 @@
static const ManifestWarningCode UNSUPPORTED_CHROME_OS_FEATURE =
ManifestWarningCode(
'UNSUPPORTED_CHROME_OS_FEATURE',
- "The feature {0} is not supported on Chrome OS, consider making it optional.",
+ "The feature {0} isn't supported on Chrome OS, consider making it optional.",
correctionMessage:
"Try changing to `android:required=\"false\"` for this feature.",
);
@@ -88,7 +88,7 @@
static const ManifestWarningCode UNSUPPORTED_CHROME_OS_HARDWARE =
ManifestWarningCode(
'UNSUPPORTED_CHROME_OS_HARDWARE',
- "The feature {0} is not supported on Chrome OS, consider making it optional.",
+ "The feature {0} isn't supported on Chrome OS, consider making it optional.",
correctionMessage:
"Try adding `android:required=\"false\"` for this feature.",
);
diff --git a/pkg/analyzer/lib/src/pubspec/pubspec_warning_code.g.dart b/pkg/analyzer/lib/src/pubspec/pubspec_warning_code.g.dart
index 689c4ba..88d2f07 100644
--- a/pkg/analyzer/lib/src/pubspec/pubspec_warning_code.g.dart
+++ b/pkg/analyzer/lib/src/pubspec/pubspec_warning_code.g.dart
@@ -291,7 +291,7 @@
// #### Description
//
// The analyzer produces this diagnostic when a package under either
- // `dependencies` or `dev_dependencies` is not a pub, `git`, or `path` based
+ // `dependencies` or `dev_dependencies` isn't a pub, `git`, or `path` based
// dependency.
//
// See [Package dependencies](https://dart.dev/tools/pub/dependencies) for
@@ -300,7 +300,7 @@
// #### Example
//
// The following code produces this diagnostic because the dependency on the
- // package `transmogrify` is not a pub, `git`, or `path` based dependency:
+ // package `transmogrify` isn't a pub, `git`, or `path` based dependency:
//
// ```yaml
// %uri="pubspec.yaml"
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index 4c8327f..8c2b4be 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -16633,7 +16633,7 @@
var x = min(0, 1);
```
UNDEFINED_REFERENCED_PARAMETER:
- problemMessage: "The parameter '{0}' is not defined by '{1}'."
+ problemMessage: "The parameter '{0}' isn't defined by '{1}'."
hasPublishedDocs: true
comment: |-
Parameters:
@@ -17457,11 +17457,11 @@
correctionMessage: Consider declaring the corresponding activity element with `screenOrientation="unspecified"` or `"fullSensor"` attribute.
comment: A code indicating that the activity is locked to an orientation.
UNSUPPORTED_CHROME_OS_FEATURE:
- problemMessage: "The feature {0} is not supported on Chrome OS, consider making it optional."
+ problemMessage: "The feature {0} isn't supported on Chrome OS, consider making it optional."
correctionMessage: "Try changing to `android:required=\"false\"` for this feature."
comment: A code indicating that a specified feature is not supported on Chrome OS.
UNSUPPORTED_CHROME_OS_HARDWARE:
- problemMessage: "The feature {0} is not supported on Chrome OS, consider making it optional."
+ problemMessage: "The feature {0} isn't supported on Chrome OS, consider making it optional."
correctionMessage: "Try adding `android:required=\"false\"` for this feature."
comment: |-
A code indicating that a specified hardware feature is not supported on
@@ -18028,7 +18028,7 @@
#### Description
The analyzer produces this diagnostic when a package under either
- `dependencies` or `dev_dependencies` is not a pub, `git`, or `path` based
+ `dependencies` or `dev_dependencies` isn't a pub, `git`, or `path` based
dependency.
See [Package dependencies](https://dart.dev/tools/pub/dependencies) for
@@ -18037,7 +18037,7 @@
#### Example
The following code produces this diagnostic because the dependency on the
- package `transmogrify` is not a pub, `git`, or `path` based dependency:
+ package `transmogrify` isn't a pub, `git`, or `path` based dependency:
```yaml
%uri="pubspec.yaml"
@@ -18397,7 +18397,7 @@
`isEven` if `s` is `null`. In other words, if `s` is `null`, then neither
`length` nor `isEven` will be invoked, and if `s` is non-`null`, then
`length` can't return a `null` value. Either way, `isEven` can't be invoked
- on a `null` value, so the null-aware operator is not necessary. See
+ on a `null` value, so the null-aware operator isn't necessary. See
[Understanding null safety](/null-safety/understanding-null-safety#smarter-null-aware-methods)
for more details.
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 74533fb..97d64c9 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -6518,7 +6518,7 @@
#### Description
The analyzer produces this diagnostic when a package under either
-`dependencies` or `dev_dependencies` is not a pub, `git`, or `path` based
+`dependencies` or `dev_dependencies` isn't a pub, `git`, or `path` based
dependency.
See [Package dependencies](https://dart.dev/tools/pub/dependencies) for
@@ -6527,7 +6527,7 @@
#### Example
The following code produces this diagnostic because the dependency on the
-package `transmogrify` is not a pub, `git`, or `path` based dependency:
+package `transmogrify` isn't a pub, `git`, or `path` based dependency:
```yaml
name: example
@@ -6968,7 +6968,7 @@
`isEven` if `s` is `null`. In other words, if `s` is `null`, then neither
`length` nor `isEven` will be invoked, and if `s` is non-`null`, then
`length` can't return a `null` value. Either way, `isEven` can't be invoked
-on a `null` value, so the null-aware operator is not necessary. See
+on a `null` value, so the null-aware operator isn't necessary. See
[Understanding null safety](/null-safety/understanding-null-safety#smarter-null-aware-methods)
for more details.
@@ -14407,7 +14407,7 @@
### undefined_referenced_parameter
-_The parameter '{0}' is not defined by '{1}'._
+_The parameter '{0}' isn't defined by '{1}'._
#### Description
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index 19d778d..a974629 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -359,7 +359,7 @@
expect(
bulletToDash(outSink),
contains(
- 'warning - The feature android.software.home_screen is not supported on Chrome OS'));
+ "warning - The feature android.software.home_screen isn't supported on Chrome OS"));
expect(exitCode, 0);
});
}
diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
index 804bfff..3e199239 100644
--- a/runtime/bin/directory_win.cc
+++ b/runtime/bin/directory_win.cc
@@ -512,16 +512,6 @@
}
const char* prefixed_new_dir = PrefixLongDirectoryPath(new_path);
Utf8ToWideScope system_new_path(prefixed_new_dir);
- ExistsResult new_exists = ExistsHelper(system_new_path.wide());
- // MoveFile does not allow replacing existing directories. Therefore,
- // if the new_path is currently a directory we need to delete it
- // first.
- if (new_exists == EXISTS) {
- bool success = Delete(namespc, prefixed_new_dir, true);
- if (!success) {
- return false;
- }
- }
DWORD flags = MOVEFILE_WRITE_THROUGH;
int move_status =
MoveFileExW(system_path.wide(), system_new_path.wide(), flags);
diff --git a/sdk/lib/io/directory.dart b/sdk/lib/io/directory.dart
index 7fb3ed5..cbda1c3 100644
--- a/sdk/lib/io/directory.dart
+++ b/sdk/lib/io/directory.dart
@@ -233,20 +233,28 @@
/// Returns a `Future<Directory>` that completes
/// with a [Directory] for the renamed directory.
///
- /// If [newPath] identifies an existing directory, that directory is
- /// removed first.
+ /// If [newPath] identifies an existing directory, then the behavior is
+ /// platform-specific. On all platforms, the future completes with an
+ /// [FileSystemException] if the existing directory is not empty. On POSIX
+ /// systems, if [newPath] identifies an existing empty directory then that
+ /// directory is deleted before this directory is renamed.
+ ///
/// If [newPath] identifies an existing file, the operation
- /// fails and the future completes with an exception.
+ /// fails and the future completes with a [FileSystemException].
Future<Directory> rename(String newPath);
/// Synchronously renames this directory.
///
/// Returns a [Directory] for the renamed directory.
///
- /// If [newPath] identifies an existing directory, that directory is
- /// removed first.
+ /// If [newPath] identifies an existing directory, then the behavior is
+ /// platform-specific. On all platforms, a [FileSystemException] is thrown
+ /// if the existing directory is not empty. On POSIX systems, if [newPath]
+ /// identifies an existing empty directory then that directory is deleted
+ /// before this directory is renamed.
+ ///
/// If [newPath] identifies an existing file the operation
- /// fails and an exception is thrown.
+ /// fails and a [FileSystemException] is thrown.
Directory renameSync(String newPath);
/// A [Directory] whose path is the absolute path of [this].
diff --git a/tests/standalone/io/directory_rename_test.dart b/tests/standalone/io/directory_rename_test.dart
index 0d31c07..de14cea 100644
--- a/tests/standalone/io/directory_rename_test.dart
+++ b/tests/standalone/io/directory_rename_test.dart
@@ -19,16 +19,22 @@
});
}
-testRenameDoesNotAdjustPath() async {
+testRenamePath() async {
+ // Verifies that the returned directory has the correct path.
await withTempDir('testRenameToNewPath', (Directory tempDir) async {
- final dir1 = Directory("${tempDir.path}/dir1");
- dir1.createSync();
- final originalPath = dir1.path;
+ final oldDir = Directory("${tempDir.path}/dir1");
+ oldDir.createSync();
- dir1.renameSync("${tempDir.path}/dir2");
- final finalPath = dir1.path;
- Expect.isTrue(originalPath == finalPath,
- "$originalPath != $finalPath - path should not be updated");
+ final newDir = oldDir.renameSync("${tempDir.path}/dir2");
+
+ Expect.isTrue(
+ oldDir.path == "${tempDir.path}/dir1",
+ "${oldDir.path} != '${tempDir.path}/dir1'"
+ "- path should not be updated");
+ Expect.isTrue(
+ newDir.path == "${tempDir.path}/dir2",
+ "${newDir.path} != '${tempDir.path}/dir2'"
+ "- path should be updated");
});
}
@@ -39,26 +45,8 @@
final file = File("${dir.path}/file");
file.createSync();
- try {
- dir.renameSync(dir.path);
- if (Platform.isWindows) {
- Expect.fail('Directory.rename to same path should fail on Windows');
- } else {
- Expect.isTrue(file.existsSync());
- }
- } on FileSystemException catch (e) {
- if (Platform.isWindows) {
- // On Windows, the directory will be *deleted*.
- Expect.isFalse(dir.existsSync());
- Expect.isTrue(
- e.osError!.message.contains('cannot find the file specified'),
- 'Unexpected error: $e');
- } else {
- Expect.fail('Directory.rename to same path should not fail on '
- '${Platform.operatingSystem} (${Platform.operatingSystemVersion}): '
- '$e');
- }
- }
+ dir.renameSync(dir.path);
+ Expect.isTrue(file.existsSync());
});
}
@@ -74,12 +62,12 @@
dir.renameSync(file.path);
Expect.fail('Directory.rename should fail to rename a non-directory');
} on FileSystemException catch (e) {
- if (Platform.isLinux || Platform.isMacOS) {
- Expect.isTrue(e.osError!.message.contains('Not a directory'),
- 'Unexpected error: $e');
- } else if (Platform.isWindows) {
+ if (Platform.isWindows) {
Expect.isTrue(e.osError!.message.contains('file already exists'),
'Unexpected error: $e');
+ } else if (Platform.isLinux || Platform.isMacOS) {
+ Expect.isTrue(e.osError!.message.contains('Not a directory'),
+ 'Unexpected error: $e');
}
}
});
@@ -95,9 +83,23 @@
final dir2 = Directory("${tempDir.path}/dir2");
dir2.createSync();
- dir1.renameSync(dir2.path);
- // Verify that the file contained in dir1 have been moved.
- Expect.isTrue(File("${dir2.path}/file").existsSync());
+ try {
+ dir1.renameSync(dir2.path);
+ // Verify that the file contained in dir1 has been moved.
+ if (Platform.isWindows) {
+ Expect.fail(
+ 'Directory.rename should fail to rename over an existing directory '
+ 'on Windows');
+ } else {
+ Expect.isTrue(File("${dir2.path}/file").existsSync());
+ }
+ } on FileSystemException catch (e) {
+ if (Platform.isWindows) {
+ Expect.isTrue(e.osError!.message.contains('file already exists'));
+ } else {
+ Expect.fail('Directory.rename should allow moves to empty directories');
+ }
+ }
});
}
@@ -114,17 +116,13 @@
try {
dir1.renameSync(dir2.path);
- if (Platform.isWindows) {
- // Verify that the old directory is deleted.
- Expect.isTrue(File("${dir2.path}/file1").existsSync());
- Expect.isFalse(File("${dir2.path}/file2").existsSync());
- } else {
- Expect.fail(
- 'Directory.rename should fail to rename a non-empty directory '
- 'except on Windows');
- }
+ Expect.fail(
+ 'Directory.rename should fail to rename a non-empty directory');
} on FileSystemException catch (e) {
- if (Platform.isLinux || Platform.isMacOS) {
+ if (Platform.isWindows) {
+ Expect.isTrue(e.osError!.message.contains('file already exists'),
+ 'Unexpected error: $e');
+ } else if (Platform.isLinux || Platform.isMacOS) {
Expect.isTrue(e.osError!.message.contains('Directory not empty'),
'Unexpected error: $e');
}
@@ -132,11 +130,31 @@
});
}
+testRenameButActuallyFile() async {
+ await withTempDir('testRenameButActuallyFile', (Directory tempDir) async {
+ final file = File("${tempDir.path}/file");
+ file.createSync();
+ final dir = Directory(file.path);
+ try {
+ dir.renameSync("${tempDir.path}/dir");
+ Expect.fail("Expected a failure to rename the file.");
+ } on FileSystemException catch (e) {
+ Expect.isTrue(
+ e.message.contains('Rename failed'), 'Unexpected error: $e');
+ if (Platform.isLinux || Platform.isMacOS) {
+ Expect.isTrue(e.osError!.message.contains('Not a directory'),
+ 'Unexpected error: $e');
+ }
+ }
+ });
+}
+
main() async {
await testRenameToNewPath();
- await testRenameDoesNotAdjustPath();
+ await testRenamePath();
await testRenameToSamePath();
await testRenameToExistingFile();
await testRenameToExistingEmptyDirectory();
await testRenameToExistingNonEmptyDirectory();
+ await testRenameButActuallyFile();
}
diff --git a/tests/standalone_2/io/directory_rename_test.dart b/tests/standalone_2/io/directory_rename_test.dart
index 50af674..5f47913 100644
--- a/tests/standalone_2/io/directory_rename_test.dart
+++ b/tests/standalone_2/io/directory_rename_test.dart
@@ -21,16 +21,22 @@
});
}
-testRenameDoesNotAdjustPath() async {
+testRenamePath() async {
+ // Verifies that the returned directory has the correct path.
await withTempDir('testRenameToNewPath', (Directory tempDir) async {
- final dir1 = Directory("${tempDir.path}/dir1");
- dir1.createSync();
- final originalPath = dir1.path;
+ final oldDir = Directory("${tempDir.path}/dir1");
+ oldDir.createSync();
- dir1.renameSync("${tempDir.path}/dir2");
- final finalPath = dir1.path;
- Expect.isTrue(originalPath == finalPath,
- "$originalPath != $finalPath - path should not be updated");
+ final newDir = oldDir.renameSync("${tempDir.path}/dir2");
+
+ Expect.isTrue(
+ oldDir.path == "${tempDir.path}/dir1",
+ "${oldDir.path} != '${tempDir.path}/dir1'"
+ "- path should not be updated");
+ Expect.isTrue(
+ newDir.path == "${tempDir.path}/dir2",
+ "${newDir.path} != '${tempDir.path}/dir2'"
+ "- path should be updated");
});
}
@@ -41,26 +47,8 @@
final file = File("${dir.path}/file");
file.createSync();
- try {
- dir.renameSync(dir.path);
- if (Platform.isWindows) {
- Expect.fail('Directory.rename to same path should fail on Windows');
- } else {
- Expect.isTrue(file.existsSync());
- }
- } on FileSystemException catch (e) {
- if (Platform.isWindows) {
- // On Windows, the directory will be *deleted*.
- Expect.isFalse(dir.existsSync());
- Expect.isTrue(
- e.osError.message.contains('cannot find the file specified'),
- 'Unexpected error: $e');
- } else {
- Expect.fail('Directory.rename to same path should not fail on '
- '${Platform.operatingSystem} (${Platform.operatingSystemVersion}): '
- '$e');
- }
- }
+ dir.renameSync(dir.path);
+ Expect.isTrue(file.existsSync());
});
}
@@ -76,12 +64,12 @@
dir.renameSync(file.path);
Expect.fail('Directory.rename should fail to rename a non-directory');
} on FileSystemException catch (e) {
- if (Platform.isLinux || Platform.isMacOS) {
- Expect.isTrue(e.osError.message.contains('Not a directory'),
- 'Unexpected error: $e');
- } else if (Platform.isWindows) {
+ if (Platform.isWindows) {
Expect.isTrue(e.osError.message.contains('file already exists'),
'Unexpected error: $e');
+ } else if (Platform.isLinux || Platform.isMacOS) {
+ Expect.isTrue(e.osError.message.contains('Not a directory'),
+ 'Unexpected error: $e');
}
}
});
@@ -97,9 +85,23 @@
final dir2 = Directory("${tempDir.path}/dir2");
dir2.createSync();
- dir1.renameSync(dir2.path);
- // Verify that the file contained in dir1 has been moved.
- Expect.isTrue(File("${dir2.path}/file").existsSync());
+ try {
+ dir1.renameSync(dir2.path);
+ // Verify that the file contained in dir1 has been moved.
+ if (Platform.isWindows) {
+ Expect.fail(
+ 'Directory.rename should fail to rename over an existing directory '
+ 'on Windows');
+ } else {
+ Expect.isTrue(File("${dir2.path}/file").existsSync());
+ }
+ } on FileSystemException catch (e) {
+ if (Platform.isWindows) {
+ Expect.isTrue(e.osError.message.contains('file already exists'));
+ } else {
+ Expect.fail('Directory.rename should allow moves to empty directories');
+ }
+ }
});
}
@@ -116,17 +118,13 @@
try {
dir1.renameSync(dir2.path);
- if (Platform.isWindows) {
- // Verify that the old directory is deleted.
- Expect.isTrue(File("${dir2.path}/file1").existsSync());
- Expect.isFalse(File("${dir2.path}/file2").existsSync());
- } else {
- Expect.fail(
- 'Directory.rename should fail to rename a non-empty directory '
- 'except on Windows');
- }
+ Expect.fail(
+ 'Directory.rename should fail to rename a non-empty directory');
} on FileSystemException catch (e) {
- if (Platform.isLinux || Platform.isMacOS) {
+ if (Platform.isWindows) {
+ Expect.isTrue(e.osError.message.contains('file already exists'),
+ 'Unexpected error: $e');
+ } else if (Platform.isLinux || Platform.isMacOS) {
Expect.isTrue(e.osError.message.contains('Directory not empty'),
'Unexpected error: $e');
}
@@ -134,11 +132,31 @@
});
}
+testRenameButActuallyFile() async {
+ await withTempDir('testRenameButActuallyFile', (Directory tempDir) async {
+ final file = File("${tempDir.path}/file");
+ file.createSync();
+ final dir = Directory(file.path);
+ try {
+ dir.renameSync("${tempDir.path}/dir");
+ Expect.fail("Expected a failure to rename the file.");
+ } on FileSystemException catch (e) {
+ Expect.isTrue(
+ e.message.contains('Rename failed'), 'Unexpected error: $e');
+ if (Platform.isLinux || Platform.isMacOS) {
+ Expect.isTrue(e.osError.message.contains('Not a directory'),
+ 'Unexpected error: $e');
+ }
+ }
+ });
+}
+
main() async {
await testRenameToNewPath();
- await testRenameDoesNotAdjustPath();
+ await testRenamePath();
await testRenameToSamePath();
await testRenameToExistingFile();
await testRenameToExistingEmptyDirectory();
await testRenameToExistingNonEmptyDirectory();
+ await testRenameButActuallyFile();
}
diff --git a/tools/VERSION b/tools/VERSION
index 70b8be2..cd8bf2f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 22
+PRERELEASE 23
PRERELEASE_PATCH 0
\ No newline at end of file