enable lint prefer_final_in_for_each (#47724)

diff --git a/dev/bots/analyze-sample-code.dart b/dev/bots/analyze-sample-code.dart
index f442234..2957f26 100644
--- a/dev/bots/analyze-sample-code.dart
+++ b/dev/bots/analyze-sample-code.dart
@@ -193,7 +193,7 @@
       "import 'dart:typed_data';",
       "import 'dart:ui' as ui;",
       "import 'package:flutter_test/flutter_test.dart';",
-      for (File file in _listDartFiles(Directory(_defaultFlutterPackage))) ...<String>[
+      for (final File file in _listDartFiles(Directory(_defaultFlutterPackage))) ...<String>[
         '',
         '// ${file.path}',
         "import 'package:flutter/${path.basename(file.path)}';",
@@ -214,7 +214,7 @@
       errors = _analyze(_tempDirectory, sections, snippets);
     } finally {
       if (errors.isNotEmpty) {
-        for (String filePath in errors.keys) {
+        for (final String filePath in errors.keys) {
           errors[filePath].forEach(stderr.writeln);
         }
         stderr.writeln('\nFound ${errors.length} sample code errors.');
@@ -310,7 +310,7 @@
     final List<Section> sections = <Section>[];
     final List<Snippet> snippets = <Snippet>[];
 
-    for (File file in _listDartFiles(_flutterPackage, recursive: true)) {
+    for (final File file in _listDartFiles(_flutterPackage, recursive: true)) {
       final String relativeFilePath = path.relative(file.path, from: _flutterPackage.path);
       final List<String> sampleLines = file.readAsLinesSync();
       final List<Section> preambleSections = <Section>[];
@@ -326,7 +326,7 @@
       final List<String> block = <String>[];
       List<String> snippetArgs = <String>[];
       Line startLine;
-      for (String line in sampleLines) {
+      for (final String line in sampleLines) {
         lineNumber += 1;
         final String trimmedLine = line.trim();
         if (inSnippet) {
@@ -434,10 +434,10 @@
       }
     }
     print('Found ${sections.length} sample code sections.');
-    for (Section section in sections) {
+    for (final Section section in sections) {
       sectionMap[_writeSection(section).path] = section;
     }
-    for (Snippet snippet in snippets) {
+    for (final Snippet snippet in snippets) {
       final File snippetFile = _writeSnippet(snippet);
       snippet.contents = snippetFile.readAsLinesSync();
       snippetMap[snippetFile.absolute.path] = snippet;
@@ -576,7 +576,7 @@
     );
     bool unknownAnalyzerErrors = false;
     final int headerLength = headers.length + 2;
-    for (String error in errors) {
+    for (final String error in errors) {
       final Match parts = errorPattern.matchAsPrefix(error);
       if (parts != null) {
         final String message = parts[2];
@@ -860,7 +860,7 @@
   String toString() {
     final StringBuffer buf = StringBuffer('snippet ${args.join(' ')}\n');
     int count = start.line;
-    for (String line in input) {
+    for (final String line in input) {
       buf.writeln(' ${count.toString().padLeft(4, ' ')}: $line');
       count++;
     }
diff --git a/dev/bots/analyze.dart b/dev/bots/analyze.dart
index 1da0458..f4a703c 100644
--- a/dev/bots/analyze.dart
+++ b/dev/bots/analyze.dart
@@ -147,11 +147,11 @@
 
 Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches = 2000 }) async {
   final List<String> errors = <String>[];
-  for (File file in _allFiles(workingDirectory, 'dart', minimumMatches: minimumMatches)) {
+  for (final File file in _allFiles(workingDirectory, 'dart', minimumMatches: minimumMatches)) {
     int lineNumber = 0;
     final List<String> lines = file.readAsLinesSync();
     final List<int> linesWithDeprecations = <int>[];
-    for (String line in lines) {
+    for (final String line in lines) {
       if (line.contains(_findDeprecationPattern) &&
           !line.endsWith(_ignoreDeprecation) &&
           !line.contains(_grandfatheredDeprecation)) {
@@ -239,7 +239,7 @@
   assert(!license.endsWith('\n'));
   final String licensePattern = license + '\n' + (trailingBlank ? '\n' : '');
   final List<String> errors = <String>[];
-  for (File file in _allFiles(workingDirectory, extension, minimumMatches: minimumMatches)) {
+  for (final File file in _allFiles(workingDirectory, extension, minimumMatches: minimumMatches)) {
     final String contents = file.readAsStringSync().replaceAll('\r\n', '\n');
     if (contents.isEmpty)
       continue; // let's not go down the /bin/true rabbit hole
@@ -270,8 +270,8 @@
   final List<String> errors = <String>[];
   assert("// foo\nimport 'binding_test.dart' as binding;\n'".contains(_testImportPattern));
   final List<File> dartFiles = _allFiles(path.join(workingDirectory, 'packages'), 'dart', minimumMatches: 1500).toList();
-  for (File file in dartFiles) {
-    for (String line in file.readAsLinesSync()) {
+  for (final File file in dartFiles) {
+    for (final String line in file.readAsLinesSync()) {
       final Match match = _testImportPattern.firstMatch(line);
       if (match != null && !_exemptTestImports.contains(match.group(2)))
         errors.add(file.path);
@@ -365,7 +365,7 @@
 
   final Map<String, List<File>> packageToRegistrants = <String, List<File>>{};
 
-  for (File file in flutterRootDir.listSync(recursive: true).whereType<File>().where(_isGeneratedPluginRegistrant)) {
+  for (final File file in flutterRootDir.listSync(recursive: true).whereType<File>().where(_isGeneratedPluginRegistrant)) {
     final String package = _getPackageFor(file, flutterRootDir);
     final List<File> registrants = packageToRegistrants.putIfAbsent(package, () => <File>[]);
     registrants.add(file);
@@ -373,16 +373,16 @@
 
   final Set<String> outOfDate = <String>{};
 
-  for (String package in packageToRegistrants.keys) {
+  for (final String package in packageToRegistrants.keys) {
     final Map<File, String> fileToContent = <File, String>{};
-    for (File f in packageToRegistrants[package]) {
+    for (final File f in packageToRegistrants[package]) {
       fileToContent[f] = f.readAsStringSync();
     }
     await runCommand(flutter, <String>['inject-plugins'],
       workingDirectory: package,
       outputMode: OutputMode.discard,
     );
-    for (File registrant in fileToContent.keys) {
+    for (final File registrant in fileToContent.keys) {
       if (registrant.readAsStringSync() != fileToContent[registrant]) {
         outOfDate.add(registrant.path);
       }
@@ -422,20 +422,20 @@
   }
   // Verify that the imports are well-ordered.
   final Map<String, Set<String>> dependencyMap = <String, Set<String>>{};
-  for (String directory in directories) {
+  for (final String directory in directories) {
     dependencyMap[directory] = _findFlutterDependencies(path.join(srcPath, directory), errors, checkForMeta: directory != 'foundation');
   }
   assert(dependencyMap['material'].contains('widgets') &&
          dependencyMap['widgets'].contains('rendering') &&
          dependencyMap['rendering'].contains('painting')); // to make sure we're convinced _findFlutterDependencies is finding some
-  for (String package in dependencyMap.keys) {
+  for (final String package in dependencyMap.keys) {
     if (dependencyMap[package].contains(package)) {
       errors.add(
         'One of the files in the $yellow$package$reset package imports that package recursively.'
       );
     }
   }
-  for (String package in dependencyMap.keys) {
+  for (final String package in dependencyMap.keys) {
     final List<String> loop = _deepSearch<String>(dependencyMap, package);
     if (loop != null) {
       errors.add(
@@ -459,7 +459,7 @@
 Future<void> verifyNoBadImportsInFlutterTools(String workingDirectory) async {
   final List<String> errors = <String>[];
   final List<File> files = _allFiles(path.join(workingDirectory, 'packages', 'flutter_tools', 'lib'), 'dart', minimumMatches: 200).toList();
-  for (File file in files) {
+  for (final File file in files) {
     if (file.readAsStringSync().contains('package:flutter_tools/')) {
       errors.add('$yellow${file.path}$reset imports flutter_tools.');
     }
@@ -535,7 +535,7 @@
     .where((File file) => path.extension(file.path) != '.jar')
     .toList();
   final List<String> problems = <String>[];
-  for (File file in files) {
+  for (final File file in files) {
     final List<String> lines = file.readAsLinesSync();
     for (int index = 0; index < lines.length; index += 1) {
       if (lines[index].endsWith(' ')) {
@@ -1004,7 +1004,7 @@
       .map<File>((String filename) => File(path.join(workingDirectory, filename)))
       .toList();
     final List<String> problems = <String>[];
-    for (File file in files) {
+    for (final File file in files) {
       final Uint8List bytes = file.readAsBytesSync();
       try {
         utf8.decode(bytes);
@@ -1156,7 +1156,7 @@
   return _allFiles(srcPath, 'dart', minimumMatches: 1)
     .map<Set<String>>((File file) {
       final Set<String> result = <String>{};
-      for (String line in file.readAsLinesSync()) {
+      for (final String line in file.readAsLinesSync()) {
         Match match = _importPattern.firstMatch(line);
         if (match != null)
           result.add(match.group(2));
@@ -1180,7 +1180,7 @@
 }
 
 List<T> _deepSearch<T>(Map<T, Set<T>> map, T start, [ Set<T> seen ]) {
-  for (T key in map[start]) {
+  for (final T key in map[start]) {
     if (key == start)
       continue; // we catch these separately
     if (seen != null && seen.contains(key))
diff --git a/dev/bots/flutter_compact_formatter.dart b/dev/bots/flutter_compact_formatter.dart
index 5a4bbf6..0b5552c 100644
--- a/dev/bots/flutter_compact_formatter.dart
+++ b/dev/bots/flutter_compact_formatter.dart
@@ -160,7 +160,7 @@
   void finish() {
     final List<String> skipped = <String>[];
     final List<String> failed = <String>[];
-    for (TestResult result in _tests.values) {
+    for (final TestResult result in _tests.values) {
       switch (result.status) {
         case TestStatus.started:
           failed.add('${_red}Unexpectedly failed to complete a test!');
diff --git a/dev/bots/prepare_package.dart b/dev/bots/prepare_package.dart
index ce9bad7..b45bb1d 100644
--- a/dev/bots/prepare_package.dart
+++ b/dev/bots/prepare_package.dart
@@ -354,7 +354,7 @@
     // Create each of the templates, since they will call 'pub get' on
     // themselves when created, and this will warm the cache with their
     // dependencies too.
-    for (String template in <String>['app', 'package', 'plugin']) {
+    for (final String template in <String>['app', 'package', 'plugin']) {
       final String createName = path.join(tempDir.path, 'create_$template');
       await _runFlutter(
         <String>['create', '--template=$template', createName],
@@ -528,7 +528,7 @@
     // Search for any entries with the same hash and channel and remove them.
     final List<dynamic> releases = jsonData['releases'] as List<dynamic>;
     jsonData['releases'] = <Map<String, dynamic>>[
-      for (Map<String, dynamic> entry in releases.cast<Map<String, dynamic>>())
+      for (final Map<String, dynamic> entry in releases.cast<Map<String, dynamic>>())
         if (entry['hash'] != newEntry['hash'] || entry['channel'] != newEntry['channel'])
           entry,
       newEntry,
diff --git a/dev/bots/run_command.dart b/dev/bots/run_command.dart
index 1407067..2577433 100644
--- a/dev/bots/run_command.dart
+++ b/dev/bots/run_command.dart
@@ -37,7 +37,7 @@
 
   stderr.addStream(process.stderr);
   final Stream<String> lines = process.stdout.transform(utf8.decoder).transform(const LineSplitter());
-  await for (String line in lines)
+  await for (final String line in lines)
     yield line;
 
   final int exitCode = await process.exitCode;
diff --git a/dev/bots/test.dart b/dev/bots/test.dart
index 05fee88..92fd621 100644
--- a/dev/bots/test.dart
+++ b/dev/bots/test.dart
@@ -295,7 +295,7 @@
 /// target app.
 Future<void> _runBuildTests() async {
   final Stream<FileSystemEntity> exampleDirectories = Directory(path.join(flutterRoot, 'examples')).list();
-  await for (FileSystemEntity fileEntity in exampleDirectories) {
+  await for (final FileSystemEntity fileEntity in exampleDirectories) {
     if (fileEntity is! Directory) {
       continue;
     }
@@ -817,7 +817,7 @@
       last = '_last';
     }
     subshards['$subshard$last'] = () async {
-      for (ShardRunner test in sublist)
+      for (final ShardRunner test in sublist)
         await test();
     };
   }
@@ -1020,7 +1020,7 @@
     item = parts[positionInTaskName];
   }
   if (item == null) {
-    for (String currentItem in items.keys) {
+    for (final String currentItem in items.keys) {
       print('$bold$key=$currentItem$reset');
       await items[currentItem]();
       print('');
diff --git a/dev/bots/test/fake_process_manager.dart b/dev/bots/test/fake_process_manager.dart
index 521e8c2..04d2317 100644
--- a/dev/bots/test/fake_process_manager.dart
+++ b/dev/bots/test/fake_process_manager.dart
@@ -34,7 +34,7 @@
   Map<String, List<ProcessResult>> get fakeResults => _fakeResults;
   set fakeResults(Map<String, List<ProcessResult>> value) {
     _fakeResults = <String, List<ProcessResult>>{};
-    for (String key in value.keys) {
+    for (final String key in value.keys) {
       _fakeResults[key] = (value[key] ?? <ProcessResult>[ProcessResult(0, 0, '', '')]).toList();
     }
   }
@@ -46,7 +46,7 @@
   /// parameters were in the same order.
   void verifyCalls(List<String> calls) {
     int index = 0;
-    for (String call in calls) {
+    for (final String call in calls) {
       expect(call.split(' '), orderedEquals(invocations[index].positionalArguments[0] as Iterable<dynamic>));
       index++;
     }
@@ -178,7 +178,7 @@
 
   @override
   Future<dynamic> close() async {
-    for (Completer<dynamic> completer in completers) {
+    for (final Completer<dynamic> completer in completers) {
       await completer.future;
     }
     completers.clear();
diff --git a/dev/bots/test/fake_process_manager_test.dart b/dev/bots/test/fake_process_manager_test.dart
index b74576c..6782c02 100644
--- a/dev/bots/test/fake_process_manager_test.dart
+++ b/dev/bots/test/fake_process_manager_test.dart
@@ -34,7 +34,7 @@
         ],
       };
       processManager.fakeResults = calls;
-      for (String key in calls.keys) {
+      for (final String key in calls.keys) {
         final Process process = await processManager.start(key.split(' '));
         String output = '';
         process.stdout.listen((List<int> item) {
@@ -56,7 +56,7 @@
         ],
       };
       processManager.fakeResults = calls;
-      for (String key in calls.keys) {
+      for (final String key in calls.keys) {
         final ProcessResult result = await processManager.run(key.split(' '));
         expect(result.stdout, equals(calls[key][0].stdout));
       }
@@ -73,7 +73,7 @@
         ],
       };
       processManager.fakeResults = calls;
-      for (String key in calls.keys) {
+      for (final String key in calls.keys) {
         final ProcessResult result = processManager.runSync(key.split(' '));
         expect(result.stdout, equals(calls[key][0].stdout));
       }
@@ -90,7 +90,7 @@
         ],
       };
       processManager.fakeResults = calls;
-      for (String key in calls.keys) {
+      for (final String key in calls.keys) {
         final Process process = await processManager.start(key.split(' '));
         String output = '';
         process.stdout.listen((List<int> item) {
diff --git a/dev/bots/test/prepare_package_test.dart b/dev/bots/test/prepare_package_test.dart
index b7054fe..9f4a122 100644
--- a/dev/bots/test/prepare_package_test.dart
+++ b/dev/bots/test/prepare_package_test.dart
@@ -35,7 +35,7 @@
       );
     }
   });
-  for (String platformName in <String>['macos', 'linux', 'windows']) {
+  for (final String platformName in <String>['macos', 'linux', 'windows']) {
     final FakePlatform platform = FakePlatform(
       operatingSystem: platformName,
       environment: <String, String>{
diff --git a/dev/bots/test/test_test.dart b/dev/bots/test/test_test.dart
index ce2e3fb..debf9ca 100644
--- a/dev/bots/test/test_test.dart
+++ b/dev/bots/test/test_test.dart
@@ -27,7 +27,7 @@
         '1.2.3+hotfix.1',
         '1.2.3+hotfix.12-pre.12',
       ];
-      for (String version in valid_versions) {
+      for (final String version in valid_versions) {
         when(file.readAsString()).thenAnswer((Invocation invocation) => Future<String>.value(version));
         expect(
           await verifyVersion(file),
@@ -47,7 +47,7 @@
         '  1.2.3',
         '1.2.3-hotfix.1',
       ];
-      for (String version in invalid_versions) {
+      for (final String version in invalid_versions) {
         when(file.readAsString()).thenAnswer((Invocation invocation) => Future<String>.value(version));
         expect(
           await verifyVersion(file),
diff --git a/dev/bots/unpublish_package.dart b/dev/bots/unpublish_package.dart
index 3da5bf6..581cd8f 100644
--- a/dev/bots/unpublish_package.dart
+++ b/dev/bots/unpublish_package.dart
@@ -254,7 +254,7 @@
       return bDate.compareTo(aDate);
     });
     jsonData['releases'] = releases;
-    for (Channel channel in channels) {
+    for (final Channel channel in channels) {
       if (!revisionsBeingRemoved.contains(jsonData['current_release'][getChannelName(channel)])) {
         // Don't replace the current release if it's not one of the revisions we're removing.
         continue;
@@ -276,7 +276,7 @@
   Future<Map<Channel, Map<String, String>>> _getArchivePaths(List<Map<String, String>> releases) async {
     final Set<String> hashes = <String>{};
     final Map<Channel, Map<String, String>> paths = <Channel, Map<String, String>>{};
-    for (Map<String, String> revision in releases) {
+    for (final Map<String, String> revision in releases) {
       final String hash = revision['hash'];
       final Channel channel = fromChannelName(revision['channel']);
       hashes.add(hash);
@@ -350,9 +350,9 @@
   Future<void> _cloudRemoveArchive(Map<Channel, Map<String, String>> paths) async {
     final List<String> files = <String>[];
     print('${confirmed ? 'Removing' : 'Would remove'} the following release archives:');
-    for (Channel channel in paths.keys) {
+    for (final Channel channel in paths.keys) {
       final Map<String, String> hashes = paths[channel];
-      for (String hash in hashes.keys) {
+      for (final String hash in hashes.keys) {
         final String file = '$gsReleaseFolder/${hashes[hash]}';
         files.add(file);
         print('  $file');
@@ -464,7 +464,7 @@
   if (revisions.isEmpty) {
     errorExit('Invalid argument: at least one --revision must be specified.');
   }
-  for (String revision in revisions) {
+  for (final String revision in revisions) {
     if (revision.length != 40) {
       errorExit('Invalid argument: --revision "$revision" must be the entire hash, not just a prefix.');
     }
@@ -500,7 +500,7 @@
   String message;
   String stack;
   try {
-    for (PublishedPlatform platform in platforms) {
+    for (final PublishedPlatform platform in platforms) {
       final ArchiveUnpublisher publisher = ArchiveUnpublisher(
         tempDir,
         revisions.toSet(),