Unverified Commit c86d090e authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] add --null-assertions flag for debugging with null safety (#63416)

parent cbe0999d
...@@ -626,9 +626,8 @@ class AndroidDevice extends Device { ...@@ -626,9 +626,8 @@ class AndroidDevice extends Device {
); );
} }
List<String> cmd; final String dartVmFlags = computeDartVmFlags(debuggingOptions);
final List<String> cmd = <String>[
cmd = <String>[
'shell', 'am', 'start', 'shell', 'am', 'start',
'-a', 'android.intent.action.RUN', '-a', 'android.intent.action.RUN',
'-f', '0x20000000', // FLAG_ACTIVITY_SINGLE_TOP '-f', '0x20000000', // FLAG_ACTIVITY_SINGLE_TOP
...@@ -665,8 +664,8 @@ class AndroidDevice extends Device { ...@@ -665,8 +664,8 @@ class AndroidDevice extends Device {
...<String>['--ez', 'start-paused', 'true'], ...<String>['--ez', 'start-paused', 'true'],
if (debuggingOptions.disableServiceAuthCodes) if (debuggingOptions.disableServiceAuthCodes)
...<String>['--ez', 'disable-service-auth-codes', 'true'], ...<String>['--ez', 'disable-service-auth-codes', 'true'],
if (debuggingOptions.dartFlags.isNotEmpty) if (dartVmFlags.isNotEmpty)
...<String>['--es', 'dart-flags', debuggingOptions.dartFlags], ...<String>['--es', 'dart-flags', dartVmFlags],
if (debuggingOptions.useTestFonts) if (debuggingOptions.useTestFonts)
...<String>['--ez', 'use-test-fonts', 'true'], ...<String>['--ez', 'use-test-fonts', 'true'],
if (debuggingOptions.verboseSystemLogs) if (debuggingOptions.verboseSystemLogs)
......
...@@ -423,6 +423,7 @@ class RunCommand extends RunCommandBase { ...@@ -423,6 +423,7 @@ class RunCommand extends RunCommandBase {
fastStart: boolArg('fast-start') fastStart: boolArg('fast-start')
&& !runningWithPrebuiltApplication && !runningWithPrebuiltApplication
&& devices.every((Device device) => device.supportsFastStart), && devices.every((Device device) => device.supportsFastStart),
nullAssertions: boolArg('null-assertions'),
); );
} }
} }
......
...@@ -265,6 +265,7 @@ class TestCommand extends FlutterCommand { ...@@ -265,6 +265,7 @@ class TestCommand extends FlutterCommand {
web: stringArg('platform') == 'chrome', web: stringArg('platform') == 'chrome',
randomSeed: stringArg('test-randomize-ordering-seed'), randomSeed: stringArg('test-randomize-ordering-seed'),
extraFrontEndOptions: getBuildInfo(forcedBuildMode: BuildMode.debug).extraFrontEndOptions, extraFrontEndOptions: getBuildInfo(forcedBuildMode: BuildMode.debug).extraFrontEndOptions,
nullAssertions: boolArg(FlutterOptions.kNullAssertions),
); );
if (collector != null) { if (collector != null) {
......
...@@ -790,6 +790,7 @@ class DebuggingOptions { ...@@ -790,6 +790,7 @@ class DebuggingOptions {
this.webEnableExpressionEvaluation = false, this.webEnableExpressionEvaluation = false,
this.vmserviceOutFile, this.vmserviceOutFile,
this.fastStart = false, this.fastStart = false,
this.nullAssertions = false,
}) : debuggingEnabled = true; }) : debuggingEnabled = true;
DebuggingOptions.disabled(this.buildInfo, { DebuggingOptions.disabled(this.buildInfo, {
...@@ -821,7 +822,8 @@ class DebuggingOptions { ...@@ -821,7 +822,8 @@ class DebuggingOptions {
deviceVmServicePort = null, deviceVmServicePort = null,
vmserviceOutFile = null, vmserviceOutFile = null,
fastStart = false, fastStart = false,
webEnableExpressionEvaluation = false; webEnableExpressionEvaluation = false,
nullAssertions = false;
final bool debuggingEnabled; final bool debuggingEnabled;
...@@ -868,6 +870,8 @@ class DebuggingOptions { ...@@ -868,6 +870,8 @@ class DebuggingOptions {
final String vmserviceOutFile; final String vmserviceOutFile;
final bool fastStart; final bool fastStart;
final bool nullAssertions;
bool get hasObservatoryPort => hostVmServicePort != null; bool get hasObservatoryPort => hostVmServicePort != null;
} }
...@@ -993,3 +997,14 @@ class NoOpDevicePortForwarder implements DevicePortForwarder { ...@@ -993,3 +997,14 @@ class NoOpDevicePortForwarder implements DevicePortForwarder {
@override @override
Future<void> dispose() async { } Future<void> dispose() async { }
} }
/// Append --null_assertions to any existing Dart VM flags if
/// [debuggingOptions.nullAssertions] is true.
String computeDartVmFlags(DebuggingOptions debuggingOptions) {
return <String>[
if (debuggingOptions.dartFlags?.isNotEmpty ?? false)
debuggingOptions.dartFlags,
if (debuggingOptions.nullAssertions)
'--null_assertions',
].join(',');
}
...@@ -355,6 +355,7 @@ class IOSDevice extends Device { ...@@ -355,6 +355,7 @@ class IOSDevice extends Device {
?? math.Random(packageId.hashCode).nextInt(16383) + 49152; ?? math.Random(packageId.hashCode).nextInt(16383) + 49152;
// Step 3: Attempt to install the application on the device. // Step 3: Attempt to install the application on the device.
final String dartVmFlags = computeDartVmFlags(debuggingOptions);
final List<String> launchArguments = <String>[ final List<String> launchArguments = <String>[
'--enable-dart-profiling', '--enable-dart-profiling',
// These arguments are required to support the fallback connection strategy // These arguments are required to support the fallback connection strategy
...@@ -363,7 +364,7 @@ class IOSDevice extends Device { ...@@ -363,7 +364,7 @@ class IOSDevice extends Device {
'--disable-service-auth-codes', '--disable-service-auth-codes',
'--observatory-port=$assumedObservatoryPort', '--observatory-port=$assumedObservatoryPort',
if (debuggingOptions.startPaused) '--start-paused', if (debuggingOptions.startPaused) '--start-paused',
if (debuggingOptions.dartFlags.isNotEmpty) '--dart-flags="${debuggingOptions.dartFlags}"', if (dartVmFlags.isNotEmpty) '--dart-flags="$dartVmFlags"',
if (debuggingOptions.useTestFonts) '--use-test-fonts', if (debuggingOptions.useTestFonts) '--use-test-fonts',
// "--enable-checked-mode" and "--verify-entry-points" should always be // "--enable-checked-mode" and "--verify-entry-points" should always be
// passed when we launch debug build via "ios-deploy". However, we don't // passed when we launch debug build via "ios-deploy". However, we don't
......
...@@ -411,6 +411,7 @@ class IOSSimulator extends Device { ...@@ -411,6 +411,7 @@ class IOSSimulator extends Device {
} }
// Prepare launch arguments. // Prepare launch arguments.
final String dartVmFlags = computeDartVmFlags(debuggingOptions);
final List<String> args = <String>[ final List<String> args = <String>[
'--enable-dart-profiling', '--enable-dart-profiling',
if (debuggingOptions.debuggingEnabled) ...<String>[ if (debuggingOptions.debuggingEnabled) ...<String>[
...@@ -423,6 +424,7 @@ class IOSSimulator extends Device { ...@@ -423,6 +424,7 @@ class IOSSimulator extends Device {
if (debuggingOptions.skiaDeterministicRendering) '--skia-deterministic-rendering', if (debuggingOptions.skiaDeterministicRendering) '--skia-deterministic-rendering',
if (debuggingOptions.useTestFonts) '--use-test-fonts', if (debuggingOptions.useTestFonts) '--use-test-fonts',
if (debuggingOptions.traceAllowlist != null) '--trace-allowlist="${debuggingOptions.traceAllowlist}"', if (debuggingOptions.traceAllowlist != null) '--trace-allowlist="${debuggingOptions.traceAllowlist}"',
if (dartVmFlags.isNotEmpty) '--dart-flags=$dartVmFlags'
'--observatory-port=${debuggingOptions.hostVmServicePort ?? 0}', '--observatory-port=${debuggingOptions.hostVmServicePort ?? 0}',
], ],
]; ];
......
...@@ -113,6 +113,7 @@ class FlutterOptions { ...@@ -113,6 +113,7 @@ class FlutterOptions {
static const String kNullSafety = 'sound-null-safety'; static const String kNullSafety = 'sound-null-safety';
static const String kDeviceUser = 'device-user'; static const String kDeviceUser = 'device-user';
static const String kAnalyzeSize = 'analyze-size'; static const String kAnalyzeSize = 'analyze-size';
static const String kNullAssertions = 'null-assertions';
} }
abstract class FlutterCommand extends Command<void> { abstract class FlutterCommand extends Command<void> {
...@@ -500,6 +501,12 @@ abstract class FlutterCommand extends Command<void> { ...@@ -500,6 +501,12 @@ abstract class FlutterCommand extends Command<void> {
defaultsTo: null, defaultsTo: null,
hide: hide, hide: hide,
); );
argParser.addFlag(FlutterOptions.kNullAssertions,
help:
'Perform additional null assertions on the boundaries of migrated and '
'unmigrated code. This setting is not currently supported on desktop '
'devices.'
);
} }
void usesExtraFrontendOptions() { void usesExtraFrontendOptions() {
......
...@@ -92,6 +92,7 @@ FlutterPlatform installHook({ ...@@ -92,6 +92,7 @@ FlutterPlatform installHook({
List<String> extraFrontEndOptions, List<String> extraFrontEndOptions,
// Deprecated, use extraFrontEndOptions. // Deprecated, use extraFrontEndOptions.
List<String> dartExperiments, List<String> dartExperiments,
bool nullAssertions = false,
}) { }) {
assert(testWrapper != null); assert(testWrapper != null);
assert(enableObservatory || (!startPaused && observatoryPort == null)); assert(enableObservatory || (!startPaused && observatoryPort == null));
...@@ -125,6 +126,7 @@ FlutterPlatform installHook({ ...@@ -125,6 +126,7 @@ FlutterPlatform installHook({
flutterProject: flutterProject, flutterProject: flutterProject,
icudtlPath: icudtlPath, icudtlPath: icudtlPath,
extraFrontEndOptions: extraFrontEndOptions, extraFrontEndOptions: extraFrontEndOptions,
nullAssertions: nullAssertions,
); );
platformPluginRegistration(platform); platformPluginRegistration(platform);
return platform; return platform;
...@@ -268,6 +270,7 @@ class FlutterPlatform extends PlatformPlugin { ...@@ -268,6 +270,7 @@ class FlutterPlatform extends PlatformPlugin {
this.projectRootDirectory, this.projectRootDirectory,
this.flutterProject, this.flutterProject,
this.icudtlPath, this.icudtlPath,
this.nullAssertions = false,
@required this.extraFrontEndOptions, @required this.extraFrontEndOptions,
}) : assert(shellPath != null); }) : assert(shellPath != null);
...@@ -290,6 +293,7 @@ class FlutterPlatform extends PlatformPlugin { ...@@ -290,6 +293,7 @@ class FlutterPlatform extends PlatformPlugin {
final FlutterProject flutterProject; final FlutterProject flutterProject;
final String icudtlPath; final String icudtlPath;
final List<String> extraFrontEndOptions; final List<String> extraFrontEndOptions;
final bool nullAssertions;
Directory fontsDirectory; Directory fontsDirectory;
...@@ -844,6 +848,8 @@ class FlutterPlatform extends PlatformPlugin { ...@@ -844,6 +848,8 @@ class FlutterPlatform extends PlatformPlugin {
'--non-interactive', '--non-interactive',
'--use-test-fonts', '--use-test-fonts',
'--packages=$packages', '--packages=$packages',
if (nullAssertions)
'--dart-flags=--null_assertions',
testPath, testPath,
]; ];
......
...@@ -52,6 +52,7 @@ abstract class FlutterTestRunner { ...@@ -52,6 +52,7 @@ abstract class FlutterTestRunner {
bool web = false, bool web = false,
String randomSeed, String randomSeed,
@required List<String> extraFrontEndOptions, @required List<String> extraFrontEndOptions,
bool nullAssertions = false,
}); });
} }
...@@ -86,6 +87,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner { ...@@ -86,6 +87,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
bool web = false, bool web = false,
String randomSeed, String randomSeed,
@required List<String> extraFrontEndOptions, @required List<String> extraFrontEndOptions,
bool nullAssertions = false,
}) async { }) async {
// Configure package:test to use the Flutter engine for child processes. // Configure package:test to use the Flutter engine for child processes.
final String shellPath = globals.artifacts.getArtifactPath(Artifact.flutterTester); final String shellPath = globals.artifacts.getArtifactPath(Artifact.flutterTester);
...@@ -178,6 +180,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner { ...@@ -178,6 +180,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
flutterProject: flutterProject, flutterProject: flutterProject,
icudtlPath: icudtlPath, icudtlPath: icudtlPath,
extraFrontEndOptions: extraFrontEndOptions, extraFrontEndOptions: extraFrontEndOptions,
nullAssertions: nullAssertions,
); );
// Make the global packages path absolute. // Make the global packages path absolute.
......
...@@ -185,6 +185,7 @@ class FakeFlutterTestRunner implements FlutterTestRunner { ...@@ -185,6 +185,7 @@ class FakeFlutterTestRunner implements FlutterTestRunner {
bool web = false, bool web = false,
String randomSeed, String randomSeed,
@override List<String> extraFrontEndOptions, @override List<String> extraFrontEndOptions,
bool nullAssertions = false,
}) async { }) async {
lastEnableObservatoryValue = enableObservatory; lastEnableObservatoryValue = enableObservatory;
return exitCode; return exitCode;
......
...@@ -254,7 +254,7 @@ void main() { ...@@ -254,7 +254,7 @@ void main() {
'--ez', 'verify-entry-points', 'true', '--ez', 'verify-entry-points', 'true',
'--ez', 'start-paused', 'true', '--ez', 'start-paused', 'true',
'--ez', 'disable-service-auth-codes', 'true', '--ez', 'disable-service-auth-codes', 'true',
'--es', 'dart-flags', 'foo', '--es', 'dart-flags', 'foo,--null_assertions',
'--ez', 'use-test-fonts', 'true', '--ez', 'use-test-fonts', 'true',
'--ez', 'verbose-logging', 'true', '--ez', 'verbose-logging', 'true',
'--user', '10', '--user', '10',
...@@ -281,6 +281,7 @@ void main() { ...@@ -281,6 +281,7 @@ void main() {
purgePersistentCache: true, purgePersistentCache: true,
useTestFonts: true, useTestFonts: true,
verboseSystemLogs: true, verboseSystemLogs: true,
nullAssertions: true,
), ),
platformArgs: <String, dynamic>{}, platformArgs: <String, dynamic>{},
userIdentifier: '10', userIdentifier: '10',
......
...@@ -416,6 +416,13 @@ void main() { ...@@ -416,6 +416,13 @@ void main() {
); );
}); });
}); });
testWithoutContext('computeDartVmFlags handles various combinations of Dart VM flags and null_assertions', () {
expect(computeDartVmFlags(DebuggingOptions.enabled(BuildInfo.debug, dartFlags: null)), '');
expect(computeDartVmFlags(DebuggingOptions.enabled(BuildInfo.debug, dartFlags: '--foo')), '--foo');
expect(computeDartVmFlags(DebuggingOptions.enabled(BuildInfo.debug, dartFlags: '', nullAssertions: true)), '--null_assertions');
expect(computeDartVmFlags(DebuggingOptions.enabled(BuildInfo.debug, dartFlags: '--foo', nullAssertions: true)), '--foo,--null_assertions');
});
} }
class TestDeviceManager extends DeviceManager { class TestDeviceManager extends DeviceManager {
......
...@@ -319,7 +319,7 @@ void main() { ...@@ -319,7 +319,7 @@ void main() {
'--disable-service-auth-codes', '--disable-service-auth-codes',
'--observatory-port=60700', '--observatory-port=60700',
'--start-paused', '--start-paused',
'--dart-flags="--foo"', '--dart-flags="--foo,--null_assertions"',
'--enable-checked-mode', '--enable-checked-mode',
'--verify-entry-points', '--verify-entry-points',
'--enable-software-rendering', '--enable-software-rendering',
...@@ -385,6 +385,7 @@ void main() { ...@@ -385,6 +385,7 @@ void main() {
cacheSkSL: true, cacheSkSL: true,
purgePersistentCache: true, purgePersistentCache: true,
verboseSystemLogs: true, verboseSystemLogs: true,
nullAssertions: true,
), ),
platformArgs: <String, dynamic>{}, platformArgs: <String, dynamic>{},
fallbackPollingDelay: Duration.zero, fallbackPollingDelay: Duration.zero,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment