[framework] dont allocate forgotten children set in profile/release mode (#94911)
diff --git a/dev/bots/analyze.dart b/dev/bots/analyze.dart
index 5e77fe7..68dae54 100644
--- a/dev/bots/analyze.dart
+++ b/dev/bots/analyze.dart
@@ -98,6 +98,9 @@
print('$clock Integration test timeouts...');
await verifyIntegrationTestTimeouts(flutterRoot);
+ print('$clock null initialized debug fields...');
+ await verifyNullInitializedDebugExpensiveFields(flutterRoot);
+
// Ensure that all package dependencies are in sync.
print('$clock Package dependencies...');
await runCommand(flutter, <String>['update-packages', '--verify-only'],
@@ -785,7 +788,7 @@
final Set<String> suggestions = <String>{};
final List<File> files = await _gitFiles(workingDirectory);
for (final File file in files) {
- if (path.basename(file.path).endsWith('_test.dart'))
+ if (path.basename(file.path).endsWith('_test.dart') || path.basename(file.path) == 'analyze.dart')
continue; // Skip tests, they're not public-facing.
final Uint8List bytes = file.readAsBytesSync();
// We allow invalid UTF-8 here so that binaries don't trip us up.
@@ -1492,6 +1495,40 @@
}
}
+const String _kDebugOnlyAnnotation = '@_debugOnly';
+final RegExp _nullInitializedField = RegExp(r'kDebugMode \? [\w\<\> ,{}()]+ : null;');
+
+Future<void> verifyNullInitializedDebugExpensiveFields(String workingDirectory, {int minimumMatches = 400}) async {
+ final String flutterLib = path.join(workingDirectory, 'packages', 'flutter', 'lib');
+ final List<File> files = await _allFiles(flutterLib, 'dart', minimumMatches: minimumMatches)
+ .toList();
+ final List<String> errors = <String>[];
+ for (final File file in files) {
+ final List<String> lines = file.readAsLinesSync();
+ for (int i = 0; i < lines.length; i += 1) {
+ final String line = lines[i];
+ if (!line.contains(_kDebugOnlyAnnotation)) {
+ continue;
+ }
+ final String nextLine = lines[i + 1];
+ if (_nullInitializedField.firstMatch(nextLine) == null) {
+ errors.add('${file.path} L$i');
+ }
+ }
+ }
+
+ if (errors.isNotEmpty) {
+ exitWithError(<String>[
+ '${bold}ERROR: ${red}fields annotated with @_debugOnly must null initialize.$reset',
+ 'to ensure both the field and initializer are removed from profile/release mode.',
+ 'These fields should be written as:\n',
+ 'field = kDebugMode ? <DebugValue> : null;\n',
+ 'Errors were found in the following files:',
+ ...errors,
+ ]);
+ }
+}
+
Future<CommandResult> _runFlutterAnalyze(String workingDirectory, {
List<String> options = const <String>[],
}) async {