Skip to content

Commit b2c65ac

Browse files
[flutter_tools] Remove --no-sound-null-safety #4 (flutter#124039)
Re-land of flutter#123297 without any of the commits at the end attempting to fix customer-testing. Fixes flutter#118810
1 parent 34d2c8d commit b2c65ac

File tree

9 files changed

+104
-187
lines changed

9 files changed

+104
-187
lines changed

dev/bots/test.dart

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -573,9 +573,7 @@ Future<void> _runExampleProjectBuildTests(Directory exampleDirectory, [File? mai
573573
// Only verify caching with flutter gallery.
574574
final bool verifyCaching = exampleDirectory.path.contains('flutter_gallery');
575575
final String examplePath = path.relative(exampleDirectory.path, from: Directory.current.path);
576-
final bool hasNullSafety = File(path.join(examplePath, 'null_safety')).existsSync();
577576
final List<String> additionalArgs = <String>[
578-
if (hasNullSafety) '--no-sound-null-safety',
579577
if (mainFile != null) path.relative(mainFile.path, from: exampleDirectory.absolute.path),
580578
];
581579
if (Directory(path.join(examplePath, 'android')).existsSync()) {
@@ -771,16 +769,14 @@ Future<void> _runAddToAppLifeCycleTests() async {
771769
}
772770

773771
Future<void> _runFrameworkTests() async {
774-
final List<String> soundNullSafetyOptions = <String>['--null-assertions', '--sound-null-safety'];
775-
final List<String> mixedModeNullSafetyOptions = <String>['--null-assertions', '--no-sound-null-safety'];
776772
final List<String> trackWidgetCreationAlternatives = <String>['--track-widget-creation', '--no-track-widget-creation'];
777773

778774
Future<void> runWidgets() async {
779775
printProgress('${green}Running packages/flutter tests $reset for ${cyan}test/widgets/$reset');
780776
for (final String trackWidgetCreationOption in trackWidgetCreationAlternatives) {
781777
await _runFlutterTest(
782778
path.join(flutterRoot, 'packages', 'flutter'),
783-
options: <String>[trackWidgetCreationOption, ...soundNullSafetyOptions],
779+
options: <String>[trackWidgetCreationOption],
784780
tests: <String>[ path.join('test', 'widgets') + path.separator ],
785781
);
786782
}
@@ -795,13 +791,13 @@ Future<void> _runFrameworkTests() async {
795791
// Run release mode tests (see packages/flutter/test_release/README.md)
796792
await _runFlutterTest(
797793
path.join(flutterRoot, 'packages', 'flutter'),
798-
options: <String>['--dart-define=dart.vm.product=true', ...soundNullSafetyOptions],
794+
options: <String>['--dart-define=dart.vm.product=true'],
799795
tests: <String>['test_release${path.separator}'],
800796
);
801797
// Run profile mode tests (see packages/flutter/test_profile/README.md)
802798
await _runFlutterTest(
803799
path.join(flutterRoot, 'packages', 'flutter'),
804-
options: <String>['--dart-define=dart.vm.product=false', '--dart-define=dart.vm.profile=true', ...soundNullSafetyOptions],
800+
options: <String>['--dart-define=dart.vm.product=false', '--dart-define=dart.vm.profile=true'],
805801
tests: <String>['test_profile${path.separator}'],
806802
);
807803
}
@@ -817,7 +813,7 @@ Future<void> _runFrameworkTests() async {
817813
for (final String trackWidgetCreationOption in trackWidgetCreationAlternatives) {
818814
await _runFlutterTest(
819815
path.join(flutterRoot, 'packages', 'flutter'),
820-
options: <String>[trackWidgetCreationOption, ...soundNullSafetyOptions],
816+
options: <String>[trackWidgetCreationOption],
821817
tests: tests,
822818
);
823819
}
@@ -837,9 +833,9 @@ Future<void> _runFrameworkTests() async {
837833
workingDirectory: path.join(flutterRoot, 'examples', 'api'),
838834
);
839835
}
840-
await _runFlutterTest(path.join(flutterRoot, 'examples', 'api'), options: soundNullSafetyOptions);
841-
await _runFlutterTest(path.join(flutterRoot, 'examples', 'hello_world'), options: soundNullSafetyOptions);
842-
await _runFlutterTest(path.join(flutterRoot, 'examples', 'layers'), options: soundNullSafetyOptions);
836+
await _runFlutterTest(path.join(flutterRoot, 'examples', 'api'));
837+
await _runFlutterTest(path.join(flutterRoot, 'examples', 'hello_world'));
838+
await _runFlutterTest(path.join(flutterRoot, 'examples', 'layers'));
843839
}
844840

845841
Future<void> runTracingTests() async {
@@ -945,7 +941,6 @@ Future<void> _runFrameworkTests() async {
945941

946942
Future<void> runPrivateTests() async {
947943
final List<String> args = <String>[
948-
'--sound-null-safety',
949944
'run',
950945
'bin/test_private.dart',
951946
];
@@ -989,17 +984,17 @@ Future<void> _runFrameworkTests() async {
989984
await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'gen_defaults'));
990985
await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'gen_keycodes'));
991986
await _runFlutterTest(path.join(flutterRoot, 'dev', 'benchmarks', 'test_apps', 'stocks'));
992-
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_driver'), tests: <String>[path.join('test', 'src', 'real_tests')], options: soundNullSafetyOptions);
987+
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_driver'), tests: <String>[path.join('test', 'src', 'real_tests')]);
993988
await _runFlutterTest(path.join(flutterRoot, 'packages', 'integration_test'), options: <String>[
994989
'--enable-vmservice',
995990
// Web-specific tests depend on Chromium, so they run as part of the web_long_running_tests shard.
996991
'--exclude-tags=web',
997992
]);
998-
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_goldens'), options: soundNullSafetyOptions);
999-
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_localizations'), options: soundNullSafetyOptions);
1000-
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_test'), options: soundNullSafetyOptions);
1001-
await _runFlutterTest(path.join(flutterRoot, 'packages', 'fuchsia_remote_debug_protocol'), options: soundNullSafetyOptions);
1002-
await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'non_nullable'), options: mixedModeNullSafetyOptions);
993+
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_goldens'));
994+
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_localizations'));
995+
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_test'));
996+
await _runFlutterTest(path.join(flutterRoot, 'packages', 'fuchsia_remote_debug_protocol'));
997+
await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'non_nullable'));
1003998
const String httpClientWarning =
1004999
'Warning: At least one test in this suite creates an HttpClient. When\n'
10051000
'running a test suite that uses TestWidgetsFlutterBinding, all HTTP\n'
@@ -1234,7 +1229,7 @@ Future<void> _runWebLongRunningTests() async {
12341229
'--dart-define=TEST_FLUTTER_ENGINE_VERSION=$engineVersion',
12351230
]),
12361231
() => _runWebDebugTest('test/test.dart'),
1237-
() => _runWebDebugTest('lib/null_safe_main.dart', enableNullSafety: true),
1232+
() => _runWebDebugTest('lib/null_safe_main.dart'),
12381233
() => _runWebDebugTest('lib/web_define_loading.dart',
12391234
additionalArguments: <String>[
12401235
'--dart-define=test.valueA=Example,A',
@@ -1247,12 +1242,8 @@ Future<void> _runWebLongRunningTests() async {
12471242
'--dart-define=test.valueB=Value',
12481243
]
12491244
),
1250-
() => _runWebDebugTest('lib/sound_mode.dart', additionalArguments: <String>[
1251-
'--sound-null-safety',
1252-
]),
1253-
() => _runWebReleaseTest('lib/sound_mode.dart', additionalArguments: <String>[
1254-
'--sound-null-safety',
1255-
]),
1245+
() => _runWebDebugTest('lib/sound_mode.dart'),
1246+
() => _runWebReleaseTest('lib/sound_mode.dart'),
12561247
() => _runFlutterWebTest(
12571248
'html',
12581249
path.join(flutterRoot, 'packages', 'integration_test'),
@@ -1311,7 +1302,6 @@ Future<void> _runFlutterDriverWebTest({
13111302
if (driver != null) '--driver=$driver',
13121303
'--target=$target',
13131304
'--browser-name=chrome',
1314-
'--no-sound-null-safety',
13151305
'-d',
13161306
'web-server',
13171307
'--$buildMode',
@@ -1353,7 +1343,6 @@ Future<void> _runWebTreeshakeTest() async {
13531343
'build',
13541344
'web',
13551345
'--target=$target',
1356-
'--no-sound-null-safety',
13571346
'--profile',
13581347
],
13591348
workingDirectory: testAppDirectory,
@@ -1579,7 +1568,6 @@ Future<void> _runGalleryE2eWebTest(String buildMode, { bool canvasKit = false })
15791568
'--driver=test_driver/transitions_perf_e2e_test.dart',
15801569
'--target=test_driver/transitions_perf_e2e.dart',
15811570
'--browser-name=chrome',
1582-
'--no-sound-null-safety',
15831571
'-d',
15841572
'web-server',
15851573
'--$buildMode',
@@ -1686,7 +1674,6 @@ Future<void> _runWebReleaseTest(String target, {
16861674
///
16871675
/// Instead, we use `flutter run --debug` and sniff out the standard output.
16881676
Future<void> _runWebDebugTest(String target, {
1689-
bool enableNullSafety = false,
16901677
List<String> additionalArguments = const<String>[],
16911678
}) async {
16921679
final String testAppDirectory = path.join(flutterRoot, 'dev', 'integration_tests', 'web');
@@ -1700,11 +1687,6 @@ Future<void> _runWebDebugTest(String target, {
17001687
<String>[
17011688
'run',
17021689
'--debug',
1703-
if (enableNullSafety)
1704-
...<String>[
1705-
'--no-sound-null-safety',
1706-
'--null-assertions',
1707-
],
17081690
'-d',
17091691
'chrome',
17101692
'--web-run-headless',
@@ -1747,7 +1729,6 @@ Future<void> _runFlutterWebTest(String webRenderer, String workingDirectory, Lis
17471729
'--platform=chrome',
17481730
'--web-renderer=$webRenderer',
17491731
'--dart-define=DART_HHH_BOT=$_runningInDartHHHBot',
1750-
'--sound-null-safety',
17511732
...flutterTestArgs,
17521733
...tests,
17531734
],

packages/flutter/test/foundation/isolates_test.dart

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ Future<int> test5CallCompute(int value) {
8080
return compute(test5, value);
8181
}
8282

83-
Future<void> expectFileSuccessfullyCompletes(String filename,
84-
[bool unsound = false]) async {
83+
Future<void> expectFileSuccessfullyCompletes(String filename) async {
8584
// Run a Dart script that calls compute().
8685
// The Dart process will terminate only if the script exits cleanly with
8786
// all isolate ports closed.
@@ -93,12 +92,10 @@ Future<void> expectFileSuccessfullyCompletes(String filename,
9392
final String packageRoot = fs.path.dirname(fs.path.fromUri(platform.script));
9493
final String scriptPath =
9594
fs.path.join(packageRoot, 'test', 'foundation', filename);
96-
final String nullSafetyArg =
97-
unsound ? '--no-sound-null-safety' : '--sound-null-safety';
9895

9996
// Enable asserts to also catch potentially invalid assertions.
10097
final ProcessResult result = await Process.run(
101-
dartPath, <String>[nullSafetyArg, 'run', '--enable-asserts', scriptPath]);
98+
dartPath, <String>['run', '--enable-asserts', scriptPath]);
10299
expect(result.exitCode, 0);
103100
}
104101

packages/flutter/test_private/bin/test_private.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ class TestCase {
225225
for (final File test in tests) {
226226
final String testPath = path.join(path.dirname(test.path), 'lib', path.basenameWithoutExtension(test.path));
227227
final ProcessRunnerResult result = await runner.runProcess(
228-
<String>[flutter, 'test', '--enable-experiment=non-nullable', '--no-sound-null-safety', '--null-assertions', testPath],
228+
<String>[flutter, 'test', testPath],
229229
failOk: true,
230230
);
231231
if (result.exitCode != 0) {

packages/flutter_tools/lib/src/globals.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import 'pre_run_validator.dart';
4343
import 'project.dart';
4444
import 'reporting/crash_reporting.dart';
4545
import 'reporting/reporting.dart';
46+
import 'runner/flutter_command.dart';
4647
import 'runner/local_engine.dart';
4748
import 'version.dart';
4849

@@ -285,3 +286,7 @@ const String kDefaultFrameworkChannel = 'master';
285286

286287
// Used to build RegExp instances which can detect the VM service message.
287288
final RegExp kVMServiceMessageRegExp = RegExp(r'The Dart VM service is listening on ((http|//)[a-zA-Z0-9:/=_\-\.\[\]]+)');
289+
290+
// The official tool no longer allows non-null safe builds. This can be
291+
// overridden in other clients.
292+
NonNullSafeBuilds get nonNullSafeBuilds => context.get<NonNullSafeBuilds>() ?? NonNullSafeBuilds.notAllowed;

packages/flutter_tools/lib/src/runner/flutter_command.dart

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import '../bundle.dart' as bundle;
2121
import '../cache.dart';
2222
import '../convert.dart';
2323
import '../dart/generate_synthetic_packages.dart';
24-
import '../dart/language_version.dart';
2524
import '../dart/package_map.dart';
2625
import '../dart/pub.dart';
2726
import '../device.dart';
@@ -822,20 +821,13 @@ abstract class FlutterCommand extends Command<void> {
822821

823822
void addNullSafetyModeOptions({ required bool hide }) {
824823
argParser.addFlag(FlutterOptions.kNullSafety,
825-
help:
826-
'Whether to override the inferred null safety mode. This allows null-safe '
827-
'libraries to depend on un-migrated (non-null safe) libraries. By default, '
828-
'Flutter mobile & desktop applications will attempt to run at the null safety '
829-
'level of their entrypoint library (usually lib/main.dart). Flutter web '
830-
'applications will default to sound null-safety, unless specifically configured.',
824+
help: 'This flag is deprecated as only null-safe code is supported.',
831825
defaultsTo: true,
832-
hide: hide,
826+
hide: true,
833827
);
834828
argParser.addFlag(FlutterOptions.kNullAssertions,
835-
help:
836-
'Perform additional null assertions on the boundaries of migrated and '
837-
'un-migrated code. This setting is not currently supported on desktop '
838-
'devices.'
829+
help: 'This flag is deprecated as only null-safe code is supported.',
830+
hide: true,
839831
);
840832
}
841833

@@ -1148,39 +1140,17 @@ abstract class FlutterCommand extends Command<void> {
11481140

11491141
NullSafetyMode nullSafetyMode = NullSafetyMode.sound;
11501142
if (argParser.options.containsKey(FlutterOptions.kNullSafety)) {
1151-
// Explicitly check for `true` and `false` so that `null` results in not
1152-
// passing a flag. Examine the entrypoint file to determine if it
1153-
// is opted in or out.
11541143
final bool wasNullSafetyFlagParsed = argResults?.wasParsed(FlutterOptions.kNullSafety) ?? false;
1155-
if (!wasNullSafetyFlagParsed && (argParser.options.containsKey('target') || forcedTargetFile != null)) {
1156-
final File entrypointFile = forcedTargetFile ?? globals.fs.file(targetFile);
1157-
final LanguageVersion languageVersion = determineLanguageVersion(
1158-
entrypointFile,
1159-
packageConfig.packageOf(entrypointFile.absolute.uri),
1160-
Cache.flutterRoot!,
1161-
);
1162-
// Extra frontend options are only provided if explicitly
1163-
// requested.
1164-
if ((languageVersion.major > nullSafeVersion.major) ||
1165-
(languageVersion.major == nullSafeVersion.major && languageVersion.minor >= nullSafeVersion.minor)) {
1144+
// Extra frontend options are only provided if explicitly
1145+
// requested.
1146+
if (wasNullSafetyFlagParsed) {
1147+
if (boolArg(FlutterOptions.kNullSafety)) {
11661148
nullSafetyMode = NullSafetyMode.sound;
1149+
extraFrontEndOptions.add('--sound-null-safety');
11671150
} else {
1168-
throwToolExit(
1169-
'This application does not support sound null-safety (its language version is $languageVersion).\n'
1170-
'To build this application, you must provide the CLI flag --no-sound-null-safety. Dart 3 will only '
1171-
'support sound null safety, see https://dart.dev/null-safety.',
1172-
);
1151+
nullSafetyMode = NullSafetyMode.unsound;
1152+
extraFrontEndOptions.add('--no-sound-null-safety');
11731153
}
1174-
} else if (!wasNullSafetyFlagParsed) {
1175-
// This mode is only used for commands which do not build a single target like
1176-
// 'flutter test'.
1177-
nullSafetyMode = NullSafetyMode.autodetect;
1178-
} else if (boolArg(FlutterOptions.kNullSafety)) {
1179-
nullSafetyMode = NullSafetyMode.sound;
1180-
extraFrontEndOptions.add('--sound-null-safety');
1181-
} else {
1182-
nullSafetyMode = NullSafetyMode.unsound;
1183-
extraFrontEndOptions.add('--no-sound-null-safety');
11841154
}
11851155
}
11861156

@@ -1487,6 +1457,16 @@ abstract class FlutterCommand extends Command<void> {
14871457
/// rather than calling [runCommand] directly.
14881458
@mustCallSuper
14891459
Future<FlutterCommandResult> verifyThenRunCommand(String? commandPath) async {
1460+
if (argParser.options.containsKey(FlutterOptions.kNullSafety) &&
1461+
argResults![FlutterOptions.kNullSafety] == false &&
1462+
globals.nonNullSafeBuilds == NonNullSafeBuilds.notAllowed) {
1463+
throwToolExit('''
1464+
Could not find an option named "no-${FlutterOptions.kNullSafety}".
1465+
1466+
Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and options.
1467+
''');
1468+
}
1469+
14901470
globals.preRunValidator.validate();
14911471

14921472
if (refreshWirelessDevices) {
@@ -1754,3 +1734,12 @@ DevelopmentArtifact? artifactFromTargetPlatform(TargetPlatform targetPlatform) {
17541734

17551735
/// Returns true if s is either null, empty or is solely made of whitespace characters (as defined by String.trim).
17561736
bool _isBlank(String s) => s.trim().isEmpty;
1737+
1738+
/// Whether the tool should allow non-null safe builds.
1739+
///
1740+
/// The Dart SDK no longer supports non-null safe builds, so this value in the
1741+
/// tool's context should always be [NonNullSafeBuilds.notAllowed].
1742+
enum NonNullSafeBuilds {
1743+
allowed,
1744+
notAllowed,
1745+
}

packages/flutter_tools/test/commands.shard/hermetic/run_test.dart

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,52 @@ void main() {
6767
Logger: () => BufferLogger.test(),
6868
});
6969

70+
testUsingContext('does not support --no-sound-null-safety by default', () async {
71+
fileSystem.file('lib/main.dart').createSync(recursive: true);
72+
fileSystem.file('pubspec.yaml').createSync();
73+
fileSystem.file('.packages').createSync();
74+
75+
final TestRunCommandThatOnlyValidates command = TestRunCommandThatOnlyValidates();
76+
await expectLater(
77+
() => createTestCommandRunner(command).run(<String>[
78+
'run',
79+
'--use-application-binary=app/bar/faz',
80+
'--no-sound-null-safety',
81+
]),
82+
throwsA(isException.having(
83+
(Exception exception) => exception.toString(),
84+
'toString',
85+
contains('Could not find an option named "no-sound-null-safety"'),
86+
)),
87+
);
88+
}, overrides: <Type, Generator>{
89+
FileSystem: () => fileSystem,
90+
ProcessManager: () => FakeProcessManager.any(),
91+
Logger: () => BufferLogger.test(),
92+
});
93+
94+
testUsingContext('supports --no-sound-null-safety with an overridden NonNullSafeBuilds', () async {
95+
fileSystem.file('lib/main.dart').createSync(recursive: true);
96+
fileSystem.file('pubspec.yaml').createSync();
97+
fileSystem.file('.packages').createSync();
98+
99+
final FakeDevice device = FakeDevice(isLocalEmulator: true, platformType: PlatformType.android);
100+
101+
testDeviceManager.devices = <Device>[device];
102+
final TestRunCommandThatOnlyValidates command = TestRunCommandThatOnlyValidates();
103+
await createTestCommandRunner(command).run(const <String>[
104+
'run',
105+
'--use-application-binary=app/bar/faz',
106+
'--no-sound-null-safety',
107+
]);
108+
}, overrides: <Type, Generator>{
109+
DeviceManager: () => testDeviceManager,
110+
FileSystem: () => fileSystem,
111+
Logger: () => BufferLogger.test(),
112+
NonNullSafeBuilds: () => NonNullSafeBuilds.allowed,
113+
ProcessManager: () => FakeProcessManager.any(),
114+
});
115+
70116
testUsingContext('does not support "--use-application-binary" and "--fast-start"', () async {
71117
fileSystem.file('lib/main.dart').createSync(recursive: true);
72118
fileSystem.file('pubspec.yaml').createSync();

packages/flutter_tools/test/general.shard/args_test.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,10 @@ void verifyOptions(String? command, Iterable<Option> options) {
176176
expect(option.name, matches(_allowedArgumentNamePattern), reason: '$_header$target--${option.name}" is not a valid name for a command line argument. (Is it all lowercase? Does it use hyphens rather than underscores?)');
177177
}
178178
expect(option.name, isNot(matches(_bannedArgumentNamePattern)), reason: '$_header$target--${option.name}" is not a valid name for a command line argument. (We use "--foo-url", not "--foo-uri", for example.)');
179-
expect(option.hide, isFalse, reason: '${_header}Help for $target--${option.name}" is always hidden. $_needHelp');
179+
// The flag --sound-null-safety is deprecated
180+
if (option.name != FlutterOptions.kNullSafety && option.name != FlutterOptions.kNullAssertions) {
181+
expect(option.hide, isFalse, reason: '${_header}Help for $target--${option.name}" is always hidden. $_needHelp');
182+
}
180183
expect(option.help, isNotNull, reason: '${_header}Help for $target--${option.name}" has null help. $_needHelp');
181184
expect(option.help, isNotEmpty, reason: '${_header}Help for $target--${option.name}" has empty help. $_needHelp');
182185
expect(option.help, isNot(matches(_bannedLeadingPatterns)), reason: '${_header}A line in the help for $target--${option.name}" starts with a lowercase letter. For stylistic consistency, all help messages must start with a capital letter.');

0 commit comments

Comments
 (0)