Avoid runtimeType.toString in toString overrides/debugLabels (#48607)
diff --git a/dev/bots/analyze.dart b/dev/bots/analyze.dart index 5fb6664..c9a5156 100644 --- a/dev/bots/analyze.dart +++ b/dev/bots/analyze.dart
@@ -44,6 +44,9 @@ exitWithError(<String>['The analyze.dart script must be run with --enable-asserts.']); } + print('$clock runtimeType in toString...'); + await verifyNoRuntimeTypeInToString(flutterRoot); + print('$clock Unexpected binaries...'); await verifyNoBinaries(flutterRoot); @@ -541,6 +544,58 @@ } } +Future<void> verifyNoRuntimeTypeInToString(String workingDirectory) async { + final String flutterLib = path.join(workingDirectory, 'packages', 'flutter', 'lib'); + final Set<String> excludedFiles = <String>{ + path.join(flutterLib, 'src', 'foundation', 'object.dart'), // Calls this from within an assert. + }; + final List<File> files = _allFiles(flutterLib, 'dart', minimumMatches: 400) + .where((File file) => !excludedFiles.contains(file.path)) + .toList(); + final RegExp toStringRegExp = RegExp(r'^\s+String\s+to(.+?)?String(.+?)?\(\)\s+(\{|=>)'); + final List<String> problems = <String>[]; + for (final File file in files) { + final List<String> lines = file.readAsLinesSync(); + for (int index = 0; index < lines.length; index++) { + if (toStringRegExp.hasMatch(lines[index])) { + final int sourceLine = index + 1; + bool _checkForRuntimeType(String line) { + if (line.contains(r'$runtimeType') || line.contains('runtimeType.toString()')) { + problems.add('${file.path}:$sourceLine}: toString calls runtimeType.toString'); + return true; + } + return false; + } + if (_checkForRuntimeType(lines[index])) { + continue; + } + if (lines[index].contains('=>')) { + while (!lines[index].contains(';')) { + index++; + assert(index < lines.length, 'Source file $file has unterminated toString method.'); + if (_checkForRuntimeType(lines[index])) { + break; + } + } + } else { + int openBraceCount = '{'.allMatches(lines[index]).length - '}'.allMatches(lines[index]).length; + while (!lines[index].contains('}') && openBraceCount > 0) { + index++; + assert(index < lines.length, 'Source file $file has unbalanced braces in a toString method.'); + if (_checkForRuntimeType(lines[index])) { + break; + } + openBraceCount += '{'.allMatches(lines[index]).length; + openBraceCount -= '}'.allMatches(lines[index]).length; + } + } + } + } + } + if (problems.isNotEmpty) + exitWithError(problems); +} + Future<void> verifyNoTrailingSpaces(String workingDirectory, { int minimumMatches = 4000 }) async { final List<File> files = _allFiles(workingDirectory, null, minimumMatches: minimumMatches) .where((File file) => path.basename(file.path) != 'serviceaccount.enc')