Migrate protoc_plugin to null safety (#642)

This is mostly a sync of cl/337728412 with some extra changes in
diverged parts.
diff --git a/protoc_plugin/bin/protoc_plugin.dart b/protoc_plugin/bin/protoc_plugin.dart
index 8e45871..54da34c 100755
--- a/protoc_plugin/bin/protoc_plugin.dart
+++ b/protoc_plugin/bin/protoc_plugin.dart
@@ -3,8 +3,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'dart:io';
 
 import 'package:protoc_plugin/protoc.dart';
diff --git a/protoc_plugin/bin/protoc_plugin_bazel.dart b/protoc_plugin/bin/protoc_plugin_bazel.dart
index 843239e..ce74938 100755
--- a/protoc_plugin/bin/protoc_plugin_bazel.dart
+++ b/protoc_plugin/bin/protoc_plugin_bazel.dart
@@ -3,8 +3,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'dart:io';
 
 import 'package:protoc_plugin/bazel.dart';
diff --git a/protoc_plugin/lib/names.dart b/protoc_plugin/lib/names.dart
index a209443..170fb0b 100644
--- a/protoc_plugin/lib/names.dart
+++ b/protoc_plugin/lib/names.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'dart:math' as math;
 
 import 'package:protobuf/meta.dart';
@@ -24,11 +22,15 @@
 
   /// The index of this field in MessageGenerator.fieldList.
   /// The same index will be stored in FieldInfo.index.
-  final int index;
+  ///
+  /// `null` for extensions.
+  final int? index;
 
   /// The position of this field as it appeared in the original DescriptorProto.
   /// Used to construct metadata.
-  final int sourcePosition;
+  ///
+  /// `null` for extensions.
+  final int? sourcePosition;
 
   /// Identifier for generated getters/setters.
   final String fieldName;
@@ -36,17 +38,17 @@
   /// Identifier for the generated hasX() method, without braces.
   ///
   /// `null` for repeated fields.
-  final String hasMethodName;
+  final String? hasMethodName;
 
   /// Identifier for the generated clearX() method, without braces.
   ///
   /// `null` for repeated fields.
-  final String clearMethodName;
+  final String? clearMethodName;
 
   // Identifier for the generated ensureX() method, without braces.
   //
-  //'null' for scalar, repeated, and map fields.
-  final String ensureMethodName;
+  // 'null' for scalar, repeated, and map fields.
+  final String? ensureMethodName;
 
   FieldNames(this.descriptor, this.index, this.sourcePosition, this.fieldName,
       {this.hasMethodName, this.clearMethodName, this.ensureMethodName});
@@ -158,7 +160,7 @@
 /// The returned name is that, which will generate the accepted variants.
 String disambiguateName(
     String name, Set<String> usedNames, Iterable<String> suffixes,
-    {List<String> Function(String candidate) generateVariants}) {
+    {List<String> Function(String candidate)? generateVariants}) {
   generateVariants ??= (String name) => <String>[name];
 
   bool allVariantsAvailable(List<String> variants) {
@@ -259,21 +261,19 @@
     indexes[field.name] = index;
   }
 
-  var existingNames = <String>{}
-    ..addAll(reservedMemberNames)
-    ..addAll(reserved);
+  var existingNames = <String>{...reservedMemberNames, ...reserved};
 
-  var fieldNames = List<FieldNames>.filled(indexes.length, null);
+  var fieldNames = List<FieldNames?>.filled(indexes.length, null);
 
   void takeFieldNames(FieldNames chosen) {
-    fieldNames[chosen.index] = chosen;
+    fieldNames[chosen.index!] = chosen;
 
     existingNames.add(chosen.fieldName);
     if (chosen.hasMethodName != null) {
-      existingNames.add(chosen.hasMethodName);
+      existingNames.add(chosen.hasMethodName!);
     }
     if (chosen.clearMethodName != null) {
-      existingNames.add(chosen.clearMethodName);
+      existingNames.add(chosen.clearMethodName!);
     }
   }
 
@@ -281,17 +281,17 @@
   // They have higher priority than automatically chosen names.
   // Explicitly setting a name that's already taken is a build error.
   for (var field in sorted) {
-    if (_nameOption(field).isNotEmpty) {
+    if (_nameOption(field)!.isNotEmpty) {
       takeFieldNames(_memberNamesFromOption(descriptor, field,
-          indexes[field.name], sourcePositions[field.name], existingNames));
+          indexes[field.name]!, sourcePositions[field.name]!, existingNames));
     }
   }
 
   // Then do other fields.
   // They are automatically renamed until we find something unused.
   for (var field in sorted) {
-    if (_nameOption(field).isEmpty) {
-      var index = indexes[field.name];
+    if (_nameOption(field)!.isEmpty) {
+      var index = indexes[field.name]!;
       var sourcePosition = sourcePositions[field.name];
       takeFieldNames(
           _unusedMemberNames(field, index, sourcePosition, existingNames));
@@ -302,16 +302,9 @@
 
   void takeOneofNames(OneofNames chosen) {
     oneofNames.add(chosen);
-
-    if (chosen.whichOneofMethodName != null) {
-      existingNames.add(chosen.whichOneofMethodName);
-    }
-    if (chosen.clearMethodName != null) {
-      existingNames.add(chosen.clearMethodName);
-    }
-    if (chosen.byTagMapName != null) {
-      existingNames.add(chosen.byTagMapName);
-    }
+    existingNames.add(chosen.whichOneofMethodName);
+    existingNames.add(chosen.clearMethodName);
+    existingNames.add(chosen.byTagMapName);
   }
 
   List<String> oneofNameVariants(String name) {
@@ -336,7 +329,7 @@
         _defaultWhichMethodName(oneofName), oneofEnumName, enumMapName));
   }
 
-  return MemberNames(fieldNames, oneofNames);
+  return MemberNames(fieldNames.cast<FieldNames>(), oneofNames);
 }
 
 /// Chooses the member names for a field that has the 'dart_name' option.
@@ -359,7 +352,7 @@
     }
   }
 
-  var name = _nameOption(field);
+  var name = _nameOption(field)!;
   if (name.isEmpty) {
     throw ArgumentError("field doesn't have dart_name option");
   }
@@ -379,7 +372,7 @@
   var clearMethod = 'clear${_capitalize(name)}';
   checkAvailable(clearMethod);
 
-  String ensureMethod;
+  String? ensureMethod;
 
   if (_isGroupOrMessage(field)) {
     ensureMethod = 'ensure${_capitalize(name)}';
@@ -399,8 +392,8 @@
   }
 }
 
-FieldNames _unusedMemberNames(FieldDescriptorProto field, int index,
-    int sourcePosition, Set<String> existingNames) {
+FieldNames _unusedMemberNames(FieldDescriptorProto field, int? index,
+    int? sourcePosition, Set<String> existingNames) {
   if (_isRepeated(field)) {
     return FieldNames(
         field,
@@ -454,7 +447,7 @@
 /// The suffix to use for this field in Dart method names.
 /// (It should be camelcase and begin with an uppercase letter.)
 String _fieldMethodSuffix(FieldDescriptorProto field) {
-  var name = _nameOption(field);
+  var name = _nameOption(field)!;
   if (name.isNotEmpty) return _capitalize(name);
 
   if (field.type != FieldDescriptorProto_Type.TYPE_GROUP) {
@@ -483,8 +476,8 @@
     field.type == FieldDescriptorProto_Type.TYPE_MESSAGE ||
     field.type == FieldDescriptorProto_Type.TYPE_GROUP;
 
-String _nameOption(FieldDescriptorProto field) =>
-    field.options.getExtension(Dart_options.dartName) as String;
+String? _nameOption(FieldDescriptorProto field) =>
+    field.options.getExtension(Dart_options.dartName) as String?;
 
 bool _isDartFieldName(String name) => name.startsWith(_dartFieldNameExpr);
 
diff --git a/protoc_plugin/lib/protoc.dart b/protoc_plugin/lib/protoc.dart
index cba09b7..f6001b3 100644
--- a/protoc_plugin/lib/protoc.dart
+++ b/protoc_plugin/lib/protoc.dart
@@ -1,5 +1,3 @@
-// @dart=2.11
-
 import 'dart:convert';
 
 import 'package:dart_style/dart_style.dart';
diff --git a/protoc_plugin/lib/src/base_type.dart b/protoc_plugin/lib/src/base_type.dart
index f9326da..4721566 100644
--- a/protoc_plugin/lib/src/base_type.dart
+++ b/protoc_plugin/lib/src/base_type.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 part of '../protoc.dart';
 
 /// Represents the base type of a particular field in a proto definition.
@@ -19,11 +17,11 @@
   final String typeConstantSuffix;
 
   // Method name of the setter method for this type.
-  final String setter;
+  final String? setter;
 
   // The generator corresponding to this type.
   // (Null for primitive types.)
-  final ProtobufContainer generator;
+  final ProtobufContainer? generator;
 
   const BaseType._raw(this.descriptor, this.typeConstantSuffix, this.unprefixed,
       this.setter, this.generator);
@@ -37,12 +35,12 @@
 
   /// The package where this type is declared.
   /// (Always the empty string for primitive types.)
-  String get package => generator == null ? '' : generator.package;
+  String get package => generator == null ? '' : generator!.package;
 
   /// The Dart expression to use for this type when in a different file.
   String get prefixed => generator == null
       ? unprefixed
-      : generator.fileImportPrefix + '.' + unprefixed;
+      : generator!.fileImportPrefix + '.' + unprefixed;
 
   /// Returns the name to use in generated code for this Dart type.
   ///
@@ -135,6 +133,6 @@
     }
 
     return BaseType._raw(
-        field.type, constSuffix, generator.classname, null, generator);
+        field.type, constSuffix, generator.classname!, null, generator);
   }
 }
diff --git a/protoc_plugin/lib/src/client_generator.dart b/protoc_plugin/lib/src/client_generator.dart
index 500c0c9..8fa0374 100644
--- a/protoc_plugin/lib/src/client_generator.dart
+++ b/protoc_plugin/lib/src/client_generator.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 part of '../protoc.dart';
 
 class ClientApiGenerator {
diff --git a/protoc_plugin/lib/src/code_generator.dart b/protoc_plugin/lib/src/code_generator.dart
index 9b900ea..1d93559 100644
--- a/protoc_plugin/lib/src/code_generator.dart
+++ b/protoc_plugin/lib/src/code_generator.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'dart:io';
 
 import 'package:fixnum/fixnum.dart';
@@ -23,7 +21,7 @@
   static int _idx = 0;
 
   String get package;
-  String get classname;
+  String? get classname;
   String get fullName;
 
   /// The field path contains the field IDs and indices (for repeated fields)
@@ -32,7 +30,7 @@
   /// the message in question.
   /// For more information see
   /// https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/descriptor.proto#L728
-  List<int> get fieldPath;
+  List<int>? get fieldPath;
 
   /// The fully qualified name with a leading '.'.
   ///
@@ -42,12 +40,12 @@
   String get fileImportPrefix => _getFileImportPrefix();
 
   String get binaryDescriptorName =>
-      '${lowerCaseFirstLetter(classname)}Descriptor';
+      '${lowerCaseFirstLetter(classname!)}Descriptor';
 
   String _getFileImportPrefix() {
-    var path = fileGen.protoFileUri.toString();
+    var path = fileGen!.protoFileUri.toString();
     if (_importPrefixes.containsKey(path)) {
-      return _importPrefixes[path];
+      return _importPrefixes[path]!;
     }
     final alias = '\$$_idx';
     _importPrefixes[path] = alias;
@@ -58,21 +56,21 @@
   /// The generator of the .pb.dart file defining this entity.
   ///
   /// (Represents the .pb.dart file that we need to import in order to use it.)
-  FileGenerator get fileGen;
+  FileGenerator? get fileGen;
 
   // The generator containing this entity.
-  ProtobufContainer get parent;
+  ProtobufContainer? get parent;
 
   /// The top-level parent of this entity. If this entity is a top-level entity,
   /// returns this.
-  ProtobufContainer get toplevelParent {
+  ProtobufContainer? get toplevelParent {
     if (parent == null) {
       return null;
     }
     if (parent is FileGenerator) {
       return this;
     }
-    return parent.toplevelParent;
+    return parent?.toplevelParent;
   }
 }
 
@@ -88,10 +86,8 @@
   /// generated files are created and how imports between generated files are
   /// constructed (see [OutputConfiguration] for details).
   void generate(
-      {Map<String, SingleOptionParser> optionParsers,
-      OutputConfiguration config}) {
-    config ??= DefaultOutputConfiguration();
-
+      {Map<String, SingleOptionParser>? optionParsers,
+      OutputConfiguration config = const DefaultOutputConfiguration()}) {
     var extensions = ExtensionRegistry();
     Dart_options.registerAllExtensions(extensions);
 
@@ -136,14 +132,19 @@
 
   @override
   String get package => '';
+
   @override
-  String get classname => null;
+  String? get classname => null;
+
   @override
   String get fullName => '';
+
   @override
-  FileGenerator get fileGen => null;
+  FileGenerator? get fileGen => null;
+
   @override
-  ProtobufContainer get parent => null;
+  ProtobufContainer? get parent => null;
+
   @override
-  List<int> get fieldPath => [];
+  List<int>? get fieldPath => [];
 }
diff --git a/protoc_plugin/lib/src/enum_generator.dart b/protoc_plugin/lib/src/enum_generator.dart
index 2b3da04..b1159ce 100644
--- a/protoc_plugin/lib/src/enum_generator.dart
+++ b/protoc_plugin/lib/src/enum_generator.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 part of '../protoc.dart';
 
 class EnumAlias {
@@ -14,11 +12,14 @@
 
 class EnumGenerator extends ProtobufContainer {
   @override
-  final ProtobufContainer parent;
+  final ProtobufContainer? parent;
+
   @override
-  final String classname;
+  final String? classname;
+
   @override
   final String fullName;
+
   final EnumDescriptorProto _descriptor;
   final List<EnumValueDescriptorProto> _canonicalValues =
       <EnumValueDescriptorProto>[];
@@ -28,20 +29,19 @@
   /// Maps the name of an enum value to the Dart name we will use for it.
   final Map<String, String> dartNames = <String, String>{};
   final List<int> _originalAliasIndices = <int>[];
-  List<int> _fieldPath;
+  List<int>? _fieldPath;
   final List<int> _fieldPathSegment;
 
   /// See [[ProtobufContainer]
   @override
-  List<int> get fieldPath =>
-      _fieldPath ??= List.from(parent.fieldPath)..addAll(_fieldPathSegment);
+  List<int>? get fieldPath =>
+      _fieldPath ??= List.from(parent!.fieldPath!)..addAll(_fieldPathSegment);
 
   EnumGenerator._(EnumDescriptorProto descriptor, this.parent,
       Set<String> usedClassNames, int repeatedFieldIndex, int fieldIdTag)
-      : assert(parent != null),
-        _fieldPathSegment = [fieldIdTag, repeatedFieldIndex],
+      : _fieldPathSegment = [fieldIdTag, repeatedFieldIndex],
         classname = messageOrEnumClassName(descriptor.name, usedClassNames,
-            parent: parent?.classname ?? ''),
+            parent: parent!.classname ?? ''),
         fullName = parent.fullName == ''
             ? descriptor.name
             : '${parent.fullName}.${descriptor.name}',
@@ -80,9 +80,10 @@
             _nestedFieldTag);
 
   @override
-  String get package => parent.package;
+  String get package => parent!.package;
+
   @override
-  FileGenerator get fileGen => parent.fileGen;
+  FileGenerator? get fileGen => parent!.fileGen;
 
   /// Make this enum available as a field type.
   void register(GenerationContext ctx) {
@@ -93,7 +94,7 @@
   /// [usage] represents the .pb.dart file where the expression will be used.
   String getJsonConstant(FileGenerator usage) {
     var name = '$classname\$json';
-    if (usage.protoFileUri == fileGen.protoFileUri) {
+    if (usage.protoFileUri == fileGen!.protoFileUri) {
       return name;
     }
     return '$fileImportPrefix.$name';
@@ -106,13 +107,15 @@
         'class $classname extends $protobufImportPrefix.ProtobufEnum {',
         '}\n', [
       NamedLocation(
-          name: classname, fieldPathSegment: fieldPath, start: 'class '.length)
+          name: classname!,
+          fieldPathSegment: fieldPath!,
+          start: 'class '.length)
     ], () {
       // -----------------------------------------------------------------
       // Define enum types.
       for (var i = 0; i < _canonicalValues.length; i++) {
         var val = _canonicalValues[i];
-        final name = dartNames[val.name];
+        final name = dartNames[val.name]!;
         final conditionalValName = configurationDependent(
             'protobuf.omit_enum_names', quoted(val.name));
         out.printlnAnnotated(
@@ -121,7 +124,7 @@
             [
               NamedLocation(
                   name: name,
-                  fieldPathSegment: List.from(fieldPath)
+                  fieldPathSegment: List.from(fieldPath!)
                     ..addAll([_enumValueTag, _originalCanonicalIndices[i]]),
                   start: 'static const $classname '.length)
             ]);
@@ -130,14 +133,14 @@
         out.println();
         for (var i = 0; i < _aliases.length; i++) {
           var alias = _aliases[i];
-          final name = dartNames[alias.value.name];
+          final name = dartNames[alias.value.name]!;
           out.printlnAnnotated(
               'static const $classname $name ='
               ' ${dartNames[alias.canonicalValue.name]};',
               [
                 NamedLocation(
                     name: name,
-                    fieldPathSegment: List.from(fieldPath)
+                    fieldPathSegment: List.from(fieldPath!)
                       ..addAll([_enumValueTag, _originalAliasIndices[i]]),
                     start: 'static const $classname '.length)
               ]);
@@ -169,11 +172,11 @@
 
   /// Writes a Dart constant containing the JSON for the EnumProtoDescriptor.
   void generateConstants(IndentingWriter out) {
-    var name = getJsonConstant(fileGen);
+    var name = getJsonConstant(fileGen!);
     var json = _descriptor.writeToJsonMap();
 
     out.println('@$coreImportPrefix.Deprecated'
-        '(\'Use ${toplevelParent.binaryDescriptorName} instead\')');
+        '(\'Use ${toplevelParent!.binaryDescriptorName} instead\')');
     out.print('const $name = ');
     writeJsonConst(out, json);
     out.println(';');
diff --git a/protoc_plugin/lib/src/extension_generator.dart b/protoc_plugin/lib/src/extension_generator.dart
index 05e9455..295100f 100644
--- a/protoc_plugin/lib/src/extension_generator.dart
+++ b/protoc_plugin/lib/src/extension_generator.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 part of '../protoc.dart';
 
 class ExtensionGenerator {
@@ -11,15 +9,15 @@
   final ProtobufContainer _parent;
 
   // populated by resolve()
-  ProtobufField _field;
+  late ProtobufField _field;
+  bool _resolved = false;
   final String _extensionName;
   String _extendedFullName = '';
-  List<int> _fieldPath;
   final List<int> _fieldPathSegment;
 
   /// See [[ProtobufContainer]
-  List<int> get fieldPath =>
-      _fieldPath ??= List.from(_parent.fieldPath)..addAll(_fieldPathSegment);
+  late final List<int> fieldPath = List.from(_parent.fieldPath!)
+    ..addAll(_fieldPathSegment);
 
   ExtensionGenerator._(this._descriptor, this._parent, Set<String> usedNames,
       int repeatedFieldIndex, int fieldIdTag)
@@ -40,6 +38,7 @@
 
   void resolve(GenerationContext ctx) {
     _field = ProtobufField.extension(_descriptor, _parent, ctx);
+    _resolved = true;
 
     var extendedType = ctx.getFieldType(_descriptor.extendee);
     // TODO(skybrian) When would this be null?
@@ -51,16 +50,16 @@
   String get package => _parent.package;
 
   /// The generator of the .pb.dart file where this extension will be defined.
-  FileGenerator get fileGen => _parent.fileGen;
+  FileGenerator? get fileGen => _parent.fileGen;
 
   String get name {
-    if (_field == null) throw StateError('resolve not called');
+    if (!_resolved) throw StateError('resolve not called');
     var name = _extensionName;
     return _parent is MessageGenerator ? '${_parent.classname}.$name' : name;
   }
 
   bool get needsFixnumImport {
-    if (_field == null) throw StateError('resolve not called');
+    if (!_resolved) throw StateError('resolve not called');
     return _field.needsFixnumImport;
   }
 
@@ -70,16 +69,16 @@
   /// add its generator.
   void addImportsTo(
       Set<FileGenerator> imports, Set<FileGenerator> enumImports) {
-    if (_field == null) throw StateError('resolve not called');
+    if (!_resolved) throw StateError('resolve not called');
     var typeGen = _field.baseType.generator;
     if (typeGen != null) {
       // The type of this extension is defined in a different file,
       // so we need to import it.
       if (typeGen is EnumGenerator) {
         // Enums are always in a different file.
-        enumImports.add(typeGen.fileGen);
+        enumImports.add(typeGen.fileGen!);
       } else if (typeGen.fileGen != fileGen) {
-        imports.add(typeGen.fileGen);
+        imports.add(typeGen.fileGen!);
       }
     }
   }
@@ -87,18 +86,18 @@
   /// For each .pb.dart file that the generated code needs to import,
   /// add its generator.
   void addConstantImportsTo(Set<FileGenerator> imports) {
-    if (_field == null) throw StateError('resolve not called');
+    if (!_resolved) throw StateError('resolve not called');
     // No dependencies - nothing to do.
   }
 
   void generate(IndentingWriter out) {
-    if (_field == null) throw StateError('resolve not called');
+    if (!_resolved) throw StateError('resolve not called');
 
     var name = _extensionName;
     final conditionalName = configurationDependent(
         'protobuf.omit_field_names', quoted(_extensionName));
     var type = _field.baseType;
-    var dartType = type.getDartType(fileGen);
+    var dartType = type.getDartType(fileGen!);
     final conditionalExtendedName = configurationDependent(
         'protobuf.omit_message_names', quoted(_extendedFullName));
 
@@ -109,7 +108,7 @@
     positionals.add('${_field.number}');
     positionals.add(_field.typeConstant);
 
-    var named = <String, String>{};
+    var named = <String, String?>{};
     named['protoName'] = _field.quotedProtoName;
     if (_field.isRepeated) {
       invocation = '$protobufImportPrefix.Extension<$dartType>.repeated';
@@ -123,16 +122,15 @@
       }
     } else {
       invocation = '$protobufImportPrefix.Extension<$dartType>';
-      named['defaultOrMaker'] = _field.generateDefaultFunction(fileGen);
+      named['defaultOrMaker'] = _field.generateDefaultFunction(fileGen!);
       if (type.isMessage || type.isGroup) {
         named['subBuilder'] = '$dartType.create';
       } else if (type.isEnum) {
-        var dartEnum = type.getDartType(fileGen);
+        var dartEnum = type.getDartType(fileGen!);
         named['valueOf'] = '$dartEnum.valueOf';
         named['enumValues'] = '$dartEnum.values';
       }
     }
-    assert(invocation != null);
     var fieldDefinition = 'static final ';
     out.printAnnotated(
         '$fieldDefinition$name = '
diff --git a/protoc_plugin/lib/src/file_generator.dart b/protoc_plugin/lib/src/file_generator.dart
index bada58e..ebe141e 100644
--- a/protoc_plugin/lib/src/file_generator.dart
+++ b/protoc_plugin/lib/src/file_generator.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 part of '../protoc.dart';
 
 final _dartIdentifier = RegExp(r'^\w+$');
@@ -91,16 +89,16 @@
           throw mixinError('Cycle in parent chain: $cycle');
         }
         parentChain.add(parentName);
-        currentMixin = dartMixins[parentName];
+        currentMixin = dartMixins[parentName]!;
       }
     }
 
     // Turn DartMixins into PbMixins.
     final pbMixins = <String, PbMixin>{};
-    PbMixin resolveMixin(String name) {
+    PbMixin? resolveMixin(String name) {
       if (pbMixins.containsKey(name)) return pbMixins[name];
       if (dartMixins.containsKey(name)) {
-        var dartMixin = dartMixins[name];
+        var dartMixin = dartMixins[name]!;
         var pbMixin = PbMixin(dartMixin.name,
             importFrom: dartMixin.importFrom,
             parent: resolveMixin(dartMixin.parent));
@@ -154,7 +152,7 @@
 
     var declaredMixins = _getDeclaredMixins(descriptor);
     var defaultMixinName =
-        descriptor.options?.getExtension(Dart_options.defaultMixin) as String ??
+        descriptor.options.getExtension(Dart_options.defaultMixin) as String? ??
             '';
     var defaultMixin =
         declaredMixins[defaultMixinName] ?? findMixin(defaultMixinName);
@@ -206,14 +204,19 @@
 
   @override
   String get package => descriptor.package;
+
   @override
   String get classname => '';
+
   @override
   String get fullName => descriptor.package;
+
   @override
   FileGenerator get fileGen => this;
+
   @override
-  ProtobufContainer get parent => null;
+  ProtobufContainer? get parent => null;
+
   @override
   List<int> get fieldPath => [];
 
diff --git a/protoc_plugin/lib/src/grpc_generator.dart b/protoc_plugin/lib/src/grpc_generator.dart
index 73fe67e..dd936aa 100644
--- a/protoc_plugin/lib/src/grpc_generator.dart
+++ b/protoc_plugin/lib/src/grpc_generator.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 part of '../protoc.dart';
 
 class GrpcServiceGenerator {
@@ -24,13 +22,13 @@
   final _undefinedDeps = <String, String>{};
 
   /// Fully-qualified gRPC service name.
-  String _fullServiceName;
+  late final String _fullServiceName;
 
   /// Dart class name for client stub.
-  String _clientClassname;
+  late final String _clientClassname;
 
   /// Dart class name for server stub.
-  String _serviceClassname;
+  late final String _serviceClassname;
 
   /// List of gRPC methods.
   final _methods = <_GrpcMethod>[];
@@ -39,7 +37,7 @@
     final name = _descriptor.name;
     final package = fileGen.package;
 
-    if (package != null && package.isNotEmpty) {
+    if (package.isNotEmpty) {
       _fullServiceName = '$package.$name';
     } else {
       _fullServiceName = name;
@@ -69,7 +67,7 @@
   void _addDependency(GenerationContext ctx, String fqname, String location) {
     if (_deps.containsKey(fqname)) return; // Already added.
 
-    final mg = ctx.getFieldType(fqname) as MessageGenerator;
+    final mg = ctx.getFieldType(fqname) as MessageGenerator?;
     if (mg == null) {
       _undefinedDeps[fqname] = location;
       return;
diff --git a/protoc_plugin/lib/src/linker.dart b/protoc_plugin/lib/src/linker.dart
index 740e719..ef99f9f 100644
--- a/protoc_plugin/lib/src/linker.dart
+++ b/protoc_plugin/lib/src/linker.dart
@@ -2,14 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import '../protoc.dart' show FileGenerator;
 import 'code_generator.dart';
 import 'options.dart';
 
 /// Resolves all cross-references in a set of proto files.
-void link(GenerationOptions options, Iterable<FileGenerator> files) {
+void link(GenerationOptions? options, Iterable<FileGenerator> files) {
   var ctx = GenerationContext(options);
 
   // Register the targets of cross-references.
@@ -41,7 +39,7 @@
 }
 
 class GenerationContext {
-  final GenerationOptions options;
+  final GenerationOptions? options;
 
   /// The files available for import.
   final Map<String, FileGenerator> _files = <String, FileGenerator>{};
@@ -67,9 +65,9 @@
 
   /// Returns info about a .pb.dart being imported,
   /// based on the filename given to us by protoc.
-  FileGenerator getImportedProtoFile(String name) => _files[name];
+  FileGenerator? getImportedProtoFile(String name) => _files[name];
 
   /// Returns info about the type of a message, group, or enum field,
   /// based on the fully qualified name given to us by protoc.
-  ProtobufContainer getFieldType(String name) => _typeRegistry[name];
+  ProtobufContainer? getFieldType(String name) => _typeRegistry[name];
 }
diff --git a/protoc_plugin/lib/src/message_generator.dart b/protoc_plugin/lib/src/message_generator.dart
index 92c3beb..9b8c560 100644
--- a/protoc_plugin/lib/src/message_generator.dart
+++ b/protoc_plugin/lib/src/message_generator.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 part of '../protoc.dart';
 
 /// Generates the Dart enum corresponding to a oneof declaration.
@@ -15,7 +13,7 @@
       IndentingWriter out, String classname, List<ProtobufField> fields) {
     out.addBlock('enum $classname {', '}\n', () {
       for (var field in fields) {
-        final name = oneofEnumMemberName(field.memberNames.fieldName);
+        final name = oneofEnumMemberName(field.memberNames!.fieldName);
         out.println('$name, ');
       }
       out.println('notSet');
@@ -51,10 +49,11 @@
   String get messageName =>
       fullName.substring(package.isEmpty ? 0 : package.length + 1);
 
-  PbMixin mixin;
+  PbMixin? mixin;
 
   @override
-  final ProtobufContainer parent;
+  final ProtobufContainer? parent;
+
   final DescriptorProto _descriptor;
   final List<EnumGenerator> _enumGenerators = <EnumGenerator>[];
   final List<MessageGenerator> _messageGenerators = <MessageGenerator>[];
@@ -64,18 +63,18 @@
   /// by the index in the containing types's oneof_decl list.
   /// Only contains the 'real' oneofs.
   final List<List<ProtobufField>> _oneofFields;
-  List<OneofNames> _oneofNames;
+  late List<OneofNames> _oneofNames;
 
-  List<int> _fieldPath;
   final List<int> _fieldPathSegment;
 
   /// See [[ProtobufContainer]
   @override
-  List<int> get fieldPath =>
-      _fieldPath ??= List.from(parent.fieldPath)..addAll(_fieldPathSegment);
+  late final List<int> fieldPath = List.from(parent!.fieldPath!)
+    ..addAll(_fieldPathSegment);
 
   // populated by resolve()
-  List<ProtobufField> _fieldList;
+  late List<ProtobufField> _fieldList;
+  bool _resolved = false;
 
   Set<String> _usedTopLevelNames;
 
@@ -83,7 +82,7 @@
       DescriptorProto descriptor,
       this.parent,
       Map<String, PbMixin> declaredMixins,
-      PbMixin defaultMixin,
+      PbMixin? defaultMixin,
       this._usedTopLevelNames,
       int repeatedFieldIndex,
       int fieldIdTag)
@@ -92,7 +91,7 @@
         classname = messageOrEnumClassName(descriptor.name, _usedTopLevelNames,
             parent: parent?.classname ?? ''),
         assert(parent != null),
-        fullName = parent.fullName == ''
+        fullName = parent!.fullName == ''
             ? descriptor.name
             : '${parent.fullName}.${descriptor.name}',
         _oneofFields =
@@ -127,7 +126,7 @@
       DescriptorProto descriptor,
       ProtobufContainer parent,
       Map<String, PbMixin> declaredMixins,
-      PbMixin defaultMixin,
+      PbMixin? defaultMixin,
       Set<String> usedNames,
       int repeatedFieldIndex)
       : this._(descriptor, parent, declaredMixins, defaultMixin, usedNames,
@@ -137,22 +136,22 @@
       DescriptorProto descriptor,
       ProtobufContainer parent,
       Map<String, PbMixin> declaredMixins,
-      PbMixin defaultMixin,
+      PbMixin? defaultMixin,
       Set<String> usedNames,
       int repeatedFieldIndex)
       : this._(descriptor, parent, declaredMixins, defaultMixin, usedNames,
             repeatedFieldIndex, _nestedMessageTag);
 
   @override
-  String get package => parent.package;
+  String get package => parent!.package;
 
   /// The generator of the .pb.dart file that will declare this type.
   @override
-  FileGenerator get fileGen => parent.fileGen;
+  FileGenerator get fileGen => parent!.fileGen!;
 
   /// Throws an exception if [resolve] hasn't been called yet.
   void checkResolved() {
-    if (_fieldList == null) {
+    if (!_resolved) {
       throw StateError('message not resolved: $fullName');
     }
   }
@@ -170,7 +169,7 @@
   /// Adds all mixins used in this message and any submessages.
   void addMixinsTo(Set<PbMixin> output) {
     if (mixin != null) {
-      output.addAll(mixin.findMixinsToApply());
+      output.addAll(mixin!.findMixinsToApply());
     }
     for (var m in _messageGenerators) {
       m.addMixinsTo(output);
@@ -190,7 +189,8 @@
 
   // Creates fields and resolves extension targets.
   void resolve(GenerationContext ctx) {
-    if (_fieldList != null) throw StateError('message already resolved');
+    if (_resolved) throw StateError('message already resolved');
+    _resolved = true;
 
     var reserved = mixin?.findReservedNames() ?? const <String>[];
     var members = messageMemberNames(_descriptor, classname, _usedTopLevelNames,
@@ -216,7 +216,7 @@
   }
 
   bool get needsFixnumImport {
-    if (_fieldList == null) throw StateError('message not resolved');
+    checkResolved();
     for (var field in _fieldList) {
       if (field.needsFixnumImport) return true;
     }
@@ -235,13 +235,13 @@
   /// add its generator.
   void addImportsTo(
       Set<FileGenerator> imports, Set<FileGenerator> enumImports) {
-    if (_fieldList == null) throw StateError('message not resolved');
+    checkResolved();
     for (var field in _fieldList) {
       var typeGen = field.baseType.generator;
       if (typeGen is EnumGenerator) {
-        enumImports.add(typeGen.fileGen);
+        enumImports.add(typeGen.fileGen!);
       } else if (typeGen != null) {
-        imports.add(typeGen.fileGen);
+        imports.add(typeGen.fileGen!);
       }
     }
     for (var m in _messageGenerators) {
@@ -266,7 +266,7 @@
   /// For each .pbjson.dart file that the generated code needs to import,
   /// add its generator.
   void addConstantImportsTo(Set<FileGenerator> imports) {
-    if (_fieldList == null) throw StateError('message not resolved');
+    checkResolved();
     for (var m in _messageGenerators) {
       m.addConstantImportsTo(imports);
     }
@@ -293,7 +293,7 @@
     var mixinClause = '';
     if (mixin != null) {
       var mixinNames =
-          mixin.findMixinsToApply().map((m) => '$mixinImportPrefix.${m.name}');
+          mixin!.findMixinsToApply().map((m) => '$mixinImportPrefix.${m.name}');
       mixinClause = ' with ${mixinNames.join(", ")}';
     }
 
@@ -304,8 +304,8 @@
     var packageClause =
         package == '' ? '' : ', package: $conditionalPackageName';
     var proto3JsonClause = (mixin?.hasProto3JsonHelpers ?? false)
-        ? ', toProto3Json: $mixinImportPrefix.${mixin.name}.toProto3JsonHelper, '
-            'fromProto3Json: $mixinImportPrefix.${mixin.name}.fromProto3JsonHelper'
+        ? ', toProto3Json: $mixinImportPrefix.${mixin!.name}.toProto3JsonHelper, '
+            'fromProto3Json: $mixinImportPrefix.${mixin!.name}.fromProto3JsonHelper'
         : '';
     out.addAnnotatedBlock(
         'class $classname extends $protobufImportPrefix.GeneratedMessage$mixinClause {',
@@ -319,7 +319,7 @@
             '};', () {
           for (var field in _oneofFields[oneof.index]) {
             final oneofMemberName =
-                oneofEnumMemberName(field.memberNames.fieldName);
+                oneofEnumMemberName(field.memberNames!.fieldName);
             out.println(
                 '${field.number} : ${oneof.oneofEnumName}.$oneofMemberName,');
           }
@@ -369,10 +369,10 @@
           _emitDeprecatedIf(field.isDeprecated, out);
           if (field.isRepeated && !field.isMapField) {
             out.println(
-                '  ${field.baseType.getRepeatedDartTypeIterable(fileGen)}? ${field.memberNames.fieldName},');
+                '  ${field.baseType.getRepeatedDartTypeIterable(fileGen)}? ${field.memberNames!.fieldName},');
           } else {
             out.println(
-                '  ${field.getDartType(fileGen)}? ${field.memberNames.fieldName},');
+                '  ${field.getDartType(fileGen)}? ${field.memberNames!.fieldName},');
           }
         }
         out.print('}');
@@ -381,17 +381,17 @@
         out.println(') {');
         out.println('  final _result = create();');
         for (final field in _fieldList) {
-          out.println('  if (${field.memberNames.fieldName} != null) {');
+          out.println('  if (${field.memberNames!.fieldName} != null) {');
           if (field.isDeprecated) {
             out.println(
                 '    // ignore: deprecated_member_use_from_same_package');
           }
           if (field.isRepeated || field.isMapField) {
             out.println(
-                '    _result.${field.memberNames.fieldName}.addAll(${field.memberNames.fieldName});');
+                '    _result.${field.memberNames!.fieldName}.addAll(${field.memberNames!.fieldName});');
           } else {
             out.println(
-                '    _result.${field.memberNames.fieldName} = ${field.memberNames.fieldName};');
+                '    _result.${field.memberNames!.fieldName} = ${field.memberNames!.fieldName};');
           }
           out.println('  }');
         }
@@ -452,7 +452,7 @@
   // already_seen is used to avoid checking the same type multiple times
   // (and also to protect against unbounded recursion).
   bool _hasRequiredFields(MessageGenerator type, Set alreadySeen) {
-    if (type._fieldList == null) throw StateError('message not resolved');
+    checkResolved();
 
     if (alreadySeen.contains(type.fullName)) {
       // The type is already in cache.  This means that either:
@@ -495,7 +495,7 @@
     for (var field in _fieldList) {
       out.println();
       var memberFieldPath = List<int>.from(fieldPath)
-        ..addAll([_messageFieldTag, field.sourcePosition]);
+        ..addAll([_messageFieldTag, field.sourcePosition!]);
       generateFieldAccessorsMutators(field, out, memberFieldPath);
     }
   }
@@ -517,10 +517,10 @@
     _emitDeprecatedIf(field.isDeprecated, out);
     _emitOverrideIf(field.overridesGetter, out);
     _emitIndexAnnotation(field.number, out);
-    final getterExpr = _getterExpression(fieldTypeString, field.index,
+    final getterExpr = _getterExpression(fieldTypeString, field.index!,
         defaultExpr, field.isRepeated, field.isMapField);
     out.printlnAnnotated(
-        '$fieldTypeString get ${names.fieldName} => $getterExpr;', [
+        '$fieldTypeString get ${names!.fieldName} => $getterExpr;', [
       NamedLocation(
           name: names.fieldName,
           fieldPathSegment: memberFieldPath,
@@ -579,7 +579,7 @@
             ' \$_has(${field.index});',
             [
               NamedLocation(
-                  name: names.hasMethodName,
+                  name: names.hasMethodName!,
                   fieldPathSegment: memberFieldPath,
                   start: '$coreImportPrefix.bool '.length)
             ]);
@@ -592,7 +592,7 @@
           ' clearField(${field.number});',
           [
             NamedLocation(
-                name: names.clearMethodName,
+                name: names.clearMethodName!,
                 fieldPathSegment: memberFieldPath,
                 start: 'void '.length)
           ]);
@@ -604,7 +604,7 @@
             '\$_ensure(${field.index});',
             <NamedLocation>[
               NamedLocation(
-                  name: names.ensureMethodName,
+                  name: names.ensureMethodName!,
                   fieldPathSegment: memberFieldPath,
                   start: '$fieldTypeString '.length)
             ]);
@@ -677,8 +677,8 @@
   void generateConstants(IndentingWriter out) {
     const nestedTypeTag = 3;
     const enumTypeTag = 4;
-    assert(_descriptor.info_.fieldInfo[nestedTypeTag].name == 'nestedType');
-    assert(_descriptor.info_.fieldInfo[enumTypeTag].name == 'enumType');
+    assert(_descriptor.info_.fieldInfo[nestedTypeTag]!.name == 'nestedType');
+    assert(_descriptor.info_.fieldInfo[enumTypeTag]!.name == 'enumType');
 
     var name = getJsonConstant(fileGen);
     var json = _descriptor.writeToJsonMap();
@@ -688,7 +688,7 @@
         _enumGenerators.map((e) => e.getJsonConstant(fileGen)).toList();
 
     out.println('@$coreImportPrefix.Deprecated'
-        '(\'Use ${toplevelParent.binaryDescriptorName} instead\')');
+        '(\'Use ${toplevelParent!.binaryDescriptorName} instead\')');
     out.addBlock('const $name = const {', '};', () {
       for (var key in json.keys) {
         out.print("'$key': ");
@@ -720,7 +720,8 @@
   ///
   /// First searches [_wellKnownMixins], then [declaredMixins],
   /// then internal mixins declared by [findMixin].
-  PbMixin _getMixin(Map<String, PbMixin> declaredMixins, PbMixin defaultMixin) {
+  PbMixin? _getMixin(
+      Map<String, PbMixin> declaredMixins, PbMixin? defaultMixin) {
     var wellKnownMixin = wellKnownMixinForFullName(fullName);
     if (wellKnownMixin != null) return wellKnownMixin;
     if (!_descriptor.hasOptions() ||
@@ -732,7 +733,7 @@
     if (name.isEmpty) return null; // don't use any mixins (override default)
     var mixin = declaredMixins[name] ?? findMixin(name);
     if (mixin == null) {
-      throw '${_descriptor.name} in ${parent.fileGen.descriptor.name}: mixin "$name" not found';
+      throw '${_descriptor.name} in ${parent!.fileGen!.descriptor.name}: mixin "$name" not found';
     }
     return mixin;
   }
diff --git a/protoc_plugin/lib/src/protobuf_field.dart b/protoc_plugin/lib/src/protobuf_field.dart
index 7f8dad6..5fa3b1c 100644
--- a/protoc_plugin/lib/src/protobuf_field.dart
+++ b/protoc_plugin/lib/src/protobuf_field.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 part of '../protoc.dart';
 
 class ProtobufField {
@@ -22,7 +20,7 @@
   final FieldDescriptorProto descriptor;
 
   /// Dart names within a GeneratedMessage or `null` for an extension.
-  final FieldNames memberNames;
+  final FieldNames? memberNames;
 
   final String fullName;
   final BaseType baseType;
@@ -35,7 +33,7 @@
       ProtobufContainer parent, GenerationContext ctx)
       : this._(descriptor, null, parent, ctx);
 
-  ProtobufField._(this.descriptor, FieldNames dartNames,
+  ProtobufField._(this.descriptor, FieldNames? dartNames,
       ProtobufContainer parent, GenerationContext ctx)
       : memberNames = dartNames,
         fullName = '${parent.fullName}.${descriptor.name}',
@@ -44,18 +42,18 @@
   /// The index of this field in MessageGenerator.fieldList.
   ///
   /// `null` for an extension.
-  int get index => memberNames?.index;
+  int? get index => memberNames?.index;
 
-  String get quotedProtoName =>
+  String? get quotedProtoName =>
       (_unCamelCase(descriptor.jsonName) == descriptor.name)
           ? null
           : "'${descriptor.name}'";
 
   /// The position of this field as it appeared in the original DescriptorProto.
-  int get sourcePosition => memberNames.sourcePosition;
+  int? get sourcePosition => memberNames?.sourcePosition;
 
   /// True if the field is to be encoded with [deprecated = true] encoding.
-  bool get isDeprecated => descriptor.options?.deprecated;
+  bool get isDeprecated => descriptor.options.deprecated;
 
   bool get isRequired =>
       descriptor.label == FieldDescriptorProto_Label.LABEL_REQUIRED;
@@ -64,8 +62,7 @@
       descriptor.label == FieldDescriptorProto_Label.LABEL_REPEATED;
 
   /// True if the field is to be encoded with [packed=true] encoding.
-  bool get isPacked =>
-      isRepeated && descriptor.options != null && descriptor.options.packed;
+  bool get isPacked => isRepeated && descriptor.options.packed;
 
   /// Whether the field has the `overrideGetter` annotation set to true.
   bool get overridesGetter => _hasBooleanOption(Dart_options.overrideGetter);
@@ -145,7 +142,7 @@
   }
 
   static String _formatArguments(
-      List<String> positionals, Map<String, String> named) {
+      List<String?> positionals, Map<String, String?> named) {
     final args = positionals.toList();
     while (args.last == null) {
       args.removeLast();
@@ -178,7 +175,7 @@
     String invocation;
 
     var args = <String>[];
-    var named = <String, String>{'protoName': quotedProtoName};
+    var named = <String, String?>{'protoName': quotedProtoName};
     args.add('$number');
     args.add(quotedName);
 
@@ -279,7 +276,6 @@
         }
       }
     }
-    assert(invocation != null);
     return '..$invocation(${_formatArguments(args, named)})';
   }
 
@@ -291,15 +287,15 @@
     if (isRepeated) return 'null';
     switch (descriptor.type) {
       case FieldDescriptorProto_Type.TYPE_BOOL:
-        return _getDefaultAsBoolExpr('false');
+        return _getDefaultAsBoolExpr('false')!;
       case FieldDescriptorProto_Type.TYPE_INT32:
       case FieldDescriptorProto_Type.TYPE_UINT32:
       case FieldDescriptorProto_Type.TYPE_SINT32:
       case FieldDescriptorProto_Type.TYPE_FIXED32:
       case FieldDescriptorProto_Type.TYPE_SFIXED32:
-        return _getDefaultAsInt32Expr('0');
+        return _getDefaultAsInt32Expr('0')!;
       case FieldDescriptorProto_Type.TYPE_STRING:
-        return _getDefaultAsStringExpr("''");
+        return _getDefaultAsStringExpr("''")!;
       default:
         return 'null';
     }
@@ -309,7 +305,7 @@
   ///
   /// [fileGen] represents the .proto file where the expression will be
   /// evaluated.
-  String generateDefaultFunction(FileGenerator fileGen) {
+  String? generateDefaultFunction(FileGenerator? fileGen) {
     assert(!isRepeated);
     switch (descriptor.type) {
       case FieldDescriptorProto_Type.TYPE_BOOL:
@@ -363,9 +359,9 @@
         return '() => <$coreImportPrefix.int>[$byteList]';
       case FieldDescriptorProto_Type.TYPE_GROUP:
       case FieldDescriptorProto_Type.TYPE_MESSAGE:
-        return '${baseType.getDartType(fileGen)}.getDefault';
+        return '${baseType.getDartType(fileGen!)}.getDefault';
       case FieldDescriptorProto_Type.TYPE_ENUM:
-        var className = baseType.getDartType(fileGen);
+        var className = baseType.getDartType(fileGen!);
         final gen = baseType.generator as EnumGenerator;
         if (descriptor.hasDefaultValue() &&
             descriptor.defaultValue.isNotEmpty) {
@@ -379,14 +375,14 @@
     }
   }
 
-  String _getDefaultAsBoolExpr(String noDefault) {
+  String? _getDefaultAsBoolExpr(String? noDefault) {
     if (descriptor.hasDefaultValue() && 'false' != descriptor.defaultValue) {
       return descriptor.defaultValue;
     }
     return noDefault;
   }
 
-  String _getDefaultAsStringExpr(String noDefault) {
+  String? _getDefaultAsStringExpr(String? noDefault) {
     if (!descriptor.hasDefaultValue() || descriptor.defaultValue.isEmpty) {
       return noDefault;
     }
@@ -394,7 +390,7 @@
     return quoted(descriptor.defaultValue);
   }
 
-  String _getDefaultAsInt32Expr(String noDefault) {
+  String? _getDefaultAsInt32Expr(String? noDefault) {
     if (descriptor.hasDefaultValue() && '0' != descriptor.defaultValue) {
       return descriptor.defaultValue;
     }
@@ -402,7 +398,7 @@
   }
 
   bool _hasBooleanOption(Extension extension) =>
-      descriptor?.options?.getExtension(extension) as bool ?? false;
+      descriptor.options.getExtension(extension) as bool? ?? false;
 
   String get _invalidDefaultValue => 'dart-protoc-plugin:'
       ' invalid default value (${descriptor.defaultValue})'
@@ -416,6 +412,6 @@
 
   static String _unCamelCase(String name) {
     return name.replaceAllMapped(
-        _upperCase, (match) => '_${match.group(0).toLowerCase()}');
+        _upperCase, (match) => '_${match.group(0)!.toLowerCase()}');
   }
 }
diff --git a/protoc_plugin/lib/src/service_generator.dart b/protoc_plugin/lib/src/service_generator.dart
index 3fcd1a9..53ef39c 100644
--- a/protoc_plugin/lib/src/service_generator.dart
+++ b/protoc_plugin/lib/src/service_generator.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 part of '../protoc.dart';
 
 class ServiceGenerator {
@@ -68,7 +66,7 @@
   void _addDependency(GenerationContext ctx, String fqname, String location) {
     if (_deps.containsKey(fqname)) return; // Already added.
 
-    final mg = ctx.getFieldType(fqname) as MessageGenerator;
+    final mg = ctx.getFieldType(fqname) as MessageGenerator?;
     if (mg == null) {
       _undefinedDeps[fqname] = location;
       return;
@@ -226,7 +224,7 @@
 
     var typeConstants = <String, String>{};
     for (var key in _transitiveDeps.keys) {
-      typeConstants[key] = _transitiveDeps[key].getJsonConstant(fileGen);
+      typeConstants[key] = _transitiveDeps[key]!.getJsonConstant(fileGen);
     }
 
     out.println('@$coreImportPrefix.Deprecated'
diff --git a/protoc_plugin/lib/src/well_known_types.dart b/protoc_plugin/lib/src/well_known_types.dart
index 7fabd87..24e360b 100644
--- a/protoc_plugin/lib/src/well_known_types.dart
+++ b/protoc_plugin/lib/src/well_known_types.dart
@@ -2,11 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 part of '../protoc.dart';
 
-PbMixin wellKnownMixinForFullName(String qualifiedName) =>
+PbMixin? wellKnownMixinForFullName(String qualifiedName) =>
     _wellKnownMixins[qualifiedName];
 
 const _wellKnownImportPath =
diff --git a/protoc_plugin/test/any_test.dart b/protoc_plugin/test/any_test.dart
index a29d6d1..df1cb12 100644
--- a/protoc_plugin/test/any_test.dart
+++ b/protoc_plugin/test/any_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'package:protobuf/protobuf.dart';
 import 'package:test/test.dart';
 
diff --git a/protoc_plugin/test/bazel_test.dart b/protoc_plugin/test/bazel_test.dart
index e1ef89c..0cca05b 100644
--- a/protoc_plugin/test/bazel_test.dart
+++ b/protoc_plugin/test/bazel_test.dart
@@ -2,17 +2,15 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'package:protoc_plugin/bazel.dart';
 import 'package:test/test.dart';
 
 void main() {
   group('BazelOptionParser', () {
-    BazelOptionParser optionParser;
-    Map<String, BazelPackage> packages;
-    List<String> errors;
-
+    late BazelOptionParser optionParser;
+    late Map<String, BazelPackage> packages;
+    late List<String> errors;
+    final optionName = 'name';
     setUp(() {
       packages = {};
       optionParser = BazelOptionParser(packages);
@@ -24,95 +22,95 @@
     }
 
     test('should call onError for null values', () {
-      optionParser.parse(null, null, _onError);
+      optionParser.parse(optionName, null, _onError);
       expect(errors, isNotEmpty);
     });
 
     test('should call onError for empty values', () {
-      optionParser.parse(null, '', _onError);
+      optionParser.parse(optionName, '', _onError);
       expect(errors, isNotEmpty);
     });
 
     test('should call onError for malformed entries', () {
-      optionParser.parse(null, 'foo', _onError);
-      optionParser.parse(null, 'foo|bar', _onError);
-      optionParser.parse(null, 'foo|bar|baz|quux', _onError);
+      optionParser.parse(optionName, 'foo', _onError);
+      optionParser.parse(optionName, 'foo|bar', _onError);
+      optionParser.parse(optionName, 'foo|bar|baz|quux', _onError);
       expect(errors.length, 3);
       expect(packages, isEmpty);
     });
 
     test('should handle a single package|path entry', () {
-      optionParser.parse(null, 'foo|bar/baz|wibble/wobble', _onError);
+      optionParser.parse(optionName, 'foo|bar/baz|wibble/wobble', _onError);
       expect(errors, isEmpty);
       expect(packages.length, 1);
-      expect(packages['bar/baz'].name, 'foo');
-      expect(packages['bar/baz'].inputRoot, 'bar/baz');
-      expect(packages['bar/baz'].outputRoot, 'wibble/wobble');
+      expect(packages['bar/baz']!.name, 'foo');
+      expect(packages['bar/baz']!.inputRoot, 'bar/baz');
+      expect(packages['bar/baz']!.outputRoot, 'wibble/wobble');
     });
 
     test('should handle multiple package|path entries', () {
       optionParser.parse(
-          null,
+          optionName,
           'foo|bar/baz|wibble/wobble;a|b/c/d|e/f;one.two|three|four/five',
           _onError);
       expect(errors, isEmpty);
       expect(packages.length, 3);
-      expect(packages['bar/baz'].name, 'foo');
-      expect(packages['bar/baz'].inputRoot, 'bar/baz');
-      expect(packages['bar/baz'].outputRoot, 'wibble/wobble');
-      expect(packages['b/c/d'].name, 'a');
-      expect(packages['b/c/d'].inputRoot, 'b/c/d');
-      expect(packages['b/c/d'].outputRoot, 'e/f');
-      expect(packages['three'].name, 'one.two');
-      expect(packages['three'].inputRoot, 'three');
-      expect(packages['three'].outputRoot, 'four/five');
+      expect(packages['bar/baz']!.name, 'foo');
+      expect(packages['bar/baz']!.inputRoot, 'bar/baz');
+      expect(packages['bar/baz']!.outputRoot, 'wibble/wobble');
+      expect(packages['b/c/d']!.name, 'a');
+      expect(packages['b/c/d']!.inputRoot, 'b/c/d');
+      expect(packages['b/c/d']!.outputRoot, 'e/f');
+      expect(packages['three']!.name, 'one.two');
+      expect(packages['three']!.inputRoot, 'three');
+      expect(packages['three']!.outputRoot, 'four/five');
     });
 
     test('should skip and continue past malformed entries', () {
-      optionParser.parse(null,
+      optionParser.parse(optionName,
           'foo|bar/baz|wibble/wobble;fizz;a.b|c/d|e/f;x|y|zz|y', _onError);
       expect(errors.length, 2);
       expect(packages.length, 2);
-      expect(packages['bar/baz'].name, 'foo');
-      expect(packages['c/d'].name, 'a.b');
+      expect(packages['bar/baz']!.name, 'foo');
+      expect(packages['c/d']!.name, 'a.b');
     });
 
     test('should emit error for conflicting package names', () {
-      optionParser.parse(null,
+      optionParser.parse(optionName,
           'foo|bar/baz|wibble/wobble;flob|bar/baz|wibble/wobble', _onError);
       expect(errors.length, 1);
       expect(packages.length, 1);
-      expect(packages['bar/baz'].name, 'foo');
+      expect(packages['bar/baz']!.name, 'foo');
     });
 
-    test('should emit error for conflicting output_roots', () {
-      optionParser.parse(null,
+    test('should emit error for conflicting outputRoots', () {
+      optionParser.parse(optionName,
           'foo|bar/baz|wibble/wobble;foo|bar/baz|womble/wumble', _onError);
       expect(errors.length, 1);
       expect(packages.length, 1);
-      expect(packages['bar/baz'].outputRoot, 'wibble/wobble');
+      expect(packages['bar/baz']!.outputRoot, 'wibble/wobble');
     });
 
     test('should normalize paths', () {
-      optionParser.parse(
-          null, 'foo|bar//baz/|quux/;a|b/|c;c|d//e/f///|g//h//', _onError);
+      optionParser.parse(optionName,
+          'foo|bar//baz/|quux/;a|b/|c;c|d//e/f///|g//h//', _onError);
       expect(errors, isEmpty);
       expect(packages.length, 3);
-      expect(packages['bar/baz'].name, 'foo');
-      expect(packages['bar/baz'].inputRoot, 'bar/baz');
-      expect(packages['bar/baz'].outputRoot, 'quux');
-      expect(packages['b'].name, 'a');
-      expect(packages['b'].inputRoot, 'b');
-      expect(packages['b'].outputRoot, 'c');
-      expect(packages['d/e/f'].name, 'c');
-      expect(packages['d/e/f'].inputRoot, 'd/e/f');
-      expect(packages['d/e/f'].outputRoot, 'g/h');
+      expect(packages['bar/baz']!.name, 'foo');
+      expect(packages['bar/baz']!.inputRoot, 'bar/baz');
+      expect(packages['bar/baz']!.outputRoot, 'quux');
+      expect(packages['b']!.name, 'a');
+      expect(packages['b']!.inputRoot, 'b');
+      expect(packages['b']!.outputRoot, 'c');
+      expect(packages['d/e/f']!.name, 'c');
+      expect(packages['d/e/f']!.inputRoot, 'd/e/f');
+      expect(packages['d/e/f']!.outputRoot, 'g/h');
     });
   });
 
   group('BazelOutputConfiguration', () {
     Map<String, BazelPackage> packages;
-    BazelOutputConfiguration config;
+    late BazelOutputConfiguration config;
 
     setUp(() {
       packages = {
diff --git a/protoc_plugin/test/client_generator_test.dart b/protoc_plugin/test/client_generator_test.dart
index 157805c..fbe2398 100644
--- a/protoc_plugin/test/client_generator_test.dart
+++ b/protoc_plugin/test/client_generator_test.dart
@@ -3,8 +3,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'package:protoc_plugin/indenting_writer.dart';
 import 'package:protoc_plugin/protoc.dart';
 import 'package:protoc_plugin/src/linker.dart';
diff --git a/protoc_plugin/test/default_value_escape_test.dart b/protoc_plugin/test/default_value_escape_test.dart
index 2894c50..b71a01b 100644
--- a/protoc_plugin/test/default_value_escape_test.dart
+++ b/protoc_plugin/test/default_value_escape_test.dart
@@ -3,8 +3,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'package:test/test.dart';
 
 import '../out/protos/default_value_escape.pb.dart';
diff --git a/protoc_plugin/test/descriptor_test.dart b/protoc_plugin/test/descriptor_test.dart
index cc97675..34085cf 100644
--- a/protoc_plugin/test/descriptor_test.dart
+++ b/protoc_plugin/test/descriptor_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'package:protobuf/protobuf.dart';
 import 'package:protoc_plugin/src/generated/descriptor.pb.dart';
 import 'package:test/test.dart';
diff --git a/protoc_plugin/test/enum_generator_test.dart b/protoc_plugin/test/enum_generator_test.dart
index a2b7b02..715df7e 100755
--- a/protoc_plugin/test/enum_generator_test.dart
+++ b/protoc_plugin/test/enum_generator_test.dart
@@ -3,8 +3,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'package:protoc_plugin/indenting_writer.dart';
 import 'package:protoc_plugin/protoc.dart';
 import 'package:protoc_plugin/src/generated/descriptor.pb.dart';
diff --git a/protoc_plugin/test/extension_generator_test.dart b/protoc_plugin/test/extension_generator_test.dart
index b49ff6d..ceb0696 100644
--- a/protoc_plugin/test/extension_generator_test.dart
+++ b/protoc_plugin/test/extension_generator_test.dart
@@ -3,8 +3,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'package:protoc_plugin/indenting_writer.dart';
 import 'package:protoc_plugin/protoc.dart';
 import 'package:protoc_plugin/src/generated/descriptor.pb.dart' as pb;
diff --git a/protoc_plugin/test/extension_test.dart b/protoc_plugin/test/extension_test.dart
index 56b7408..c4b668a 100644
--- a/protoc_plugin/test/extension_test.dart
+++ b/protoc_plugin/test/extension_test.dart
@@ -3,8 +3,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'package:protobuf/protobuf.dart';
 import 'package:test/test.dart';
 
@@ -17,7 +15,8 @@
 import '../out/protos/non_nested_extension.pb.dart';
 import 'test_util.dart';
 
-Matcher throwsArgError(String expectedMessage) => throwsA(predicate((x) {
+Matcher throwsArgError(String expectedMessage) =>
+    throwsA(predicate((dynamic x) {
       expect(x, isArgumentError);
       expect(x.message, expectedMessage);
       return true;
@@ -174,14 +173,14 @@
   });
 
   test('can extend a message with a message field with a different type', () {
-    expect(Non_nested_extension.nonNestedExtension.makeDefault(),
+    expect(Non_nested_extension.nonNestedExtension.makeDefault!(),
         TypeMatcher<MyNonNestedExtension>());
     expect(Non_nested_extension.nonNestedExtension.name, 'nonNestedExtension');
   });
 
   test('can extend a message with a message field of the same type', () {
     expect(
-        MyNestedExtension.recursiveExtension.makeDefault()
+        MyNestedExtension.recursiveExtension.makeDefault!()
             is MessageToBeExtended,
         isTrue);
     expect(MyNestedExtension.recursiveExtension.name, 'recursiveExtension');
@@ -532,7 +531,7 @@
     final withUnknownFields = Outer.fromBuffer(original.writeToBuffer());
 
     expect(
-        withUnknownFields.innerMap[0]
+        withUnknownFields.innerMap[0]!
             .hasExtension(Extend_unittest.innerExtensionString),
         isFalse);
 
@@ -540,7 +539,8 @@
     final reparsed = r.reparseMessage(withUnknownFields);
 
     expect(
-        reparsed.innerMap[0].hasExtension(Extend_unittest.innerExtensionString),
+        reparsed.innerMap[0]!
+            .hasExtension(Extend_unittest.innerExtensionString),
         isTrue);
     expect(
         identical(withUnknownFields.innerMap[1], reparsed.innerMap[1]), isTrue);
diff --git a/protoc_plugin/test/file_generator_test.dart b/protoc_plugin/test/file_generator_test.dart
index 84c733a..6763579 100644
--- a/protoc_plugin/test/file_generator_test.dart
+++ b/protoc_plugin/test/file_generator_test.dart
@@ -3,8 +3,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'package:protoc_plugin/indenting_writer.dart';
 import 'package:protoc_plugin/protoc.dart';
 import 'package:protoc_plugin/src/generated/descriptor.pb.dart';
@@ -95,8 +93,8 @@
   test('FileGenerator outputs a .pb.dart file for a proto with one message',
       () {
     var fd = buildFileDescriptor();
-    var options =
-        parseGenerationOptions(CodeGeneratorRequest(), CodeGeneratorResponse());
+    var options = parseGenerationOptions(
+        CodeGeneratorRequest(), CodeGeneratorResponse())!;
     var fg = FileGenerator(fd, options);
     link(options, [fg]);
     expectMatchesGoldenFile(
@@ -105,8 +103,8 @@
 
   test('FileGenerator outputs a .pb.dart file for an Int64 message', () {
     var fd = createInt64Proto();
-    var options =
-        parseGenerationOptions(CodeGeneratorRequest(), CodeGeneratorResponse());
+    var options = parseGenerationOptions(
+        CodeGeneratorRequest(), CodeGeneratorResponse())!;
     var fg = FileGenerator(fd, options);
     link(options, [fg]);
     expectMatchesGoldenFile(
@@ -119,7 +117,7 @@
     var fd = buildFileDescriptor();
     var options = parseGenerationOptions(
         CodeGeneratorRequest()..parameter = 'generate_kythe_info',
-        CodeGeneratorResponse());
+        CodeGeneratorResponse())!;
     var fg = FileGenerator(fd, options);
     link(options, [fg]);
     expectMatchesGoldenFile(fg.generateMainFile().sourceLocationInfo.toString(),
@@ -129,8 +127,8 @@
   test('FileGenerator outputs a pbjson.dart file for a proto with one message',
       () {
     var fd = buildFileDescriptor();
-    var options =
-        parseGenerationOptions(CodeGeneratorRequest(), CodeGeneratorResponse());
+    var options = parseGenerationOptions(
+        CodeGeneratorRequest(), CodeGeneratorResponse())!;
     var fg = FileGenerator(fd, options);
     link(options, [fg]);
     expectMatchesGoldenFile(
@@ -139,8 +137,8 @@
 
   test('FileGenerator generates files for a top-level enum', () {
     var fd = buildFileDescriptor(phoneNumber: false, topLevelEnum: true);
-    var options =
-        parseGenerationOptions(CodeGeneratorRequest(), CodeGeneratorResponse());
+    var options = parseGenerationOptions(
+        CodeGeneratorRequest(), CodeGeneratorResponse())!;
 
     var fg = FileGenerator(fd, options);
     link(options, [fg]);
@@ -154,7 +152,7 @@
     var fd = buildFileDescriptor(phoneNumber: false, topLevelEnum: true);
     var options = parseGenerationOptions(
         CodeGeneratorRequest()..parameter = 'generate_kythe_info',
-        CodeGeneratorResponse());
+        CodeGeneratorResponse())!;
     var fg = FileGenerator(fd, options);
     link(options, [fg]);
 
@@ -166,8 +164,8 @@
 
   test('FileGenerator generates a .pbjson.dart file for a top-level enum', () {
     var fd = buildFileDescriptor(phoneNumber: false, topLevelEnum: true);
-    var options =
-        parseGenerationOptions(CodeGeneratorRequest(), CodeGeneratorResponse());
+    var options = parseGenerationOptions(
+        CodeGeneratorRequest(), CodeGeneratorResponse())!;
 
     var fg = FileGenerator(fd, options);
     link(options, [fg]);
@@ -178,8 +176,8 @@
   test('FileGenerator outputs library for a .proto in a package', () {
     var fd = buildFileDescriptor();
     fd.package = 'pb_library';
-    var options =
-        parseGenerationOptions(CodeGeneratorRequest(), CodeGeneratorResponse());
+    var options = parseGenerationOptions(
+        CodeGeneratorRequest(), CodeGeneratorResponse())!;
 
     var fg = FileGenerator(fd, options);
     link(options, [fg]);
@@ -203,8 +201,8 @@
             ..type = FieldDescriptorProto_Type.TYPE_INT64
         ]));
 
-    var options =
-        parseGenerationOptions(CodeGeneratorRequest(), CodeGeneratorResponse());
+    var options = parseGenerationOptions(
+        CodeGeneratorRequest(), CodeGeneratorResponse())!;
 
     var fg = FileGenerator(fd, options);
     link(options, [fg]);
@@ -230,8 +228,8 @@
       ..messageType.add(empty)
       ..service.add(sd);
 
-    var options =
-        parseGenerationOptions(CodeGeneratorRequest(), CodeGeneratorResponse());
+    var options = parseGenerationOptions(
+        CodeGeneratorRequest(), CodeGeneratorResponse())!;
 
     var fg = FileGenerator(fd, options);
     link(options, [fg]);
@@ -420,7 +418,7 @@
     fd.dependency.addAll(['package1.proto', 'package2.proto']);
     var request = CodeGeneratorRequest();
     var response = CodeGeneratorResponse();
-    var options = parseGenerationOptions(request, response);
+    var options = parseGenerationOptions(request, response)!;
 
     var fg = FileGenerator(fd, options);
     link(options,
diff --git a/protoc_plugin/test/message_generator_test.dart b/protoc_plugin/test/message_generator_test.dart
index 1cf2c4a..e8b6d2e 100755
--- a/protoc_plugin/test/message_generator_test.dart
+++ b/protoc_plugin/test/message_generator_test.dart
@@ -3,8 +3,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'dart:collection';
 
 import 'package:collection/collection.dart';
@@ -19,9 +17,9 @@
 import 'golden_file.dart';
 
 void main() {
-  FileDescriptorProto fd;
+  late FileDescriptorProto fd;
   EnumDescriptorProto ed;
-  DescriptorProto md;
+  late DescriptorProto md;
   setUp(() async {
     fd = FileDescriptorProto();
     ed = EnumDescriptorProto()
@@ -76,11 +74,12 @@
       ..enumType.add(ed);
   });
   test('testMessageGenerator', () {
-    var options =
-        parseGenerationOptions(CodeGeneratorRequest(), CodeGeneratorResponse());
+    var options = parseGenerationOptions(
+        CodeGeneratorRequest(), CodeGeneratorResponse())!;
 
-    var fg = FileGenerator(fd, options);
-    var mg = MessageGenerator.topLevel(md, fg, {}, null, <String>{}, 0);
+    FileGenerator fg = FileGenerator(fd, options);
+    MessageGenerator mg =
+        MessageGenerator.topLevel(md, fg, {}, null, <String>{}, 0);
 
     var ctx = GenerationContext(options);
     mg.register(ctx);
@@ -101,10 +100,11 @@
   });
 
   test('testMetadataIndices', () {
-    var options =
-        parseGenerationOptions(CodeGeneratorRequest(), CodeGeneratorResponse());
-    var fg = FileGenerator(fd, options);
-    var mg = MessageGenerator.topLevel(md, fg, {}, null, <String>{}, 0);
+    var options = parseGenerationOptions(
+        CodeGeneratorRequest(), CodeGeneratorResponse())!;
+    FileGenerator fg = FileGenerator(fd, options);
+    MessageGenerator mg =
+        MessageGenerator.topLevel(md, fg, {}, null, <String>{}, 0);
 
     var ctx = GenerationContext(options);
     mg.register(ctx);
diff --git a/protoc_plugin/test/names_test.dart b/protoc_plugin/test/names_test.dart
index 4e1adf3..9fa3a0d 100644
--- a/protoc_plugin/test/names_test.dart
+++ b/protoc_plugin/test/names_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'package:protoc_plugin/names.dart' as names;
 import 'package:protoc_plugin/src/generated/dart_options.pb.dart';
 import 'package:protoc_plugin/src/generated/descriptor.pb.dart';
@@ -220,7 +218,7 @@
   });
 
   test('The proto name is set correctly', () {
-    expect(json_name.JsonNamedMessage().info_.byName['barName'].protoName,
+    expect(json_name.JsonNamedMessage().info_.byName['barName']!.protoName,
         'foo_name');
   });
 
diff --git a/protoc_plugin/test/protoc_options_test.dart b/protoc_plugin/test/protoc_options_test.dart
index f463b94..f197efb 100644
--- a/protoc_plugin/test/protoc_options_test.dart
+++ b/protoc_plugin/test/protoc_options_test.dart
@@ -3,15 +3,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'package:protoc_plugin/src/generated/plugin.pb.dart';
 import 'package:protoc_plugin/src/options.dart';
 import 'package:test/test.dart';
 
 void main() {
   test('testValidGeneratorOptions', () {
-    void checkValid(String parameter) {
+    void checkValid(String? parameter) {
       var request = CodeGeneratorRequest();
       if (parameter != null) request.parameter = parameter;
       var response = CodeGeneratorResponse();
@@ -28,9 +26,9 @@
   });
 
   test('testInvalidGeneratorOptions', () {
-    void checkInvalid(String parameter) {
+    checkInvalid(String parameter) {
       var request = CodeGeneratorRequest();
-      if (parameter != null) request.parameter = parameter;
+      request.parameter = parameter;
       var response = CodeGeneratorResponse();
       var options = parseGenerationOptions(request, response);
       expect(options, isNull);
diff --git a/protoc_plugin/test/service_generator_test.dart b/protoc_plugin/test/service_generator_test.dart
index 5dc0214..388a78a 100644
--- a/protoc_plugin/test/service_generator_test.dart
+++ b/protoc_plugin/test/service_generator_test.dart
@@ -3,8 +3,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'package:protoc_plugin/indenting_writer.dart';
 import 'package:protoc_plugin/protoc.dart';
 import 'package:protoc_plugin/src/linker.dart';
diff --git a/protoc_plugin/test/validate_fail_test.dart b/protoc_plugin/test/validate_fail_test.dart
index 5c04584..5dde01e 100755
--- a/protoc_plugin/test/validate_fail_test.dart
+++ b/protoc_plugin/test/validate_fail_test.dart
@@ -3,8 +3,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.11
-
 import 'package:fixnum/fixnum.dart';
 import 'package:test/test.dart';
 
@@ -25,10 +23,6 @@
     var builder = TestAllTypes();
 
     expect(() {
-      builder.optionalInt32 = null;
-    }, throwsArgumentError);
-
-    expect(() {
       builder.optionalInt32 = cast('101') as int;
     }, badArgument);
     expect(() {