Migrate template to null safety (#80016)

diff --git a/packages/flutter_tools/lib/src/android/deferred_components_prebuild_validator.dart b/packages/flutter_tools/lib/src/android/deferred_components_prebuild_validator.dart
index 69aa782..4839766 100644
--- a/packages/flutter_tools/lib/src/android/deferred_components_prebuild_validator.dart
+++ b/packages/flutter_tools/lib/src/android/deferred_components_prebuild_validator.dart
@@ -267,7 +267,7 @@
         templateRenderer: globals.templateRenderer,
       );
     }
-    final Map<String, dynamic> context = <String, dynamic>{
+    final Map<String, Object> context = <String, Object>{
       'androidIdentifier': FlutterProject.current().manifest.androidPackage ?? 'com.example.${FlutterProject.current().manifest.appName}',
       'componentName': name,
     };
diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart
index d0d7290..cc876be 100644
--- a/packages/flutter_tools/lib/src/commands/create.dart
+++ b/packages/flutter_tools/lib/src/commands/create.dart
@@ -227,7 +227,7 @@
       );
     }
 
-    final Map<String, dynamic> templateContext = createTemplateContext(
+    final Map<String, Object> templateContext = createTemplateContext(
       organization: organization,
       projectName: projectName,
       projectDescription: stringArg('description'),
diff --git a/packages/flutter_tools/lib/src/commands/create_base.dart b/packages/flutter_tools/lib/src/commands/create_base.dart
index 1d820bd..1aba583 100644
--- a/packages/flutter_tools/lib/src/commands/create_base.dart
+++ b/packages/flutter_tools/lib/src/commands/create_base.dart
@@ -312,7 +312,7 @@
 
   /// Creates a template to use for [renderTemplate].
   @protected
-  Map<String, dynamic> createTemplateContext({
+  Map<String, Object> createTemplateContext({
     String organization,
     String projectName,
     String projectDescription,
@@ -344,7 +344,7 @@
     // https://developer.gnome.org/gio/stable/GApplication.html#g-application-id-is-valid
     final String linuxIdentifier = androidIdentifier;
 
-    return <String, dynamic>{
+    return <String, Object>{
       'organization': organization,
       'projectName': projectName,
       'androidIdentifier': androidIdentifier,
@@ -385,7 +385,7 @@
   /// If `overwrite` is true, overwrites existing files, `overwrite` defaults to `false`.
   @protected
   Future<int> renderTemplate(
-      String templateName, Directory directory, Map<String, dynamic> context,
+      String templateName, Directory directory, Map<String, Object> context,
       {bool overwrite = false}) async {
     final Template template = await Template.fromName(
       templateName,
@@ -402,7 +402,7 @@
   /// If `overwrite` is true, overwrites existing files, `overwrite` defaults to `false`.
   @protected
   Future<int> generateApp(
-      Directory directory, Map<String, dynamic> templateContext,
+      Directory directory, Map<String, Object> templateContext,
       {bool overwrite = false, bool pluginExampleApp = false}) async {
     int generatedCount = 0;
     generatedCount += await renderTemplate(
diff --git a/packages/flutter_tools/lib/src/commands/ide_config.dart b/packages/flutter_tools/lib/src/commands/ide_config.dart
index cf5c6b6..fdbf7a6 100644
--- a/packages/flutter_tools/lib/src/commands/ide_config.dart
+++ b/packages/flutter_tools/lib/src/commands/ide_config.dart
@@ -234,7 +234,7 @@
 
     globals.printStatus('Updating IDE configuration for Flutter tree at $dirPath...');
     int generatedCount = 0;
-    generatedCount += _renderTemplate(_ideName, dirPath, <String, dynamic>{
+    generatedCount += _renderTemplate(_ideName, dirPath, <String, Object>{
       'withRootModule': boolArg('with-root-module'),
       'android': true,
     });
@@ -247,7 +247,7 @@
     return FlutterCommandResult.success();
   }
 
-  int _renderTemplate(String templateName, String dirPath, Map<String, dynamic> context) {
+  int _renderTemplate(String templateName, String dirPath, Map<String, Object> context) {
     final Template template = Template(
       _templateDirectory,
       _templateDirectory,
diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart
index 2628996..a89afa0 100644
--- a/packages/flutter_tools/lib/src/project.dart
+++ b/packages/flutter_tools/lib/src/project.dart
@@ -786,7 +786,7 @@
     );
     template.render(
       target,
-      <String, dynamic>{
+      <String, Object>{
         'ios': true,
         'projectName': parent.manifest.appName,
         'iosIdentifier': parent.manifest.iosBundleIdentifier,
@@ -970,7 +970,7 @@
     );
     template.render(
       target,
-      <String, dynamic>{
+      <String, Object>{
         'android': true,
         'projectName': parent.manifest.appName,
         'androidIdentifier': parent.manifest.androidPackage,
diff --git a/packages/flutter_tools/lib/src/template.dart b/packages/flutter_tools/lib/src/template.dart
index 0489642..0e5ecf2 100644
--- a/packages/flutter_tools/lib/src/template.dart
+++ b/packages/flutter_tools/lib/src/template.dart
@@ -2,9 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// @dart = 2.8
-
-import 'package:meta/meta.dart';
 import 'package:package_config/package_config.dart';
 import 'package:package_config/package_config_types.dart';
 
@@ -33,23 +30,21 @@
 /// 'img.tmpl', or '-<language>.tmpl' extensions.
 class Template {
   Template(Directory templateSource, Directory baseDir, this.imageSourceDir, {
-    @required FileSystem fileSystem,
-    @required Logger logger,
-    @required TemplateRenderer templateRenderer,
-    @required Set<Uri> templateManifest,
+    required FileSystem fileSystem,
+    required Logger logger,
+    required TemplateRenderer templateRenderer,
+    required Set<Uri>? templateManifest,
   }) : _fileSystem = fileSystem,
        _logger = logger,
        _templateRenderer = templateRenderer,
-       _templateManifest = templateManifest {
-    _templateFilePaths = <String, String>{};
-
+       _templateManifest = templateManifest ?? <Uri>{} {
     if (!templateSource.existsSync()) {
       return;
     }
 
     final List<FileSystemEntity> templateFiles = templateSource.listSync(recursive: true);
     for (final FileSystemEntity entity in templateFiles.whereType<File>()) {
-      if (_templateManifest != null && !_templateManifest.contains(Uri.file(entity.absolute.path))) {
+      if (_templateManifest.isNotEmpty && !_templateManifest.contains(Uri.file(entity.absolute.path))) {
         _logger.printTrace('Skipping ${entity.absolute.path}, missing from the template manifest.');
         // Skip stale files in the flutter_tools directory.
         continue;
@@ -67,10 +62,10 @@
   }
 
   static Future<Template> fromName(String name, {
-    @required FileSystem fileSystem,
-    @required Set<Uri> templateManifest,
-    @required Logger logger,
-    @required TemplateRenderer templateRenderer,
+    required FileSystem fileSystem,
+    required Set<Uri>? templateManifest,
+    required Logger logger,
+    required TemplateRenderer templateRenderer,
   }) async {
     // All named templates are placed in the 'templates' directory
     final Directory templateDir = _templateDirectoryInPackage(name, fileSystem);
@@ -96,14 +91,14 @@
   final Pattern _kTemplateLanguageVariant = RegExp(r'(\w+)-(\w+)\.tmpl.*');
   final Directory imageSourceDir;
 
-  Map<String /* relative */, String /* absolute source */> _templateFilePaths;
+  final Map<String /* relative */, String /* absolute source */> _templateFilePaths = <String, String>{};
 
   /// Render the template into [directory].
   ///
   /// May throw a [ToolExit] if the directory is not writable.
   int render(
     Directory destination,
-    Map<String, dynamic> context, {
+    Map<String, Object> context, {
     bool overwriteExisting = true,
     bool printStatusWhenWriting = true,
   }) {
@@ -120,57 +115,57 @@
     /// expansion on the path itself.
     ///
     /// Returns null if the given raw destination path has been filtered.
-    String renderPath(String relativeDestinationPath) {
-      final Match match = _kTemplateLanguageVariant.matchAsPrefix(relativeDestinationPath);
+    String? renderPath(String relativeDestinationPath) {
+      final Match? match = _kTemplateLanguageVariant.matchAsPrefix(relativeDestinationPath);
       if (match != null) {
-        final String platform = match.group(1);
-        final String language = context['${platform}Language'] as String;
+        final String platform = match.group(1)!;
+        final String? language = context['${platform}Language'] as String?;
         if (language != match.group(2)) {
           return null;
         }
         relativeDestinationPath = relativeDestinationPath.replaceAll('$platform-$language.tmpl', platform);
       }
 
-      final bool android = context['android'] as bool;
+      final bool android = (context['android'] as bool?) == true;
       if (relativeDestinationPath.contains('android') && !android) {
         return null;
       }
 
-      final bool ios = context['ios'] as bool;
+      final bool ios = (context['ios'] as bool?) == true;
       if (relativeDestinationPath.contains('ios') && !ios) {
         return null;
       }
 
       // Only build a web project if explicitly asked.
-      final bool web = context['web'] as bool;
+      final bool web = (context['web'] as bool?) == true;
       if (relativeDestinationPath.contains('web') && !web) {
         return null;
       }
       // Only build a Linux project if explicitly asked.
-      final bool linux = context['linux'] as bool;
+      final bool linux = (context['linux'] as bool?) == true;
       if (relativeDestinationPath.startsWith('linux.tmpl') && !linux) {
         return null;
       }
       // Only build a macOS project if explicitly asked.
-      final bool macOS = context['macos'] as bool;
+      final bool macOS = (context['macos'] as bool?) == true;
       if (relativeDestinationPath.startsWith('macos.tmpl') && !macOS) {
         return null;
       }
       // Only build a Windows project if explicitly asked.
-      final bool windows = context['windows'] as bool;
+      final bool windows = (context['windows'] as bool?) == true;
       if (relativeDestinationPath.startsWith('windows.tmpl') && !windows) {
         return null;
       }
       // Only build a Windows UWP project if explicitly asked.
-      final bool windowsUwp = context['winuwp'] as bool;
+      final bool windowsUwp = (context['winuwp'] as bool?) == true;
       if (relativeDestinationPath.startsWith('winuwp.tmpl') && !windowsUwp) {
         return null;
       }
 
-      final String projectName = context['projectName'] as String;
-      final String androidIdentifier = context['androidIdentifier'] as String;
-      final String pluginClass = context['pluginClass'] as String;
-      final String pluginClassSnakeCase = context['pluginClassSnakeCase'] as String;
+      final String? projectName = context['projectName'] as String?;
+      final String? androidIdentifier = context['androidIdentifier'] as String?;
+      final String? pluginClass = context['pluginClass'] as String?;
+      final String? pluginClassSnakeCase = context['pluginClassSnakeCase'] as String?;
       final String destinationDirPath = destination.absolute.path;
       final String pathSeparator = _fileSystem.path.separator;
       String finalDestinationPath = _fileSystem.path
@@ -197,12 +192,12 @@
     }
 
     _templateFilePaths.forEach((String relativeDestinationPath, String absoluteSourcePath) {
-      final bool withRootModule = context['withRootModule'] as bool ?? false;
+      final bool withRootModule = context['withRootModule'] as bool? ?? false;
       if (!withRootModule && absoluteSourcePath.contains('flutter_root')) {
         return;
       }
 
-      final String finalDestinationPath = renderPath(relativeDestinationPath);
+      final String? finalDestinationPath = renderPath(relativeDestinationPath);
       if (finalDestinationPath == null) {
         return;
       }
@@ -277,7 +272,7 @@
 }
 
 Directory _templateDirectoryInPackage(String name, FileSystem fileSystem) {
-  final String templatesDir = fileSystem.path.join(Cache.flutterRoot,
+  final String templatesDir = fileSystem.path.join(Cache.flutterRoot!,
       'packages', 'flutter_tools', 'templates');
   return fileSystem.directory(fileSystem.path.join(templatesDir, name));
 }
@@ -286,13 +281,13 @@
 // flutter_template_images, to resolve image placeholder against.
 Future<Directory> _templateImageDirectory(String name, FileSystem fileSystem, Logger logger) async {
   final String toolPackagePath = fileSystem.path.join(
-      Cache.flutterRoot, 'packages', 'flutter_tools');
+      Cache.flutterRoot!, 'packages', 'flutter_tools');
   final String packageFilePath = fileSystem.path.join(toolPackagePath, '.dart_tool', 'package_config.json');
   final PackageConfig packageConfig = await loadPackageConfigWithLogging(
     fileSystem.file(packageFilePath),
     logger: logger,
   );
-  final Uri imagePackageLibDir = packageConfig['flutter_template_images']?.packageUriRoot;
+  final Uri? imagePackageLibDir = packageConfig['flutter_template_images']?.packageUriRoot;
   return fileSystem.directory(imagePackageLibDir)
       .parent
       .childDirectory('templates')
diff --git a/packages/flutter_tools/test/template_test.dart b/packages/flutter_tools/test/general.shard/template_test.dart
similarity index 97%
rename from packages/flutter_tools/test/template_test.dart
rename to packages/flutter_tools/test/general.shard/template_test.dart
index 71b4edc..9b2cd56 100644
--- a/packages/flutter_tools/test/template_test.dart
+++ b/packages/flutter_tools/test/general.shard/template_test.dart
@@ -2,15 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// @dart = 2.8
-
 import 'package:file/memory.dart';
 import 'package:file_testing/file_testing.dart';
 import 'package:flutter_tools/src/base/file_system.dart';
 import 'package:flutter_tools/src/base/logger.dart';
 import 'package:flutter_tools/src/base/template.dart';
 import 'package:flutter_tools/src/template.dart';
-import 'src/common.dart';
+import '../src/common.dart';
 
 void main() {
   testWithoutContext('Template.render throws ToolExit when FileSystem exception is raised', () {
@@ -19,7 +17,7 @@
     final Template template = Template(
       fileSystem.directory('examples'),
       fileSystem.currentDirectory,
-      null,
+      fileSystem.currentDirectory,
       fileSystem: fileSystem,
       logger: BufferLogger.test(),
       templateRenderer: FakeTemplateRenderer(),