mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
[flutter_tools] add --null-assertions flag for debugging with null safety (#63416)
This commit is contained in:
parent
cbe0999d1f
commit
c86d090e6f
@ -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 {
|
|||||||
...<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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
@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 {
|
|||||||
?? 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 {
|
|||||||
'--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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
|||||||
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 {
|
|||||||
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> {
|
|||||||
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({
|
|||||||
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({
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
'--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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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() {
|
|||||||
'--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() {
|
|||||||
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() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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() {
|
|||||||
'--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() {
|
|||||||
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,
|
||||||
|
Loading…
Reference in New Issue
Block a user