Version 2.13.0-201.0.dev

Merge commit 'f1fb297ad90c619af90aeeec3abe1e6c6a379c0e' into 'dev'
diff --git a/pkg/analysis_server/tool/spec/api.dart b/pkg/analysis_server/tool/spec/api.dart
index fd40a3b..95fddb4f 100644
--- a/pkg/analysis_server/tool/spec/api.dart
+++ b/pkg/analysis_server/tool/spec/api.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.9
-
 /// Data structures representing an API definition, and visitor base classes
 /// for visiting those data structures.
 import 'dart:collection';
@@ -19,8 +17,8 @@
 
   Api(this.version, this.domains, this.types, this.refactorings,
       dom.Element html,
-      {bool experimental})
-      : super(html, experimental, false);
+      {bool experimental = false})
+      : super(html, experimental: experimental, deprecated: false);
 }
 
 /// Base class for objects in the API model.
@@ -31,12 +29,10 @@
   /// A flag to indicate if this API is deprecated.
   final bool deprecated;
 
-  /// Html element representing this part of the API.
-  final dom.Element html;
+  /// Html element representing this part of the API, `null` if built-in.
+  final dom.Element? html;
 
-  ApiNode(this.html, bool experimental, bool deprecated)
-      : experimental = experimental ?? false,
-        deprecated = deprecated ?? false;
+  ApiNode(this.html, {this.experimental = false, this.deprecated = false});
 }
 
 /// Base class for visiting the API definition.
@@ -59,8 +55,11 @@
   final List<Notification> notifications;
 
   Domain(this.name, this.requests, this.notifications, dom.Element html,
-      {bool experimental, bool deprecated})
-      : super(html, experimental, deprecated);
+      {bool experimental = false, bool deprecated = false})
+      : super(html, experimental: experimental, deprecated: deprecated);
+
+  @override
+  dom.Element get html => super.html!;
 }
 
 /// API visitor that visits the entire API hierarchically by default.
@@ -76,8 +75,12 @@
   /// If it is not possible (because the chain ends with a [TypeReference] that
   /// is not defined in the API), then that final [TypeReference] is returned.
   TypeDecl resolveTypeReferenceChain(TypeDecl type) {
-    while (type is TypeReference && api.types.containsKey(type.typeName)) {
-      type = api.types[(type as TypeReference).typeName].type;
+    while (type is TypeReference) {
+      var newTypeRef = api.types[type.typeName];
+      if (newTypeRef == null) {
+        break;
+      }
+      type = newTypeRef.type;
     }
     return type;
   }
@@ -94,30 +97,37 @@
   }
 
   void visitNotification(Notification notification) {
-    if (notification.params != null) {
-      visitTypeDecl(notification.params);
+    var params = notification.params;
+    if (params != null) {
+      visitTypeDecl(params);
     }
   }
 
   void visitRefactoring(Refactoring refactoring) {
-    if (refactoring.feedback != null) {
-      visitTypeDecl(refactoring.feedback);
+    var feedback = refactoring.feedback;
+    if (feedback != null) {
+      visitTypeDecl(feedback);
     }
-    if (refactoring.options != null) {
-      visitTypeDecl(refactoring.options);
+
+    var options = refactoring.options;
+    if (options != null) {
+      visitTypeDecl(options);
     }
   }
 
   void visitRefactorings(Refactorings refactorings) {
-    refactorings?.forEach(visitRefactoring);
+    refactorings.forEach(visitRefactoring);
   }
 
   void visitRequest(Request request) {
-    if (request.params != null) {
-      visitTypeDecl(request.params);
+    var params = request.params;
+    if (params != null) {
+      visitTypeDecl(params);
     }
-    if (request.result != null) {
-      visitTypeDecl(request.result);
+
+    var result = request.result;
+    if (result != null) {
+      visitTypeDecl(result);
     }
   }
 
@@ -175,11 +185,11 @@
 
   /// Type of the object associated with the "params" key in the notification
   /// object, or null if the notification has no parameters.
-  final TypeObject params;
+  final TypeObject? params;
 
   Notification(this.domainName, this.event, this.params, dom.Element html,
-      {bool experimental})
-      : super(html, experimental, false);
+      {bool experimental = false})
+      : super(html, experimental: experimental, deprecated: false);
 
   /// Get the name of the notification, including the domain prefix.
   String get longEvent => '$domainName.$event';
@@ -191,9 +201,12 @@
       TypeObjectField('event', TypeReference('String', null), null,
           value: '$domainName.$event')
     ];
+
+    var params = this.params;
     if (params != null) {
       fields.add(TypeObjectField('params', params, null));
     }
+
     return TypeObject(fields, null);
   }
 }
@@ -206,23 +219,24 @@
 
   /// Type of the refactoring feedback, or null if the refactoring has no
   /// feedback.
-  final TypeObject feedback;
+  final TypeObject? feedback;
 
   /// Type of the refactoring options, or null if the refactoring has no
   /// options.
-  final TypeObject options;
+  final TypeObject? options;
 
   Refactoring(this.kind, this.feedback, this.options, dom.Element html,
-      {bool experimental})
-      : super(html, experimental, false);
+      {bool experimental = false})
+      : super(html, experimental: experimental, deprecated: false);
 }
 
 /// A collection of refactoring definitions.
 class Refactorings extends ApiNode with IterableMixin<Refactoring> {
   final List<Refactoring> refactorings;
 
-  Refactorings(this.refactorings, dom.Element html, {bool experimental})
-      : super(html, experimental, false);
+  Refactorings(this.refactorings, dom.Element? html,
+      {bool experimental = false})
+      : super(html, experimental: experimental, deprecated: false);
 
   @override
   Iterator<Refactoring> get iterator => refactorings.iterator;
@@ -238,16 +252,16 @@
 
   /// Type of the object associated with the "params" key in the request object,
   /// or null if the request has no parameters.
-  final TypeObject params;
+  final TypeObject? params;
 
   /// Type of the object associated with the "result" key in the response
   /// object, or `null` if the response has no results.
-  final TypeObject result;
+  final TypeObject? result;
 
   Request(
       this.domainName, this.method, this.params, this.result, dom.Element html,
-      {bool experimental, bool deprecated})
-      : super(html, experimental, deprecated);
+      {bool experimental = false, bool deprecated = false})
+      : super(html, experimental: experimental, deprecated: deprecated);
 
   /// Get the name of the request, including the domain prefix.
   String get longMethod => '$domainName.$method';
@@ -260,9 +274,12 @@
       TypeObjectField('method', TypeReference('String', null), null,
           value: '$domainName.$method')
     ];
+
+    var params = this.params;
     if (params != null) {
       fields.add(TypeObjectField('params', params, null));
     }
+
     return TypeObject(fields, null);
   }
 
@@ -274,17 +291,21 @@
       TypeObjectField('error', TypeReference('RequestError', null), null,
           optional: true)
     ];
+
+    var result = this.result;
     if (result != null) {
       fields.add(TypeObjectField('result', result, null));
     }
+
     return TypeObject(fields, null);
   }
 }
 
 /// Base class for all possible types.
 abstract class TypeDecl extends ApiNode {
-  TypeDecl(dom.Element html, bool experimental, bool deprecated)
-      : super(html, experimental, deprecated);
+  TypeDecl(dom.Element? html,
+      {bool experimental = false, bool deprecated = false})
+      : super(html, experimental: experimental, deprecated: deprecated);
 
   T accept<T>(ApiVisitor<T> visitor);
 }
@@ -297,8 +318,8 @@
   bool isExternal = false;
 
   TypeDefinition(this.name, this.type, dom.Element html,
-      {bool experimental, bool deprecated})
-      : super(html, experimental, deprecated);
+      {bool experimental = false, bool deprecated = false})
+      : super(html, experimental: experimental, deprecated: deprecated);
 }
 
 /// Type of an enum.  We represent enums in JSON as strings, so this type
@@ -306,8 +327,9 @@
 class TypeEnum extends TypeDecl {
   final List<TypeEnumValue> values;
 
-  TypeEnum(this.values, dom.Element html, {bool experimental, bool deprecated})
-      : super(html, experimental, deprecated);
+  TypeEnum(this.values, dom.Element html,
+      {bool experimental = false, bool deprecated = false})
+      : super(html, experimental: experimental, deprecated: deprecated);
 
   @override
   T accept<T>(ApiVisitor<T> visitor) => visitor.visitTypeEnum(this);
@@ -318,16 +340,19 @@
   final String value;
 
   TypeEnumValue(this.value, dom.Element html,
-      {bool experimental, bool deprecated})
-      : super(html, experimental, deprecated);
+      {bool experimental = false, bool deprecated = false})
+      : super(html, experimental: experimental, deprecated: deprecated);
+
+  @override
+  dom.Element get html => super.html!;
 }
 
 /// Type of a JSON list.
 class TypeList extends TypeDecl {
   final TypeDecl itemType;
 
-  TypeList(this.itemType, dom.Element html, {bool experimental})
-      : super(html, experimental, false);
+  TypeList(this.itemType, dom.Element html, {bool experimental = false})
+      : super(html, experimental: experimental, deprecated: false);
 
   @override
   T accept<T>(ApiVisitor<T> visitor) => visitor.visitTypeList(this);
@@ -344,8 +369,9 @@
   /// Type of map values.
   final TypeDecl valueType;
 
-  TypeMap(this.keyType, this.valueType, dom.Element html, {bool experimental})
-      : super(html, experimental, false);
+  TypeMap(this.keyType, this.valueType, dom.Element html,
+      {bool experimental = false})
+      : super(html, experimental: experimental, deprecated: false);
 
   @override
   T accept<T>(ApiVisitor<T> visitor) => visitor.visitTypeMap(this);
@@ -355,15 +381,15 @@
 class TypeObject extends TypeDecl {
   final List<TypeObjectField> fields;
 
-  TypeObject(this.fields, dom.Element html,
-      {bool experimental, bool deprecated})
-      : super(html, experimental, deprecated);
+  TypeObject(this.fields, dom.Element? html,
+      {bool experimental = false, bool deprecated = false})
+      : super(html, experimental: experimental, deprecated: deprecated);
 
   @override
   T accept<T>(ApiVisitor<T> visitor) => visitor.visitTypeObject(this);
 
   /// Return the field with the given [name], or null if there is no such field.
-  TypeObjectField getField(String name) {
+  TypeObjectField? getField(String name) {
     for (var field in fields) {
       if (field.name == name) {
         return field;
@@ -380,11 +406,14 @@
   final bool optional;
 
   /// Value that the field is required to contain, or null if it may vary.
-  final Object value;
+  final Object? value;
 
-  TypeObjectField(this.name, this.type, dom.Element html,
-      {this.optional = false, this.value, bool experimental, bool deprecated})
-      : super(html, experimental, deprecated);
+  TypeObjectField(this.name, this.type, dom.Element? html,
+      {this.optional = false,
+      this.value,
+      bool experimental = false,
+      bool deprecated = false})
+      : super(html, experimental: experimental, deprecated: deprecated);
 }
 
 /// A reference to a type which is either defined elsewhere in the API or which
@@ -392,8 +421,8 @@
 class TypeReference extends TypeDecl {
   final String typeName;
 
-  TypeReference(this.typeName, dom.Element html, {bool experimental})
-      : super(html, experimental, false) {
+  TypeReference(this.typeName, dom.Element? html, {bool experimental = false})
+      : super(html, experimental: experimental, deprecated: false) {
     if (typeName.isEmpty) {
       throw Exception('Empty type name');
     }
@@ -409,15 +438,15 @@
 
   List<String> importUris = <String>[];
 
-  Types(this.types, dom.Element html, {bool experimental})
-      : super(html, experimental, false);
+  Types(this.types, dom.Element? html, {bool experimental = false})
+      : super(html, experimental: experimental, deprecated: false);
 
   @override
   Iterator<TypeDefinition> get iterator => types.values.iterator;
 
   Iterable<String> get keys => types.keys;
 
-  TypeDefinition operator [](String typeName) => types[typeName];
+  TypeDefinition? operator [](String typeName) => types[typeName];
 
   bool containsKey(String typeName) => types.containsKey(typeName);
 }
@@ -429,8 +458,9 @@
   /// The field that is used to disambiguate this union
   final String field;
 
-  TypeUnion(this.choices, this.field, dom.Element html, {bool experimental})
-      : super(html, experimental, false);
+  TypeUnion(this.choices, this.field, dom.Element html,
+      {bool experimental = false})
+      : super(html, experimental: experimental, deprecated: false);
 
   @override
   T accept<T>(ApiVisitor<T> visitor) => visitor.visitTypeUnion(this);
diff --git a/pkg/analysis_server/tool/spec/check_all_test.dart b/pkg/analysis_server/tool/spec/check_all_test.dart
index 14ede1c..3be8ed7 100644
--- a/pkg/analysis_server/tool/spec/check_all_test.dart
+++ b/pkg/analysis_server/tool/spec/check_all_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.9
-
 import 'dart:io';
 
 import 'package:analyzer_utilities/tools.dart';
diff --git a/pkg/analysis_server/tool/spec/codegen_analysis_server.dart b/pkg/analysis_server/tool/spec/codegen_analysis_server.dart
index a41e9ad..096db25 100644
--- a/pkg/analysis_server/tool/spec/codegen_analysis_server.dart
+++ b/pkg/analysis_server/tool/spec/codegen_analysis_server.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.9
-
 /// Code generation for the file "AnalysisServer.java".
 import 'package:analyzer_utilities/tools.dart';
 
@@ -167,14 +165,18 @@
       }));
       write('public void $methodName(');
       var arguments = <String>[];
-      if (request.params != null) {
-        for (var field in request.params.fields) {
+
+      var params = request.params;
+      if (params != null) {
+        for (var field in params.fields) {
           arguments.add('${javaType(field.type)} ${javaName(field.name)}');
         }
       }
+
       if (request.result != null) {
         arguments.add('${consumerName(request)} consumer');
       }
+
       write(arguments.join(', '));
       writeln(');');
     });
diff --git a/pkg/analysis_server/tool/spec/codegen_dart.dart b/pkg/analysis_server/tool/spec/codegen_dart.dart
index b38ba00..7069dc0 100644
--- a/pkg/analysis_server/tool/spec/codegen_dart.dart
+++ b/pkg/analysis_server/tool/spec/codegen_dart.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.9
-
 import 'api.dart';
 
 /// Visitor specialized for generating Dart code.
@@ -21,8 +19,9 @@
     if (type is TypeReference) {
       var typeName = type.typeName;
       var referencedDefinition = api.types[typeName];
-      if (_typeRenames.containsKey(typeName)) {
-        return _typeRenames[typeName];
+      var typeRename = _typeRenames[typeName];
+      if (typeRename != null) {
+        return typeRename;
       }
       if (referencedDefinition == null) {
         return typeName;
diff --git a/pkg/analysis_server/tool/spec/codegen_dart_notification_handler.dart b/pkg/analysis_server/tool/spec/codegen_dart_notification_handler.dart
index a1ae0ab..160c52d 100644
--- a/pkg/analysis_server/tool/spec/codegen_dart_notification_handler.dart
+++ b/pkg/analysis_server/tool/spec/codegen_dart_notification_handler.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.9
-
 import 'package:analyzer_utilities/tools.dart';
 import 'package:html/dom.dart';
 
@@ -140,6 +138,6 @@
         _generateNotificationMethodName(
             notification.domainName, notification.event),
         _generateParamTypeName(notification.domainName, notification.event),
-        _generateDartDoc(notification.html)));
+        _generateDartDoc(notification.html!)));
   }
 }
diff --git a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
index 7410305..c17e46f 100644
--- a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
+++ b/pkg/analysis_server/tool/spec/codegen_dart_protocol.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.9
-
 import 'dart:convert';
 
 import 'package:analyzer_utilities/tools.dart';
@@ -268,8 +266,9 @@
       toHtmlVisitor.p(() {
         toHtmlVisitor.write(impliedType.humanReadableName);
       });
-      if (impliedType.type != null) {
-        toHtmlVisitor.showType(null, impliedType.type);
+      var impliedTypeType = impliedType.type;
+      if (impliedTypeType != null) {
+        toHtmlVisitor.showType(null, impliedTypeType);
       }
       toHtmlVisitor.p(() {
         toHtmlVisitor.write(disclaimer);
@@ -412,8 +411,9 @@
       toHtmlVisitor.p(() {
         toHtmlVisitor.write(impliedType.humanReadableName);
       });
-      if (impliedType.type != null) {
-        toHtmlVisitor.showType(null, impliedType.type);
+      var impliedTypeType = impliedType.type;
+      if (impliedTypeType != null) {
+        toHtmlVisitor.showType(null, impliedTypeType);
       }
       toHtmlVisitor.p(() {
         toHtmlVisitor.write(disclaimer);
@@ -523,7 +523,7 @@
   }
 
   /// Emit the operator== code for an object class.
-  void emitObjectEqualsMember(TypeObject type, String className) {
+  void emitObjectEqualsMember(TypeObject? type, String className) {
     writeln('@override');
     writeln('bool operator ==(other) {');
     indent(() {
@@ -639,7 +639,7 @@
   }
 
   /// Emit the hashCode getter for an object class.
-  void emitObjectHashCode(TypeObject type, String className) {
+  void emitObjectHashCode(TypeObject? type, String className) {
     writeln('@override');
     writeln('int get hashCode {');
     indent(() {
diff --git a/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart b/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart
index 1ed8a77..5864cb2 100644
--- a/pkg/analysis_server/tool/spec/codegen_inttest_methods.dart
+++ b/pkg/analysis_server/tool/spec/codegen_inttest_methods.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.9
-
 /// Code generation for the file "integration_test_methods.dart".
 import 'package:analyzer_utilities/tools.dart';
 import 'package:path/path.dart' as path;
@@ -186,8 +184,9 @@
     var methodName = camelJoin(['send', request.domainName, request.method]);
     var args = <String>[];
     var optionalArgs = <String>[];
-    if (request.params != null) {
-      for (var field in request.params.fields) {
+    var params = request.params;
+    if (params != null) {
+      for (var field in params.fields) {
         if (field.optional) {
           optionalArgs.add(formatArgument(field));
         } else {
@@ -201,32 +200,35 @@
     writeln();
     docComment(toHtmlVisitor.collectHtml(() {
       toHtmlVisitor.translateHtml(request.html);
-      toHtmlVisitor.describePayload(request.params, 'Parameters');
+      toHtmlVisitor.describePayload(params, 'Parameters');
       toHtmlVisitor.describePayload(request.result, 'Returns');
     }));
     if (request.deprecated) {
       writeln('@deprecated');
     }
-    String resultClass;
+
+    String? resultClass;
     String futureClass;
-    if (request.result == null) {
-      futureClass = 'Future';
-    } else {
+    var hasResult = request.result != null;
+    if (hasResult) {
       resultClass = camelJoin([request.domainName, request.method, 'result'],
           doCapitalize: true);
       futureClass = 'Future<$resultClass>';
+    } else {
+      futureClass = 'Future';
     }
+
     writeln('$futureClass $methodName(${args.join(', ')}) async {');
     indent(() {
       var requestClass = camelJoin(
           [request.domainName, request.method, 'params'],
           doCapitalize: true);
       var paramsVar = 'null';
-      if (request.params != null) {
+      if (params != null) {
         paramsVar = 'params';
         var args = <String>[];
         var optionalArgs = <String>[];
-        for (var field in request.params.fields) {
+        for (var field in params.fields) {
           if (field.optional) {
             optionalArgs.add('${field.name}: ${field.name}');
           } else {
@@ -238,7 +240,7 @@
       }
       var methodJson = "'${request.longMethod}'";
       writeln('var result = await server.send($methodJson, $paramsVar);');
-      if (request.result != null) {
+      if (resultClass != null) {
         var kind = 'null';
         if (requestClass == 'EditGetRefactoringParams') {
           kind = 'kind';
diff --git a/pkg/analysis_server/tool/spec/codegen_java.dart b/pkg/analysis_server/tool/spec/codegen_java.dart
index ea62d4a..54b48e8 100644
--- a/pkg/analysis_server/tool/spec/codegen_java.dart
+++ b/pkg/analysis_server/tool/spec/codegen_java.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.9
-
 /// Tools for Java code generation.
 import 'package:analyzer_utilities/tools.dart';
 import 'package:html/dom.dart' as dom;
@@ -24,9 +22,9 @@
 
 /// Iterate through the values in [map] in the order of increasing keys.
 Iterable<String> _valuesSortedByKey(Map<String, String> map) {
-  var keys = map.keys.toList();
-  keys.sort();
-  return keys.map((String key) => map[key]);
+  var entries = map.entries.toList();
+  entries.sort((a, b) => a.key.compareTo(b.key));
+  return entries.map((e) => e.value);
 }
 
 /// Common code for all Java code generation.
@@ -48,7 +46,7 @@
     'Override': 'OverrideMember',
   };
 
-  _CodegenJavaState _state;
+  _CodegenJavaState _state = _CodegenJavaState();
 
   /// Visitor used to produce doc comments.
   final ToHtmlVisitor toHtmlVisitor;
@@ -127,19 +125,17 @@
 
   /// Return a suitable representation of [name] as the name of a Java variable.
   String javaName(String name) {
-    if (_variableRenames.containsKey(name)) {
-      return _variableRenames[name];
-    }
-    return name;
+    return _variableRenames[name] ?? name;
   }
 
   /// Convert the given [TypeDecl] to a Java type.
   String javaType(TypeDecl type, [bool optional = false]) {
     if (type is TypeReference) {
-      TypeReference resolvedType = resolveTypeReferenceChain(type);
+      var resolvedType = resolveTypeReferenceChain(type) as TypeReference;
       var typeName = resolvedType.typeName;
-      if (_typeRenames.containsKey(typeName)) {
-        typeName = _typeRenames[typeName];
+      var renameTo = _typeRenames[typeName];
+      if (renameTo != null) {
+        typeName = renameTo;
         if (optional) {
           if (typeName == 'boolean') {
             typeName = 'Boolean';
diff --git a/pkg/analysis_server/tool/spec/codegen_java_types.dart b/pkg/analysis_server/tool/spec/codegen_java_types.dart
index 8b2d471..cd11d2c 100644
--- a/pkg/analysis_server/tool/spec/codegen_java_types.dart
+++ b/pkg/analysis_server/tool/spec/codegen_java_types.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.9
-
 /// Code generation for the file "AnalysisServer.java".
 import 'package:analyzer_utilities/tools.dart';
 import 'package:html/dom.dart' as dom;
@@ -60,15 +58,16 @@
         isRefactoringFeedback ||
         isRefactoringOption) {
       var type = impliedType.type;
-      if (type is TypeObject || type is TypeEnum) {
+      if (type != null && (type is TypeObject || type is TypeEnum)) {
         // This is for situations such as 'Override' where the name in the spec
         // doesn't match the java object that we generate:
         var typeNameInJava = typeNameInSpec;
-        if (_typeRenames.containsKey(typeNameInSpec)) {
-          typeNameInJava = _typeRenames[typeNameInSpec];
+        var renamedTo = _typeRenames[typeNameInSpec];
+        if (renamedTo != null) {
+          typeNameInJava = renamedTo;
         }
         map['$typeNameInJava.java'] = (String pkgPath) async {
-          String superclassName;
+          String? superclassName;
           if (isRefactoringFeedback) {
             superclassName = 'RefactoringFeedback';
           }
@@ -102,7 +101,7 @@
 
 class CodegenJavaType extends CodegenJavaVisitor {
   final String className;
-  final String superclassName;
+  final String? superclassName;
   final bool generateGetters;
   final bool generateSetters;
 
@@ -116,7 +115,7 @@
     return camelJoin([request.method, 'consumer'], doCapitalize: true);
   }
 
-  void emitType(TypeDecl type, dom.Element html) {
+  void emitType(TypeDecl type, dom.Element? html) {
     outputHeader(javaStyle: true);
     writeln('package org.dartlang.analysis.server.protocol;');
     writeln();
@@ -233,7 +232,7 @@
     }
   }
 
-  void _writeTypeEnum(TypeDecl type, dom.Element html) {
+  void _writeTypeEnum(TypeDecl type, dom.Element? html) {
     javadocComment(toHtmlVisitor.collectHtml(() {
       toHtmlVisitor.translateHtml(html);
       toHtmlVisitor.br();
@@ -257,7 +256,7 @@
     });
   }
 
-  void _writeTypeObject(TypeDecl type, dom.Element html) {
+  void _writeTypeObject(TypeDecl type, dom.Element? html) {
     writeln('import java.util.Arrays;');
     writeln('import java.util.List;');
     writeln('import java.util.Map;');
diff --git a/pkg/analysis_server/tool/spec/codegen_matchers.dart b/pkg/analysis_server/tool/spec/codegen_matchers.dart
index 1a55c6e..9e0a9d1 100644
--- a/pkg/analysis_server/tool/spec/codegen_matchers.dart
+++ b/pkg/analysis_server/tool/spec/codegen_matchers.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.9
-
 /// Code generation for the file "matchers.dart".
 import 'package:analyzer_utilities/tools.dart';
 
@@ -24,7 +22,7 @@
 
   /// Short human-readable string describing the context of the matcher being
   /// created.
-  String context;
+  late String context;
 
   CodegenMatchersVisitor(Api api)
       : toHtmlVisitor = ToHtmlVisitor(api),
@@ -41,19 +39,20 @@
   /// matches the given [type].
   void makeMatcher(ImpliedType impliedType) {
     context = impliedType.humanReadableName;
+    var impliedTypeType = impliedType.type;
     docComment(toHtmlVisitor.collectHtml(() {
       toHtmlVisitor.p(() {
         toHtmlVisitor.write(context);
       });
-      if (impliedType.type != null) {
-        toHtmlVisitor.showType(null, impliedType.type);
+      if (impliedTypeType != null) {
+        toHtmlVisitor.showType(null, impliedTypeType);
       }
     }));
     write('final Matcher ${camelJoin(['is', impliedType.camelName])} = ');
-    if (impliedType.type == null) {
+    if (impliedTypeType == null) {
       write('isNull');
     } else {
-      visitTypeDecl(impliedType.type);
+      visitTypeDecl(impliedTypeType);
     }
     writeln(';');
     writeln();
diff --git a/pkg/analysis_server/tool/spec/codegen_protocol_constants.dart b/pkg/analysis_server/tool/spec/codegen_protocol_constants.dart
index a81d141..f6cf4f0 100644
--- a/pkg/analysis_server/tool/spec/codegen_protocol_constants.dart
+++ b/pkg/analysis_server/tool/spec/codegen_protocol_constants.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.9
-
 import 'package:analyzer_utilities/tools.dart';
 
 import 'api.dart';
@@ -64,6 +62,15 @@
     codeGeneratorSettings.languageName = 'dart';
   }
 
+  /// Generate the given [constant].
+  void generateConstant(_Constant constant) {
+    write('const String ');
+    write(constant.name);
+    write(' = ');
+    write(constant.value);
+    writeln(';');
+  }
+
   /// Generate all of the constants associates with the [api].
   void generateConstants() {
     writeln("const String PROTOCOL_VERSION = '${api.version}';");
@@ -73,19 +80,10 @@
     var constants = visitor.constants;
     constants.sort((first, second) => first.name.compareTo(second.name));
     for (var constant in constants) {
-      generateContant(constant);
+      generateConstant(constant);
     }
   }
 
-  /// Generate the given [constant].
-  void generateContant(_Constant constant) {
-    write('const String ');
-    write(constant.name);
-    write(' = ');
-    write(constant.value);
-    writeln(';');
-  }
-
   @override
   void visitApi() {
     outputHeader(year: '2017');
@@ -141,7 +139,7 @@
   /// Generate a constant for each of the fields in the given [type], where the
   /// name of each constant will be composed from the [parentName] and the name
   /// of the field.
-  void _addFieldConstants(String parentName, TypeObject type) {
+  void _addFieldConstants(String parentName, TypeObject? type) {
     if (type == null) {
       return;
     }
diff --git a/pkg/analysis_server/tool/spec/from_html.dart b/pkg/analysis_server/tool/spec/from_html.dart
index de97dc7..bf64d22 100644
--- a/pkg/analysis_server/tool/spec/from_html.dart
+++ b/pkg/analysis_server/tool/spec/from_html.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.9
-
 /// Code for reading an HTML API description.
 import 'dart:io';
 
@@ -77,8 +75,8 @@
     Api api;
     var versions = <String>[];
     var domains = <Domain>[];
-    Types types;
-    Refactorings refactorings;
+    var types = Types({}, null);
+    var refactorings = Refactorings([], null);
     recurse(html, 'api', {
       'domain': (dom.Element element) {
         domains.add(domainFromHtml(element));
@@ -111,6 +109,10 @@
       {List<String> optionalAttributes = const []}) {
     var attributesFound = <String>{};
     element.attributes.forEach((name, value) {
+      if (name is! String) {
+        throw Exception(
+            '$context: Only string attribute names expected: $name');
+      }
       if (!requiredAttributes.contains(name) &&
           !optionalAttributes.contains(name)) {
         throw Exception(
@@ -127,7 +129,7 @@
   }
 
   /// Check that the given [element] has the given [expectedName].
-  void checkName(dom.Element element, String expectedName, [String context]) {
+  void checkName(dom.Element element, String expectedName, [String? context]) {
     if (element.localName != expectedName) {
       context ??= element.localName;
       throw Exception(
@@ -145,19 +147,22 @@
   /// Child elements can occur in any order.
   Domain domainFromHtml(dom.Element html) {
     checkName(html, 'domain');
+
     var name = html.attributes['name'];
-    var context = name ?? 'domain';
+    if (name == null) {
+      throw Exception('domains: name not specified');
+    }
+
     var experimental = html.attributes['experimental'] == 'true';
-    checkAttributes(html, ['name'], context,
-        optionalAttributes: ['experimental']);
+    checkAttributes(html, ['name'], name, optionalAttributes: ['experimental']);
     var requests = <Request>[];
     var notifications = <Notification>[];
-    recurse(html, context, {
+    recurse(html, name, {
       'request': (dom.Element child) {
-        requests.add(requestFromHtml(child, context));
+        requests.add(requestFromHtml(child, name));
       },
       'notification': (dom.Element child) {
-        notifications.add(notificationFromHtml(child, context));
+        notifications.add(notificationFromHtml(child, name));
       }
     });
     return Domain(name, requests, notifications, html,
@@ -190,18 +195,30 @@
   /// Child elements can occur in any order.
   Notification notificationFromHtml(dom.Element html, String context) {
     var domainName = getAncestor(html, 'domain', context).attributes['name'];
+    if (domainName == null) {
+      throw Exception('$context: domain not specified');
+    }
+
     checkName(html, 'notification', context);
+
     var event = html.attributes['event'];
-    context = '$context.${event ?? 'event'}';
-    checkAttributes(html, ['event'], context,
-        optionalAttributes: ['experimental']);
-    var experimental = html.attributes['experimental'] == 'true';
-    TypeObject params;
+    if (event == null) {
+      throw Exception('$context: event not specified');
+    }
+
+    context = '$context.$event';
+
+    TypeObject? params;
     recurse(html, context, {
       'params': (dom.Element child) {
         params = typeObjectFromHtml(child, '$context.params');
       }
     });
+
+    checkAttributes(html, ['event'], context,
+        optionalAttributes: ['experimental']);
+    var experimental = html.attributes['experimental'] == 'true';
+
     return Notification(domainName, event, params, html,
         experimental: experimental);
   }
@@ -255,25 +272,29 @@
       },
       'map': (dom.Element child) {
         checkAttributes(child, [], context);
-        TypeDecl keyType;
-        TypeDecl valueType;
+        TypeDecl? keyTypeNullable;
+        TypeDecl? valueTypeNullable;
         recurse(child, context, {
           'key': (dom.Element child) {
-            if (keyType != null) {
+            if (keyTypeNullable != null) {
               throw Exception('$context: Key type already specified');
             }
-            keyType = processContentsAsType(child, '$context.key');
+            keyTypeNullable = processContentsAsType(child, '$context.key');
           },
           'value': (dom.Element child) {
-            if (valueType != null) {
+            if (valueTypeNullable != null) {
               throw Exception('$context: Value type already specified');
             }
-            valueType = processContentsAsType(child, '$context.value');
+            valueTypeNullable = processContentsAsType(child, '$context.value');
           }
         });
-        if (keyType == null) {
-          throw Exception('$context: Key type not specified');
+        var keyType = keyTypeNullable;
+        if (keyType is! TypeReference) {
+          throw Exception(
+            '$context: Key type not specified, or not a reference',
+          );
         }
+        var valueType = valueTypeNullable;
         if (valueType == null) {
           throw Exception('$context: Value type not specified');
         }
@@ -288,7 +309,7 @@
       },
       'union': (dom.Element child) {
         checkAttributes(child, ['field'], context);
-        var field = child.attributes['field'];
+        var field = child.attributes['field']!;
         types.add(
             TypeUnion(processContentsAsTypes(child, context), field, child));
       }
@@ -301,7 +322,7 @@
     var htmlContents = File(filePath).readAsStringSync();
     var document = parser.parse(htmlContents);
     var htmlElement = document.children
-        .singleWhere((element) => element.localName.toLowerCase() == 'html');
+        .singleWhere((element) => element.localName!.toLowerCase() == 'html');
     return apiFromHtml(htmlElement);
   }
 
@@ -314,8 +335,9 @@
     }
     for (var node in parent.nodes) {
       if (node is dom.Element) {
-        if (elementProcessors.containsKey(node.localName)) {
-          elementProcessors[node.localName](node);
+        var processor = elementProcessors[node.localName];
+        if (processor != null) {
+          processor(node);
         } else if (specialElements.contains(node.localName)) {
           throw Exception('$context: Unexpected use of <${node.localName}>');
         } else {
@@ -338,17 +360,21 @@
   /// Child elements can occur in any order.
   Refactoring refactoringFromHtml(dom.Element html) {
     checkName(html, 'refactoring');
+
     var kind = html.attributes['kind'];
-    var context = kind ?? 'refactoring';
-    checkAttributes(html, ['kind'], context);
-    TypeObject feedback;
-    TypeObject options;
-    recurse(html, context, {
+    if (kind == null) {
+      throw Exception('refactorings: kind not specified');
+    }
+
+    checkAttributes(html, ['kind'], kind);
+    TypeObject? feedback;
+    TypeObject? options;
+    recurse(html, kind, {
       'feedback': (dom.Element child) {
-        feedback = typeObjectFromHtml(child, '$context.feedback');
+        feedback = typeObjectFromHtml(child, '$kind.feedback');
       },
       'options': (dom.Element child) {
-        options = typeObjectFromHtml(child, '$context.options');
+        options = typeObjectFromHtml(child, '$kind.options');
       }
     });
     return Refactoring(kind, feedback, options, html);
@@ -387,15 +413,24 @@
   /// Child elements can occur in any order.
   Request requestFromHtml(dom.Element html, String context) {
     var domainName = getAncestor(html, 'domain', context).attributes['name'];
+    if (domainName == null) {
+      throw Exception('$context: domain not specified');
+    }
+
     checkName(html, 'request', context);
+
     var method = html.attributes['method'];
-    context = '$context.${method ?? 'method'}';
+    if (method == null) {
+      throw Exception('$context: method not specified');
+    }
+
+    context = '$context.$method}';
     checkAttributes(html, ['method'], context,
         optionalAttributes: ['experimental', 'deprecated']);
     var experimental = html.attributes['experimental'] == 'true';
     var deprecated = html.attributes['deprecated'] == 'true';
-    TypeObject params;
-    TypeObject result;
+    TypeObject? params;
+    TypeObject? result;
     recurse(html, context, {
       'params': (dom.Element child) {
         params = typeObjectFromHtml(child, '$context.params');
@@ -419,11 +454,15 @@
   /// Child elements can occur in any order.
   TypeDefinition typeDefinitionFromHtml(dom.Element html) {
     checkName(html, 'type');
+
     var name = html.attributes['name'];
-    var context = name ?? 'type';
-    checkAttributes(html, ['name'], context,
+    if (name == null) {
+      throw Exception('types: name not specified');
+    }
+
+    checkAttributes(html, ['name'], name,
         optionalAttributes: ['experimental', 'deprecated']);
-    var type = processContentsAsType(html, context);
+    var type = processContentsAsType(html, name);
     var experimental = html.attributes['experimental'] == 'true';
     var deprecated = html.attributes['deprecated'] == 'true';
     return TypeDefinition(name, type, html,
@@ -484,8 +523,13 @@
   /// Child elements can occur in any order.
   TypeObjectField typeObjectFieldFromHtml(dom.Element html, String context) {
     checkName(html, 'field', context);
+
     var name = html.attributes['name'];
-    context = '$context.${name ?? 'field'}';
+    if (name == null) {
+      throw Exception('$context: name not specified');
+    }
+
+    context = '$context.$name}';
     checkAttributes(html, ['name'], context,
         optionalAttributes: [
           'optional',
@@ -556,7 +600,7 @@
         var api = reader.readApi();
         for (var typeDefinition in api.types) {
           typeDefinition.isExternal = true;
-          childElements.add(typeDefinition.html);
+          childElements.add(typeDefinition.html!);
           typeMap[typeDefinition.name] = typeDefinition;
         }
       },
diff --git a/pkg/analysis_server/tool/spec/generate_all.dart b/pkg/analysis_server/tool/spec/generate_all.dart
index 30fb5f3..20840ce 100644
--- a/pkg/analysis_server/tool/spec/generate_all.dart
+++ b/pkg/analysis_server/tool/spec/generate_all.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.9
-
 import 'dart:io';
 
 import 'package:analyzer_utilities/tools.dart';
diff --git a/pkg/analysis_server/tool/spec/implied_types.dart b/pkg/analysis_server/tool/spec/implied_types.dart
index 521485c..6a49fcc 100644
--- a/pkg/analysis_server/tool/spec/implied_types.dart
+++ b/pkg/analysis_server/tool/spec/implied_types.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.9
-
 /// Code for enumerating the set of types implied by the API.
 import 'package:analyzer_utilities/tools.dart';
 
@@ -18,7 +16,7 @@
 class ImpliedType {
   final String camelName;
   final String humanReadableName;
-  final TypeDecl type;
+  final TypeDecl? type;
 
   /// Kind of implied type this is.  One of:
   /// - 'requestParams'
@@ -41,7 +39,7 @@
 
   _ImpliedTypesVisitor(Api api) : super(api);
 
-  void storeType(String name, String nameSuffix, TypeDecl type, String kind,
+  void storeType(String name, String? nameSuffix, TypeDecl? type, String kind,
       ApiNode apiNode) {
     var humanReadableName = name;
     var camelNameParts = name.split('.');
diff --git a/pkg/analysis_server/tool/spec/to_html.dart b/pkg/analysis_server/tool/spec/to_html.dart
index 3d13b63..0bcc45e 100644
--- a/pkg/analysis_server/tool/spec/to_html.dart
+++ b/pkg/analysis_server/tool/spec/to_html.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.9
-
 /// Code for displaying the API as HTML.  This is used both for generating a
 /// full description of the API as a web page, and for generating doc comments
 /// in generated code.
@@ -177,9 +175,6 @@
       element('span', {'style': 'color:#999999'}, callback);
   void h1(void Function() callback) => element('h1', {}, callback);
   void h2(String cls, void Function() callback) {
-    if (cls == null) {
-      return element('h2', {}, callback);
-    }
     return element('h2', {'class': cls}, callback);
   }
 
@@ -193,7 +188,7 @@
   void i(void Function() callback) => element('i', {}, callback);
   void li(void Function() callback) => element('li', {}, callback);
   void link(String id, void Function() callback,
-      [Map<dynamic, String> attributes]) {
+      [Map<Object, String>? attributes]) {
     attributes ??= {};
     attributes['href'] = '#$id';
     element('a', attributes, callback);
@@ -228,7 +223,7 @@
   ///
   /// If [force] is true, then a section is inserted even if the payload is
   /// null.
-  void describePayload(TypeObject subType, String name, {bool force = false}) {
+  void describePayload(TypeObject? subType, String name, {bool force = false}) {
     if (force || subType != null) {
       h4(() {
         write(name);
@@ -300,9 +295,6 @@
   }
 
   void generateRefactoringsIndex(Iterable<Refactoring> refactorings) {
-    if (refactorings == null) {
-      return;
-    }
     h3(() {
       write('Refactorings');
       write(' (');
@@ -385,7 +377,7 @@
     });
   }
 
-  void javadocParams(TypeObject typeObject) {
+  void javadocParams(TypeObject? typeObject) {
     if (typeObject != null) {
       for (var field in typeObject.fields) {
         hangingIndent(() {
@@ -403,7 +395,8 @@
   ///
   /// If [typeForBolding] is supplied, then fields in this type are shown in
   /// boldface.
-  void showType(String shortDesc, TypeDecl type, [TypeObject typeForBolding]) {
+  void showType(String? shortDesc, TypeDecl type,
+      [TypeObject? typeForBolding]) {
     var fieldsToBold = <String>{};
     if (typeForBolding != null) {
       for (var field in typeForBolding.fields) {
@@ -423,19 +416,23 @@
 
   /// Copy the contents of the given HTML element, translating the special
   /// elements that define the API appropriately.
-  void translateHtml(dom.Element html, {bool squashParagraphs = false}) {
+  void translateHtml(dom.Element? html, {bool squashParagraphs = false}) {
+    if (html == null) {
+      return;
+    }
     for (var node in html.nodes) {
       if (node is dom.Element) {
-        if (squashParagraphs && node.localName == 'p') {
+        var localName = node.localName!;
+        if (squashParagraphs && localName == 'p') {
           translateHtml(node, squashParagraphs: squashParagraphs);
           continue;
         }
-        switch (node.localName) {
+        switch (localName) {
           case 'domains':
             generateDomainsHeader();
             break;
           case 'domain':
-            visitDomain(apiMappings.domains[node]);
+            visitDomain(apiMappings.domains[node]!);
             break;
           case 'head':
             head(() {
@@ -467,8 +464,8 @@
             generateIndex();
             break;
           default:
-            if (!ApiReader.specialElements.contains(node.localName)) {
-              element(node.localName, node.attributes, () {
+            if (!ApiReader.specialElements.contains(localName)) {
+              element(localName, node.attributes, () {
                 translateHtml(node, squashParagraphs: squashParagraphs);
               });
             }
@@ -707,15 +704,15 @@
 /// }
 class TypeVisitor extends HierarchicalApiVisitor
     with HtmlMixin, HtmlCodeGenerator {
-  /// Set of fields which should be shown in boldface, or null if no field
-  /// should be shown in boldface.
+  /// Set of fields which should be shown in boldface.
   final Set<String> fieldsToBold;
 
   /// True if a short description should be generated.  In a short description,
   /// objects are shown as simply "object", and enums are shown as "String".
   final bool short;
 
-  TypeVisitor(Api api, {this.fieldsToBold, this.short = false}) : super(api);
+  TypeVisitor(Api api, {this.fieldsToBold = const {}, this.short = false})
+      : super(api);
 
   @override
   void visitTypeEnum(TypeEnum typeEnum) {
@@ -758,7 +755,7 @@
     indent(() {
       for (var field in typeObject.fields) {
         write('"');
-        if (fieldsToBold != null && fieldsToBold.contains(field.name)) {
+        if (fieldsToBold.contains(field.name)) {
           b(() {
             write(field.name);
           });
diff --git a/tools/VERSION b/tools/VERSION
index 5e77d8c..6086192 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 200
+PRERELEASE 201
 PRERELEASE_PATCH 0
\ No newline at end of file