Version 2.18.0-261.0.dev

Merge commit '9b02bdaa76a402d839c90997acf35ea067cfece1' into 'dev'
diff --git a/DEPS b/DEPS
index c2357c9..f63331a 100644
--- a/DEPS
+++ b/DEPS
@@ -108,7 +108,7 @@
   # For more details, see https://github.com/dart-lang/sdk/issues/30164.
   "dart_style_rev": "d7b73536a8079331c888b7da539b80e6825270ea", # manually rev'd
 
-  "dartdoc_rev": "21f9341eb6623a46fc56fc3705e878371991aebb",
+  "dartdoc_rev": "61dea6b8307392ee6dfe8fd952716b07f5243b1d",
   "devtools_rev": "95d292626da26505b02417735f77e8922783b477",
   "ffi_rev": "18b2b549d55009ff594600b04705ff6161681e07",
   "file_rev": "0132eeedea2933513bf230513a766a8baeab0c4f",
diff --git a/pkg/analysis_server_client/analysis_options.yaml b/pkg/analysis_server_client/analysis_options.yaml
index e4fce7e..fd44484 100644
--- a/pkg/analysis_server_client/analysis_options.yaml
+++ b/pkg/analysis_server_client/analysis_options.yaml
@@ -1,58 +1,13 @@
-analyzer:
-  #strong-mode:
-  #  implicit-casts: false
+include: package:lints/recommended.yaml
 
 linter:
   rules:
-    - await_only_futures
-    - depend_on_referenced_packages
-    - empty_statements
-    - unnecessary_brace_in_string_interps
-    #
-    # From pedantic 1.9.0:
-    #
-    - always_declare_return_types
-    - always_require_non_null_named_parameters
-    - annotate_overrides
-    - avoid_empty_else
-    - avoid_init_to_null
-    - avoid_null_checks_in_equality_operators
-    - avoid_relative_lib_imports
-    - avoid_return_types_on_setters
-    - avoid_shadowing_type_parameters
-    - avoid_types_as_parameter_names
-    - camel_case_extensions
-    - curly_braces_in_flow_control_structures
-    - empty_catches
-    - empty_constructor_bodies
-    - library_names
-    - library_prefixes
-    - no_duplicate_case_values
-    - null_closures
-    - omit_local_variable_types
-    - prefer_adjacent_string_concatenation
-    - prefer_collection_literals
-    - prefer_conditional_assignment
-    - prefer_contains
-    - prefer_equal_for_default_values
-    - prefer_final_fields
-    - prefer_for_elements_to_map_fromIterable
-    - prefer_generic_function_type_aliases
-    - prefer_if_null_operators
-    - prefer_is_empty
-    - prefer_is_not_empty
-    - prefer_iterable_whereType
-    - prefer_single_quotes
-    - prefer_spread_collections
-    - recursive_getters
-    - slash_for_doc_comments
-    - type_init_formals
-    - unawaited_futures
-    - unnecessary_const
-    - unnecessary_new
-    - unnecessary_null_in_if_null_operators
-    - unnecessary_this
-    - unrelated_type_equality_checks
-    - use_function_type_syntax_for_parameters
-    - use_rethrow_when_possible
-    - valid_regexps
+    # In addition to lints/recommended:
+    always_declare_return_types: true
+    omit_local_variable_types: true
+    prefer_single_quotes: true
+    unawaited_futures: true
+
+    # Remove from lints/recommended:
+    constant_identifier_names: false
+    non_constant_identifier_names: false
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart
index 10de551..cd84e71 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart
@@ -37,7 +37,7 @@
       String content;
       if (json.containsKey('content')) {
         content =
-            jsonDecoder.decodeString(jsonPath + '.content', json['content']);
+            jsonDecoder.decodeString('$jsonPath.content', json['content']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'content');
       }
@@ -139,57 +139,57 @@
       AnalysisErrorSeverity severity;
       if (json.containsKey('severity')) {
         severity = AnalysisErrorSeverity.fromJson(
-            jsonDecoder, jsonPath + '.severity', json['severity']);
+            jsonDecoder, '$jsonPath.severity', json['severity']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'severity');
       }
       AnalysisErrorType type;
       if (json.containsKey('type')) {
         type = AnalysisErrorType.fromJson(
-            jsonDecoder, jsonPath + '.type', json['type']);
+            jsonDecoder, '$jsonPath.type', json['type']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'type');
       }
       Location location;
       if (json.containsKey('location')) {
         location = Location.fromJson(
-            jsonDecoder, jsonPath + '.location', json['location']);
+            jsonDecoder, '$jsonPath.location', json['location']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'location');
       }
       String message;
       if (json.containsKey('message')) {
         message =
-            jsonDecoder.decodeString(jsonPath + '.message', json['message']);
+            jsonDecoder.decodeString('$jsonPath.message', json['message']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'message');
       }
       String? correction;
       if (json.containsKey('correction')) {
         correction = jsonDecoder.decodeString(
-            jsonPath + '.correction', json['correction']);
+            '$jsonPath.correction', json['correction']);
       }
       String code;
       if (json.containsKey('code')) {
-        code = jsonDecoder.decodeString(jsonPath + '.code', json['code']);
+        code = jsonDecoder.decodeString('$jsonPath.code', json['code']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'code');
       }
       String? url;
       if (json.containsKey('url')) {
-        url = jsonDecoder.decodeString(jsonPath + '.url', json['url']);
+        url = jsonDecoder.decodeString('$jsonPath.url', json['url']);
       }
       List<DiagnosticMessage>? contextMessages;
       if (json.containsKey('contextMessages')) {
         contextMessages = jsonDecoder.decodeList(
-            jsonPath + '.contextMessages',
+            '$jsonPath.contextMessages',
             json['contextMessages'],
             (String jsonPath, Object? json) =>
                 DiagnosticMessage.fromJson(jsonDecoder, jsonPath, json));
       }
       bool? hasFix;
       if (json.containsKey('hasFix')) {
-        hasFix = jsonDecoder.decodeBool(jsonPath + '.hasFix', json['hasFix']);
+        hasFix = jsonDecoder.decodeBool('$jsonPath.hasFix', json['hasFix']);
       }
       return AnalysisError(severity, type, location, message, code,
           correction: correction,
@@ -440,7 +440,7 @@
       List<SourceEdit> edits;
       if (json.containsKey('edits')) {
         edits = jsonDecoder.decodeList(
-            jsonPath + '.edits',
+            '$jsonPath.edits',
             json['edits'],
             (String jsonPath, Object? json) =>
                 SourceEdit.fromJson(jsonDecoder, jsonPath, json));
@@ -673,145 +673,144 @@
       CompletionSuggestionKind kind;
       if (json.containsKey('kind')) {
         kind = CompletionSuggestionKind.fromJson(
-            jsonDecoder, jsonPath + '.kind', json['kind']);
+            jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
       int relevance;
       if (json.containsKey('relevance')) {
         relevance =
-            jsonDecoder.decodeInt(jsonPath + '.relevance', json['relevance']);
+            jsonDecoder.decodeInt('$jsonPath.relevance', json['relevance']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'relevance');
       }
       String completion;
       if (json.containsKey('completion')) {
         completion = jsonDecoder.decodeString(
-            jsonPath + '.completion', json['completion']);
+            '$jsonPath.completion', json['completion']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'completion');
       }
       String? displayText;
       if (json.containsKey('displayText')) {
         displayText = jsonDecoder.decodeString(
-            jsonPath + '.displayText', json['displayText']);
+            '$jsonPath.displayText', json['displayText']);
       }
       int? replacementOffset;
       if (json.containsKey('replacementOffset')) {
         replacementOffset = jsonDecoder.decodeInt(
-            jsonPath + '.replacementOffset', json['replacementOffset']);
+            '$jsonPath.replacementOffset', json['replacementOffset']);
       }
       int? replacementLength;
       if (json.containsKey('replacementLength')) {
         replacementLength = jsonDecoder.decodeInt(
-            jsonPath + '.replacementLength', json['replacementLength']);
+            '$jsonPath.replacementLength', json['replacementLength']);
       }
       int selectionOffset;
       if (json.containsKey('selectionOffset')) {
         selectionOffset = jsonDecoder.decodeInt(
-            jsonPath + '.selectionOffset', json['selectionOffset']);
+            '$jsonPath.selectionOffset', json['selectionOffset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'selectionOffset');
       }
       int selectionLength;
       if (json.containsKey('selectionLength')) {
         selectionLength = jsonDecoder.decodeInt(
-            jsonPath + '.selectionLength', json['selectionLength']);
+            '$jsonPath.selectionLength', json['selectionLength']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'selectionLength');
       }
       bool isDeprecated;
       if (json.containsKey('isDeprecated')) {
         isDeprecated = jsonDecoder.decodeBool(
-            jsonPath + '.isDeprecated', json['isDeprecated']);
+            '$jsonPath.isDeprecated', json['isDeprecated']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'isDeprecated');
       }
       bool isPotential;
       if (json.containsKey('isPotential')) {
         isPotential = jsonDecoder.decodeBool(
-            jsonPath + '.isPotential', json['isPotential']);
+            '$jsonPath.isPotential', json['isPotential']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'isPotential');
       }
       String? docSummary;
       if (json.containsKey('docSummary')) {
         docSummary = jsonDecoder.decodeString(
-            jsonPath + '.docSummary', json['docSummary']);
+            '$jsonPath.docSummary', json['docSummary']);
       }
       String? docComplete;
       if (json.containsKey('docComplete')) {
         docComplete = jsonDecoder.decodeString(
-            jsonPath + '.docComplete', json['docComplete']);
+            '$jsonPath.docComplete', json['docComplete']);
       }
       String? declaringType;
       if (json.containsKey('declaringType')) {
         declaringType = jsonDecoder.decodeString(
-            jsonPath + '.declaringType', json['declaringType']);
+            '$jsonPath.declaringType', json['declaringType']);
       }
       String? defaultArgumentListString;
       if (json.containsKey('defaultArgumentListString')) {
         defaultArgumentListString = jsonDecoder.decodeString(
-            jsonPath + '.defaultArgumentListString',
+            '$jsonPath.defaultArgumentListString',
             json['defaultArgumentListString']);
       }
       List<int>? defaultArgumentListTextRanges;
       if (json.containsKey('defaultArgumentListTextRanges')) {
         defaultArgumentListTextRanges = jsonDecoder.decodeList(
-            jsonPath + '.defaultArgumentListTextRanges',
+            '$jsonPath.defaultArgumentListTextRanges',
             json['defaultArgumentListTextRanges'],
             jsonDecoder.decodeInt);
       }
       Element? element;
       if (json.containsKey('element')) {
-        element = Element.fromJson(
-            jsonDecoder, jsonPath + '.element', json['element']);
+        element =
+            Element.fromJson(jsonDecoder, '$jsonPath.element', json['element']);
       }
       String? returnType;
       if (json.containsKey('returnType')) {
         returnType = jsonDecoder.decodeString(
-            jsonPath + '.returnType', json['returnType']);
+            '$jsonPath.returnType', json['returnType']);
       }
       List<String>? parameterNames;
       if (json.containsKey('parameterNames')) {
-        parameterNames = jsonDecoder.decodeList(jsonPath + '.parameterNames',
+        parameterNames = jsonDecoder.decodeList('$jsonPath.parameterNames',
             json['parameterNames'], jsonDecoder.decodeString);
       }
       List<String>? parameterTypes;
       if (json.containsKey('parameterTypes')) {
-        parameterTypes = jsonDecoder.decodeList(jsonPath + '.parameterTypes',
+        parameterTypes = jsonDecoder.decodeList('$jsonPath.parameterTypes',
             json['parameterTypes'], jsonDecoder.decodeString);
       }
       int? requiredParameterCount;
       if (json.containsKey('requiredParameterCount')) {
         requiredParameterCount = jsonDecoder.decodeInt(
-            jsonPath + '.requiredParameterCount',
-            json['requiredParameterCount']);
+            '$jsonPath.requiredParameterCount', json['requiredParameterCount']);
       }
       bool? hasNamedParameters;
       if (json.containsKey('hasNamedParameters')) {
         hasNamedParameters = jsonDecoder.decodeBool(
-            jsonPath + '.hasNamedParameters', json['hasNamedParameters']);
+            '$jsonPath.hasNamedParameters', json['hasNamedParameters']);
       }
       String? parameterName;
       if (json.containsKey('parameterName')) {
         parameterName = jsonDecoder.decodeString(
-            jsonPath + '.parameterName', json['parameterName']);
+            '$jsonPath.parameterName', json['parameterName']);
       }
       String? parameterType;
       if (json.containsKey('parameterType')) {
         parameterType = jsonDecoder.decodeString(
-            jsonPath + '.parameterType', json['parameterType']);
+            '$jsonPath.parameterType', json['parameterType']);
       }
       String? libraryUri;
       if (json.containsKey('libraryUri')) {
         libraryUri = jsonDecoder.decodeString(
-            jsonPath + '.libraryUri', json['libraryUri']);
+            '$jsonPath.libraryUri', json['libraryUri']);
       }
       bool? isNotImported;
       if (json.containsKey('isNotImported')) {
         isNotImported = jsonDecoder.decodeBool(
-            jsonPath + '.isNotImported', json['isNotImported']);
+            '$jsonPath.isNotImported', json['isNotImported']);
       }
       return CompletionSuggestion(kind, relevance, completion, selectionOffset,
           selectionLength, isDeprecated, isPotential,
@@ -1146,14 +1145,14 @@
       String message;
       if (json.containsKey('message')) {
         message =
-            jsonDecoder.decodeString(jsonPath + '.message', json['message']);
+            jsonDecoder.decodeString('$jsonPath.message', json['message']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'message');
       }
       Location location;
       if (json.containsKey('location')) {
         location = Location.fromJson(
-            jsonDecoder, jsonPath + '.location', json['location']);
+            jsonDecoder, '$jsonPath.location', json['location']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'location');
       }
@@ -1282,46 +1281,46 @@
       ElementKind kind;
       if (json.containsKey('kind')) {
         kind =
-            ElementKind.fromJson(jsonDecoder, jsonPath + '.kind', json['kind']);
+            ElementKind.fromJson(jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
       String name;
       if (json.containsKey('name')) {
-        name = jsonDecoder.decodeString(jsonPath + '.name', json['name']);
+        name = jsonDecoder.decodeString('$jsonPath.name', json['name']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'name');
       }
       Location? location;
       if (json.containsKey('location')) {
         location = Location.fromJson(
-            jsonDecoder, jsonPath + '.location', json['location']);
+            jsonDecoder, '$jsonPath.location', json['location']);
       }
       int flags;
       if (json.containsKey('flags')) {
-        flags = jsonDecoder.decodeInt(jsonPath + '.flags', json['flags']);
+        flags = jsonDecoder.decodeInt('$jsonPath.flags', json['flags']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'flags');
       }
       String? parameters;
       if (json.containsKey('parameters')) {
         parameters = jsonDecoder.decodeString(
-            jsonPath + '.parameters', json['parameters']);
+            '$jsonPath.parameters', json['parameters']);
       }
       String? returnType;
       if (json.containsKey('returnType')) {
         returnType = jsonDecoder.decodeString(
-            jsonPath + '.returnType', json['returnType']);
+            '$jsonPath.returnType', json['returnType']);
       }
       String? typeParameters;
       if (json.containsKey('typeParameters')) {
         typeParameters = jsonDecoder.decodeString(
-            jsonPath + '.typeParameters', json['typeParameters']);
+            '$jsonPath.typeParameters', json['typeParameters']);
       }
       String? aliasedType;
       if (json.containsKey('aliasedType')) {
         aliasedType = jsonDecoder.decodeString(
-            jsonPath + '.aliasedType', json['aliasedType']);
+            '$jsonPath.aliasedType', json['aliasedType']);
       }
       return Element(kind, name, flags,
           location: location,
@@ -1748,19 +1747,19 @@
       FoldingKind kind;
       if (json.containsKey('kind')) {
         kind =
-            FoldingKind.fromJson(jsonDecoder, jsonPath + '.kind', json['kind']);
+            FoldingKind.fromJson(jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
@@ -1828,19 +1827,19 @@
       HighlightRegionType type;
       if (json.containsKey('type')) {
         type = HighlightRegionType.fromJson(
-            jsonDecoder, jsonPath + '.type', json['type']);
+            jsonDecoder, '$jsonPath.type', json['type']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'type');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
@@ -2522,29 +2521,29 @@
       KytheVName source;
       if (json.containsKey('source')) {
         source = KytheVName.fromJson(
-            jsonDecoder, jsonPath + '.source', json['source']);
+            jsonDecoder, '$jsonPath.source', json['source']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'source');
       }
       String? kind;
       if (json.containsKey('kind')) {
-        kind = jsonDecoder.decodeString(jsonPath + '.kind', json['kind']);
+        kind = jsonDecoder.decodeString('$jsonPath.kind', json['kind']);
       }
       KytheVName? target;
       if (json.containsKey('target')) {
         target = KytheVName.fromJson(
-            jsonDecoder, jsonPath + '.target', json['target']);
+            jsonDecoder, '$jsonPath.target', json['target']);
       }
       String fact;
       if (json.containsKey('fact')) {
-        fact = jsonDecoder.decodeString(jsonPath + '.fact', json['fact']);
+        fact = jsonDecoder.decodeString('$jsonPath.fact', json['fact']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'fact');
       }
       List<int>? value;
       if (json.containsKey('value')) {
         value = jsonDecoder.decodeList(
-            jsonPath + '.value', json['value'], jsonDecoder.decodeInt);
+            '$jsonPath.value', json['value'], jsonDecoder.decodeInt);
       }
       return KytheEntry(source, fact, kind: kind, target: target, value: value);
     } else {
@@ -2637,33 +2636,33 @@
     if (json is Map) {
       String signature;
       if (json.containsKey('signature')) {
-        signature = jsonDecoder.decodeString(
-            jsonPath + '.signature', json['signature']);
+        signature =
+            jsonDecoder.decodeString('$jsonPath.signature', json['signature']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'signature');
       }
       String corpus;
       if (json.containsKey('corpus')) {
-        corpus = jsonDecoder.decodeString(jsonPath + '.corpus', json['corpus']);
+        corpus = jsonDecoder.decodeString('$jsonPath.corpus', json['corpus']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'corpus');
       }
       String root;
       if (json.containsKey('root')) {
-        root = jsonDecoder.decodeString(jsonPath + '.root', json['root']);
+        root = jsonDecoder.decodeString('$jsonPath.root', json['root']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'root');
       }
       String path;
       if (json.containsKey('path')) {
-        path = jsonDecoder.decodeString(jsonPath + '.path', json['path']);
+        path = jsonDecoder.decodeString('$jsonPath.path', json['path']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'path');
       }
       String language;
       if (json.containsKey('language')) {
         language =
-            jsonDecoder.decodeString(jsonPath + '.language', json['language']);
+            jsonDecoder.decodeString('$jsonPath.language', json['language']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'language');
       }
@@ -2739,7 +2738,7 @@
       List<Position> positions;
       if (json.containsKey('positions')) {
         positions = jsonDecoder.decodeList(
-            jsonPath + '.positions',
+            '$jsonPath.positions',
             json['positions'],
             (String jsonPath, Object? json) =>
                 Position.fromJson(jsonDecoder, jsonPath, json));
@@ -2748,14 +2747,14 @@
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       List<LinkedEditSuggestion> suggestions;
       if (json.containsKey('suggestions')) {
         suggestions = jsonDecoder.decodeList(
-            jsonPath + '.suggestions',
+            '$jsonPath.suggestions',
             json['suggestions'],
             (String jsonPath, Object? json) =>
                 LinkedEditSuggestion.fromJson(jsonDecoder, jsonPath, json));
@@ -2840,14 +2839,14 @@
     if (json is Map) {
       String value;
       if (json.containsKey('value')) {
-        value = jsonDecoder.decodeString(jsonPath + '.value', json['value']);
+        value = jsonDecoder.decodeString('$jsonPath.value', json['value']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'value');
       }
       LinkedEditSuggestionKind kind;
       if (json.containsKey('kind')) {
         kind = LinkedEditSuggestionKind.fromJson(
-            jsonDecoder, jsonPath + '.kind', json['kind']);
+            jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
@@ -2996,44 +2995,44 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       int startLine;
       if (json.containsKey('startLine')) {
         startLine =
-            jsonDecoder.decodeInt(jsonPath + '.startLine', json['startLine']);
+            jsonDecoder.decodeInt('$jsonPath.startLine', json['startLine']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'startLine');
       }
       int startColumn;
       if (json.containsKey('startColumn')) {
-        startColumn = jsonDecoder.decodeInt(
-            jsonPath + '.startColumn', json['startColumn']);
+        startColumn =
+            jsonDecoder.decodeInt('$jsonPath.startColumn', json['startColumn']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'startColumn');
       }
       int? endLine;
       if (json.containsKey('endLine')) {
-        endLine = jsonDecoder.decodeInt(jsonPath + '.endLine', json['endLine']);
+        endLine = jsonDecoder.decodeInt('$jsonPath.endLine', json['endLine']);
       }
       int? endColumn;
       if (json.containsKey('endColumn')) {
         endColumn =
-            jsonDecoder.decodeInt(jsonPath + '.endColumn', json['endColumn']);
+            jsonDecoder.decodeInt('$jsonPath.endColumn', json['endColumn']);
       }
       return Location(file, offset, length, startLine, startColumn,
           endLine: endLine, endColumn: endColumn);
@@ -3119,20 +3118,20 @@
     if (json is Map) {
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       List<int> targets;
       if (json.containsKey('targets')) {
         targets = jsonDecoder.decodeList(
-            jsonPath + '.targets', json['targets'], jsonDecoder.decodeInt);
+            '$jsonPath.targets', json['targets'], jsonDecoder.decodeInt);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'targets');
       }
@@ -3225,52 +3224,52 @@
       ElementKind kind;
       if (json.containsKey('kind')) {
         kind =
-            ElementKind.fromJson(jsonDecoder, jsonPath + '.kind', json['kind']);
+            ElementKind.fromJson(jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
       int fileIndex;
       if (json.containsKey('fileIndex')) {
         fileIndex =
-            jsonDecoder.decodeInt(jsonPath + '.fileIndex', json['fileIndex']);
+            jsonDecoder.decodeInt('$jsonPath.fileIndex', json['fileIndex']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'fileIndex');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       int startLine;
       if (json.containsKey('startLine')) {
         startLine =
-            jsonDecoder.decodeInt(jsonPath + '.startLine', json['startLine']);
+            jsonDecoder.decodeInt('$jsonPath.startLine', json['startLine']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'startLine');
       }
       int startColumn;
       if (json.containsKey('startColumn')) {
-        startColumn = jsonDecoder.decodeInt(
-            jsonPath + '.startColumn', json['startColumn']);
+        startColumn =
+            jsonDecoder.decodeInt('$jsonPath.startColumn', json['startColumn']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'startColumn');
       }
       int? codeOffset;
       if (json.containsKey('codeOffset')) {
         codeOffset =
-            jsonDecoder.decodeInt(jsonPath + '.codeOffset', json['codeOffset']);
+            jsonDecoder.decodeInt('$jsonPath.codeOffset', json['codeOffset']);
       }
       int? codeLength;
       if (json.containsKey('codeLength')) {
         codeLength =
-            jsonDecoder.decodeInt(jsonPath + '.codeLength', json['codeLength']);
+            jsonDecoder.decodeInt('$jsonPath.codeLength', json['codeLength']);
       }
       return NavigationTarget(
           kind, fileIndex, offset, length, startLine, startColumn,
@@ -3358,21 +3357,21 @@
     if (json is Map) {
       Element element;
       if (json.containsKey('element')) {
-        element = Element.fromJson(
-            jsonDecoder, jsonPath + '.element', json['element']);
+        element =
+            Element.fromJson(jsonDecoder, '$jsonPath.element', json['element']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'element');
       }
       List<int> offsets;
       if (json.containsKey('offsets')) {
         offsets = jsonDecoder.decodeList(
-            jsonPath + '.offsets', json['offsets'], jsonDecoder.decodeInt);
+            '$jsonPath.offsets', json['offsets'], jsonDecoder.decodeInt);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offsets');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
@@ -3458,41 +3457,41 @@
     if (json is Map) {
       Element element;
       if (json.containsKey('element')) {
-        element = Element.fromJson(
-            jsonDecoder, jsonPath + '.element', json['element']);
+        element =
+            Element.fromJson(jsonDecoder, '$jsonPath.element', json['element']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'element');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       int codeOffset;
       if (json.containsKey('codeOffset')) {
         codeOffset =
-            jsonDecoder.decodeInt(jsonPath + '.codeOffset', json['codeOffset']);
+            jsonDecoder.decodeInt('$jsonPath.codeOffset', json['codeOffset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'codeOffset');
       }
       int codeLength;
       if (json.containsKey('codeLength')) {
         codeLength =
-            jsonDecoder.decodeInt(jsonPath + '.codeLength', json['codeLength']);
+            jsonDecoder.decodeInt('$jsonPath.codeLength', json['codeLength']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'codeLength');
       }
       List<Outline>? children;
       if (json.containsKey('children')) {
         children = jsonDecoder.decodeList(
-            jsonPath + '.children',
+            '$jsonPath.children',
             json['children'],
             (String jsonPath, Object? json) =>
                 Outline.fromJson(jsonDecoder, jsonPath, json));
@@ -3579,27 +3578,27 @@
     if (json is Map) {
       ParameterKind kind;
       if (json.containsKey('kind')) {
-        kind = ParameterKind.fromJson(
-            jsonDecoder, jsonPath + '.kind', json['kind']);
+        kind =
+            ParameterKind.fromJson(jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
       String name;
       if (json.containsKey('name')) {
-        name = jsonDecoder.decodeString(jsonPath + '.name', json['name']);
+        name = jsonDecoder.decodeString('$jsonPath.name', json['name']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'name');
       }
       String type;
       if (json.containsKey('type')) {
-        type = jsonDecoder.decodeString(jsonPath + '.type', json['type']);
+        type = jsonDecoder.decodeString('$jsonPath.type', json['type']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'type');
       }
       String? defaultValue;
       if (json.containsKey('defaultValue')) {
         defaultValue = jsonDecoder.decodeString(
-            jsonPath + '.defaultValue', json['defaultValue']);
+            '$jsonPath.defaultValue', json['defaultValue']);
       }
       return ParameterInfo(kind, name, type, defaultValue: defaultValue);
     } else {
@@ -3736,13 +3735,13 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
@@ -3919,31 +3918,31 @@
     if (json is Map) {
       String? id;
       if (json.containsKey('id')) {
-        id = jsonDecoder.decodeString(jsonPath + '.id', json['id']);
+        id = jsonDecoder.decodeString('$jsonPath.id', json['id']);
       }
       RefactoringMethodParameterKind kind;
       if (json.containsKey('kind')) {
         kind = RefactoringMethodParameterKind.fromJson(
-            jsonDecoder, jsonPath + '.kind', json['kind']);
+            jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
       String type;
       if (json.containsKey('type')) {
-        type = jsonDecoder.decodeString(jsonPath + '.type', json['type']);
+        type = jsonDecoder.decodeString('$jsonPath.type', json['type']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'type');
       }
       String name;
       if (json.containsKey('name')) {
-        name = jsonDecoder.decodeString(jsonPath + '.name', json['name']);
+        name = jsonDecoder.decodeString('$jsonPath.name', json['name']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'name');
       }
       String? parameters;
       if (json.containsKey('parameters')) {
         parameters = jsonDecoder.decodeString(
-            jsonPath + '.parameters', json['parameters']);
+            '$jsonPath.parameters', json['parameters']);
       }
       return RefactoringMethodParameter(kind, type, name,
           id: id, parameters: parameters);
@@ -4083,21 +4082,21 @@
       RefactoringProblemSeverity severity;
       if (json.containsKey('severity')) {
         severity = RefactoringProblemSeverity.fromJson(
-            jsonDecoder, jsonPath + '.severity', json['severity']);
+            jsonDecoder, '$jsonPath.severity', json['severity']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'severity');
       }
       String message;
       if (json.containsKey('message')) {
         message =
-            jsonDecoder.decodeString(jsonPath + '.message', json['message']);
+            jsonDecoder.decodeString('$jsonPath.message', json['message']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'message');
       }
       Location? location;
       if (json.containsKey('location')) {
         location = Location.fromJson(
-            jsonDecoder, jsonPath + '.location', json['location']);
+            jsonDecoder, '$jsonPath.location', json['location']);
       }
       return RefactoringProblem(severity, message, location: location);
     } else {
@@ -4319,14 +4318,14 @@
       String message;
       if (json.containsKey('message')) {
         message =
-            jsonDecoder.decodeString(jsonPath + '.message', json['message']);
+            jsonDecoder.decodeString('$jsonPath.message', json['message']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'message');
       }
       List<SourceFileEdit> edits;
       if (json.containsKey('edits')) {
         edits = jsonDecoder.decodeList(
-            jsonPath + '.edits',
+            '$jsonPath.edits',
             json['edits'],
             (String jsonPath, Object? json) =>
                 SourceFileEdit.fromJson(jsonDecoder, jsonPath, json));
@@ -4336,7 +4335,7 @@
       List<LinkedEditGroup> linkedEditGroups;
       if (json.containsKey('linkedEditGroups')) {
         linkedEditGroups = jsonDecoder.decodeList(
-            jsonPath + '.linkedEditGroups',
+            '$jsonPath.linkedEditGroups',
             json['linkedEditGroups'],
             (String jsonPath, Object? json) =>
                 LinkedEditGroup.fromJson(jsonDecoder, jsonPath, json));
@@ -4346,16 +4345,16 @@
       Position? selection;
       if (json.containsKey('selection')) {
         selection = Position.fromJson(
-            jsonDecoder, jsonPath + '.selection', json['selection']);
+            jsonDecoder, '$jsonPath.selection', json['selection']);
       }
       int? selectionLength;
       if (json.containsKey('selectionLength')) {
         selectionLength = jsonDecoder.decodeInt(
-            jsonPath + '.selectionLength', json['selectionLength']);
+            '$jsonPath.selectionLength', json['selectionLength']);
       }
       String? id;
       if (json.containsKey('id')) {
-        id = jsonDecoder.decodeString(jsonPath + '.id', json['id']);
+        id = jsonDecoder.decodeString('$jsonPath.id', json['id']);
       }
       return SourceChange(message,
           edits: edits,
@@ -4487,26 +4486,26 @@
     if (json is Map) {
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       String replacement;
       if (json.containsKey('replacement')) {
         replacement = jsonDecoder.decodeString(
-            jsonPath + '.replacement', json['replacement']);
+            '$jsonPath.replacement', json['replacement']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'replacement');
       }
       String? id;
       if (json.containsKey('id')) {
-        id = jsonDecoder.decodeString(jsonPath + '.id', json['id']);
+        id = jsonDecoder.decodeString('$jsonPath.id', json['id']);
       }
       return SourceEdit(offset, length, replacement, id: id);
     } else {
@@ -4588,21 +4587,21 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       int fileStamp;
       if (json.containsKey('fileStamp')) {
         fileStamp =
-            jsonDecoder.decodeInt(jsonPath + '.fileStamp', json['fileStamp']);
+            jsonDecoder.decodeInt('$jsonPath.fileStamp', json['fileStamp']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'fileStamp');
       }
       List<SourceEdit> edits;
       if (json.containsKey('edits')) {
         edits = jsonDecoder.decodeList(
-            jsonPath + '.edits',
+            '$jsonPath.edits',
             json['edits'],
             (String jsonPath, Object? json) =>
                 SourceEdit.fromJson(jsonDecoder, jsonPath, json));
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_internal.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_internal.dart
index 431cca2..edcf693 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_internal.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_internal.dart
@@ -20,8 +20,9 @@
 void addAllEditsForSource(
     SourceFileEdit sourceFileEdit, Iterable<SourceEdit> edits,
     {bool insertBeforeExisting = false}) {
-  edits.forEach((edit) =>
-      sourceFileEdit.add(edit, insertBeforeExisting: insertBeforeExisting));
+  for (var edit in edits) {
+    sourceFileEdit.add(edit, insertBeforeExisting: insertBeforeExisting);
+  }
 }
 
 /// Adds the given [sourceEdit] to the list in [sourceFileEdit].
@@ -76,9 +77,9 @@
 /// are applied in the order they appear in [edits]. Access via
 /// SourceEdit.applySequence().
 String applySequenceOfEdits(String code, Iterable<SourceEdit> edits) {
-  edits.forEach((SourceEdit edit) {
+  for (var edit in edits) {
     code = edit.apply(code);
-  });
+  }
   return code;
 }
 
diff --git a/pkg/analysis_server_client/pubspec.yaml b/pkg/analysis_server_client/pubspec.yaml
index a5438e9..293e5fb 100644
--- a/pkg/analysis_server_client/pubspec.yaml
+++ b/pkg/analysis_server_client/pubspec.yaml
@@ -21,4 +21,5 @@
   analyzer: any
   analysis_server: any
   analyzer_utilities: any
+  lints: any
   test: any
diff --git a/pkg/analyzer_cli/CHANGELOG.md b/pkg/analyzer_cli/CHANGELOG.md
deleted file mode 100644
index c4298d7..0000000
--- a/pkg/analyzer_cli/CHANGELOG.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Changelog
-
-## 1.1.1
-
-- Removed outmoded `--url-mapping` command line option.
-
-## 1.1.0
-
-- New `--lints` command line option.
-
-## 0.0.
-
-
-## 0.0.1
-
-- Initial version
diff --git a/pkg/analyzer_cli/README.md b/pkg/analyzer_cli/README.md
index a06b656..5eea2c3 100644
--- a/pkg/analyzer_cli/README.md
+++ b/pkg/analyzer_cli/README.md
@@ -1,79 +1,27 @@
 # dartanalyzer
 
-Use _dartanalyzer_ to statically analyze your code at the command line,
-checking for errors and warnings that are specified in the
-[Dart Language Specification](https://dart.dev/guides/language/spec).
-DartPad, code editors, and IDEs such as Android Studio and VS Code
-use the same analysis engine that dartanalyzer uses.
+_dartanalyzer_ used to be the tool for statically analyzing dart code
+at the command line.  However, this tool has been replaced with
+`dart analyze` for this purpose in current SDKs and will no longer
+be published on pub.
+
+Do not depend on the command line interface or other semantics in
+this directory as it is now an internal tool for SDK development, used
+as the `dart2analyzer` "compiler" for `tools/test.py` in the SDK.
+It is configured as part of the test runner,
+[here](https://github.com/dart-lang/sdk/blob/main/pkg/test_runner/lib/src/compiler_configuration.dart).
 
 ## Basic usage
 
-Run the analyzer from the top directory of the package.
-Here's an example of analyzing a Dart file.
+Run `dartanalyzer` from the test tool to validate analysis
+conclusions on language samples in the testing directory.
+From the root of the SDK:
 
 ```
-dartanalyzer bin/test.dart
+tools/test.py --build --use-sdk -c dart2analyzer co19_2 language_2
 ```
 
-## Options
-
-The following are the most commonly used options for dartanalyzer:
-
-* `--packages=`
-
-  Specify the path to the package resolution configuration file.
-  For more information see
-  [Package Resolution Configuration File](https://github.com/lrhn/dep-pkgspec/blob/master/DEP-pkgspec.md).
-
-* `--package-warnings`
-
-  Show warnings not only for code in the specified .dart file and
-  others in its library, but also for libraries imported with `package:`.
-
-* `--options=`
-
-  Specify the path to an analysis options file.
-
-* `--[no-]lints`
-
-  Show the results from the linter.
-
-* `--[no-]hints`
-
-  Don't show hints for improving the code.
-
-* `--version`
-
-  Show the analyzer version.
-
-* `-h` _or_ `--help`
-
-  Show all of the command-line options.
-
-See the[Customizing static analysis
-guide](https://dart.dev/guides/language/analysis-options) for further ways to
-customize how dartanalyzer performs static analysis, and how it reports its
-findings.
-
-The following are advanced options to use with dartanalyzer:
-
-* `--dart-sdk=`
-
-  Specify the directory that contains the Dart SDK.
-
-* `--fatal-warnings`
-
-  Except for type warnings, treat warnings as fatal.
-
-* `--format=machine`
-
-  Produce output in a format suitable for parsing.
-
-* `--ignore-unrecognized-flags`
-
-  Rather than printing the help message, ignore any unrecognized command-line
-  flags.
-
-* `--url-mapping=libraryUri,/path/to/library.dart`
-
-  Use the specified library as the source for that particular import.
+This will build the Dart VM and compile dartanalyzer into a snapshot, then use
+that snapshot while analyzing those directories under `testing/`.  Without
+`--use-sdk`, test.py will use the source code version of `dartanalyzer`
+instead of the compiled one, which can be useful for debugging.
diff --git a/pkg/analyzer_cli/lib/src/error_severity.dart b/pkg/analyzer_cli/lib/src/error_severity.dart
index 23bfe3e..f51f574 100644
--- a/pkg/analyzer_cli/lib/src/error_severity.dart
+++ b/pkg/analyzer_cli/lib/src/error_severity.dart
@@ -4,7 +4,6 @@
 
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/source/error_processor.dart';
-import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer_cli/src/options.dart';
 
@@ -23,10 +22,6 @@
     return processor.severity;
   }
 
-  if (commandLineOptions.lintsAreFatal && error.errorCode is LintCode) {
-    return ErrorSeverity.ERROR;
-  }
-
   return error.errorCode.errorSeverity;
 }
 
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
index a7278e1..23a11be 100644
--- a/pkg/analyzer_cli/lib/src/options.dart
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -116,10 +116,6 @@
   /// Whether to treat info level items as fatal
   final bool infosAreFatal;
 
-  /// Whether to treat lints as fatal
-  // TODO(devoncarew): Deprecate and remove this flag.
-  final bool lintsAreFatal;
-
   /// Emit output in a verbose mode.
   final bool verbose;
 
@@ -154,7 +150,6 @@
         sourceFiles = args.rest,
         infosAreFatal = cast(args['fatal-infos']) || cast(args['fatal-hints']),
         warningsAreFatal = cast(args['fatal-warnings']),
-        lintsAreFatal = cast(args['fatal-lints']),
         trainSnapshot = cast(args['train-snapshot']),
         verbose = cast(args['verbose']),
         color = cast(args['color']) {
diff --git a/pkg/analyzer_cli/test/options_test.dart b/pkg/analyzer_cli/test/options_test.dart
index 1c151dd..690b5c9 100644
--- a/pkg/analyzer_cli/test/options_test.dart
+++ b/pkg/analyzer_cli/test/options_test.dart
@@ -73,7 +73,6 @@
         expect(options.showSdkWarnings, isFalse);
         expect(options.sourceFiles, equals(['foo.dart']));
         expect(options.warningsAreFatal, isFalse);
-        expect(options.lintsAreFatal, isFalse);
         expect(options.trainSnapshot, isFalse);
       });
 
@@ -262,11 +261,6 @@
         expect(options.sourceFiles, equals(['foo.dart']));
       });
 
-      test('hintsAreFatal', () {
-        var options = parse(['--dart-sdk', '.', '--fatal-lints', 'foo.dart'])!;
-        expect(options.lintsAreFatal, isTrue);
-      });
-
       test('bad SDK dir', () {
         String? failureMessage;
         parse(['--dart-sdk', '&&&&&', 'foo.dart'],
diff --git a/pkg/analyzer_plugin/analysis_options.yaml b/pkg/analyzer_plugin/analysis_options.yaml
index a8cb96f..e58f0a5 100644
--- a/pkg/analyzer_plugin/analysis_options.yaml
+++ b/pkg/analyzer_plugin/analysis_options.yaml
@@ -1,57 +1,23 @@
+include: package:lints/recommended.yaml
+
 analyzer:
   language:
     strict-casts: true
+
 linter:
   rules:
-    - await_only_futures
-    - depend_on_referenced_packages
-    - empty_statements
-    - unnecessary_brace_in_string_interps
-    #
-    # From pedantic 1.9.0:
-    #
-    - always_declare_return_types
-    - always_require_non_null_named_parameters
-    - annotate_overrides
-    - avoid_empty_else
-    - avoid_init_to_null
-    - avoid_null_checks_in_equality_operators
-    - avoid_relative_lib_imports
-    - avoid_return_types_on_setters
-    - avoid_shadowing_type_parameters
-    - avoid_types_as_parameter_names
-    - camel_case_extensions
-    - curly_braces_in_flow_control_structures
-    - empty_catches
-    - empty_constructor_bodies
-    - library_names
-    - library_prefixes
-    - no_duplicate_case_values
-    - null_closures
-    - omit_local_variable_types
-    - prefer_adjacent_string_concatenation
-    - prefer_collection_literals
-    - prefer_conditional_assignment
-    - prefer_contains
-    - prefer_equal_for_default_values
-    - prefer_final_fields
-    - prefer_for_elements_to_map_fromIterable
-    - prefer_generic_function_type_aliases
-    - prefer_if_null_operators
-    - prefer_is_empty
-    - prefer_is_not_empty
-    - prefer_iterable_whereType
-    - prefer_single_quotes
-    - prefer_spread_collections
-    - recursive_getters
-    - slash_for_doc_comments
-    - type_init_formals
-    - unawaited_futures
-    - unnecessary_const
-    - unnecessary_new
-    - unnecessary_null_in_if_null_operators
-    - unnecessary_this
-    - unrelated_type_equality_checks
-    - use_function_type_syntax_for_parameters
-    - use_rethrow_when_possible
-    - valid_regexps
+    # In addition to lints/recommended:
+    always_declare_return_types: true
+    omit_local_variable_types: true
+    prefer_single_quotes: true
+    unawaited_futures: true
+
+    # Remove from lints/recommended:
+    constant_identifier_names: false
+    implementation_imports: false
+    non_constant_identifier_names: false
+
+    # Existing violations (3)
+    library_private_types_in_public_api: false
+    # Existing violations (3)
+    prefer_initializing_formals: false
diff --git a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
index 6f3ab9e..925dfa3 100644
--- a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
+++ b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
@@ -37,7 +37,7 @@
       String content;
       if (json.containsKey('content')) {
         content =
-            jsonDecoder.decodeString(jsonPath + '.content', json['content']);
+            jsonDecoder.decodeString('$jsonPath.content', json['content']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'content');
       }
@@ -139,57 +139,57 @@
       AnalysisErrorSeverity severity;
       if (json.containsKey('severity')) {
         severity = AnalysisErrorSeverity.fromJson(
-            jsonDecoder, jsonPath + '.severity', json['severity']);
+            jsonDecoder, '$jsonPath.severity', json['severity']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'severity');
       }
       AnalysisErrorType type;
       if (json.containsKey('type')) {
         type = AnalysisErrorType.fromJson(
-            jsonDecoder, jsonPath + '.type', json['type']);
+            jsonDecoder, '$jsonPath.type', json['type']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'type');
       }
       Location location;
       if (json.containsKey('location')) {
         location = Location.fromJson(
-            jsonDecoder, jsonPath + '.location', json['location']);
+            jsonDecoder, '$jsonPath.location', json['location']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'location');
       }
       String message;
       if (json.containsKey('message')) {
         message =
-            jsonDecoder.decodeString(jsonPath + '.message', json['message']);
+            jsonDecoder.decodeString('$jsonPath.message', json['message']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'message');
       }
       String? correction;
       if (json.containsKey('correction')) {
         correction = jsonDecoder.decodeString(
-            jsonPath + '.correction', json['correction']);
+            '$jsonPath.correction', json['correction']);
       }
       String code;
       if (json.containsKey('code')) {
-        code = jsonDecoder.decodeString(jsonPath + '.code', json['code']);
+        code = jsonDecoder.decodeString('$jsonPath.code', json['code']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'code');
       }
       String? url;
       if (json.containsKey('url')) {
-        url = jsonDecoder.decodeString(jsonPath + '.url', json['url']);
+        url = jsonDecoder.decodeString('$jsonPath.url', json['url']);
       }
       List<DiagnosticMessage>? contextMessages;
       if (json.containsKey('contextMessages')) {
         contextMessages = jsonDecoder.decodeList(
-            jsonPath + '.contextMessages',
+            '$jsonPath.contextMessages',
             json['contextMessages'],
             (String jsonPath, Object? json) =>
                 DiagnosticMessage.fromJson(jsonDecoder, jsonPath, json));
       }
       bool? hasFix;
       if (json.containsKey('hasFix')) {
-        hasFix = jsonDecoder.decodeBool(jsonPath + '.hasFix', json['hasFix']);
+        hasFix = jsonDecoder.decodeBool('$jsonPath.hasFix', json['hasFix']);
       }
       return AnalysisError(severity, type, location, message, code,
           correction: correction,
@@ -440,7 +440,7 @@
       List<SourceEdit> edits;
       if (json.containsKey('edits')) {
         edits = jsonDecoder.decodeList(
-            jsonPath + '.edits',
+            '$jsonPath.edits',
             json['edits'],
             (String jsonPath, Object? json) =>
                 SourceEdit.fromJson(jsonDecoder, jsonPath, json));
@@ -673,145 +673,144 @@
       CompletionSuggestionKind kind;
       if (json.containsKey('kind')) {
         kind = CompletionSuggestionKind.fromJson(
-            jsonDecoder, jsonPath + '.kind', json['kind']);
+            jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
       int relevance;
       if (json.containsKey('relevance')) {
         relevance =
-            jsonDecoder.decodeInt(jsonPath + '.relevance', json['relevance']);
+            jsonDecoder.decodeInt('$jsonPath.relevance', json['relevance']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'relevance');
       }
       String completion;
       if (json.containsKey('completion')) {
         completion = jsonDecoder.decodeString(
-            jsonPath + '.completion', json['completion']);
+            '$jsonPath.completion', json['completion']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'completion');
       }
       String? displayText;
       if (json.containsKey('displayText')) {
         displayText = jsonDecoder.decodeString(
-            jsonPath + '.displayText', json['displayText']);
+            '$jsonPath.displayText', json['displayText']);
       }
       int? replacementOffset;
       if (json.containsKey('replacementOffset')) {
         replacementOffset = jsonDecoder.decodeInt(
-            jsonPath + '.replacementOffset', json['replacementOffset']);
+            '$jsonPath.replacementOffset', json['replacementOffset']);
       }
       int? replacementLength;
       if (json.containsKey('replacementLength')) {
         replacementLength = jsonDecoder.decodeInt(
-            jsonPath + '.replacementLength', json['replacementLength']);
+            '$jsonPath.replacementLength', json['replacementLength']);
       }
       int selectionOffset;
       if (json.containsKey('selectionOffset')) {
         selectionOffset = jsonDecoder.decodeInt(
-            jsonPath + '.selectionOffset', json['selectionOffset']);
+            '$jsonPath.selectionOffset', json['selectionOffset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'selectionOffset');
       }
       int selectionLength;
       if (json.containsKey('selectionLength')) {
         selectionLength = jsonDecoder.decodeInt(
-            jsonPath + '.selectionLength', json['selectionLength']);
+            '$jsonPath.selectionLength', json['selectionLength']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'selectionLength');
       }
       bool isDeprecated;
       if (json.containsKey('isDeprecated')) {
         isDeprecated = jsonDecoder.decodeBool(
-            jsonPath + '.isDeprecated', json['isDeprecated']);
+            '$jsonPath.isDeprecated', json['isDeprecated']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'isDeprecated');
       }
       bool isPotential;
       if (json.containsKey('isPotential')) {
         isPotential = jsonDecoder.decodeBool(
-            jsonPath + '.isPotential', json['isPotential']);
+            '$jsonPath.isPotential', json['isPotential']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'isPotential');
       }
       String? docSummary;
       if (json.containsKey('docSummary')) {
         docSummary = jsonDecoder.decodeString(
-            jsonPath + '.docSummary', json['docSummary']);
+            '$jsonPath.docSummary', json['docSummary']);
       }
       String? docComplete;
       if (json.containsKey('docComplete')) {
         docComplete = jsonDecoder.decodeString(
-            jsonPath + '.docComplete', json['docComplete']);
+            '$jsonPath.docComplete', json['docComplete']);
       }
       String? declaringType;
       if (json.containsKey('declaringType')) {
         declaringType = jsonDecoder.decodeString(
-            jsonPath + '.declaringType', json['declaringType']);
+            '$jsonPath.declaringType', json['declaringType']);
       }
       String? defaultArgumentListString;
       if (json.containsKey('defaultArgumentListString')) {
         defaultArgumentListString = jsonDecoder.decodeString(
-            jsonPath + '.defaultArgumentListString',
+            '$jsonPath.defaultArgumentListString',
             json['defaultArgumentListString']);
       }
       List<int>? defaultArgumentListTextRanges;
       if (json.containsKey('defaultArgumentListTextRanges')) {
         defaultArgumentListTextRanges = jsonDecoder.decodeList(
-            jsonPath + '.defaultArgumentListTextRanges',
+            '$jsonPath.defaultArgumentListTextRanges',
             json['defaultArgumentListTextRanges'],
             jsonDecoder.decodeInt);
       }
       Element? element;
       if (json.containsKey('element')) {
-        element = Element.fromJson(
-            jsonDecoder, jsonPath + '.element', json['element']);
+        element =
+            Element.fromJson(jsonDecoder, '$jsonPath.element', json['element']);
       }
       String? returnType;
       if (json.containsKey('returnType')) {
         returnType = jsonDecoder.decodeString(
-            jsonPath + '.returnType', json['returnType']);
+            '$jsonPath.returnType', json['returnType']);
       }
       List<String>? parameterNames;
       if (json.containsKey('parameterNames')) {
-        parameterNames = jsonDecoder.decodeList(jsonPath + '.parameterNames',
+        parameterNames = jsonDecoder.decodeList('$jsonPath.parameterNames',
             json['parameterNames'], jsonDecoder.decodeString);
       }
       List<String>? parameterTypes;
       if (json.containsKey('parameterTypes')) {
-        parameterTypes = jsonDecoder.decodeList(jsonPath + '.parameterTypes',
+        parameterTypes = jsonDecoder.decodeList('$jsonPath.parameterTypes',
             json['parameterTypes'], jsonDecoder.decodeString);
       }
       int? requiredParameterCount;
       if (json.containsKey('requiredParameterCount')) {
         requiredParameterCount = jsonDecoder.decodeInt(
-            jsonPath + '.requiredParameterCount',
-            json['requiredParameterCount']);
+            '$jsonPath.requiredParameterCount', json['requiredParameterCount']);
       }
       bool? hasNamedParameters;
       if (json.containsKey('hasNamedParameters')) {
         hasNamedParameters = jsonDecoder.decodeBool(
-            jsonPath + '.hasNamedParameters', json['hasNamedParameters']);
+            '$jsonPath.hasNamedParameters', json['hasNamedParameters']);
       }
       String? parameterName;
       if (json.containsKey('parameterName')) {
         parameterName = jsonDecoder.decodeString(
-            jsonPath + '.parameterName', json['parameterName']);
+            '$jsonPath.parameterName', json['parameterName']);
       }
       String? parameterType;
       if (json.containsKey('parameterType')) {
         parameterType = jsonDecoder.decodeString(
-            jsonPath + '.parameterType', json['parameterType']);
+            '$jsonPath.parameterType', json['parameterType']);
       }
       String? libraryUri;
       if (json.containsKey('libraryUri')) {
         libraryUri = jsonDecoder.decodeString(
-            jsonPath + '.libraryUri', json['libraryUri']);
+            '$jsonPath.libraryUri', json['libraryUri']);
       }
       bool? isNotImported;
       if (json.containsKey('isNotImported')) {
         isNotImported = jsonDecoder.decodeBool(
-            jsonPath + '.isNotImported', json['isNotImported']);
+            '$jsonPath.isNotImported', json['isNotImported']);
       }
       return CompletionSuggestion(kind, relevance, completion, selectionOffset,
           selectionLength, isDeprecated, isPotential,
@@ -1146,14 +1145,14 @@
       String message;
       if (json.containsKey('message')) {
         message =
-            jsonDecoder.decodeString(jsonPath + '.message', json['message']);
+            jsonDecoder.decodeString('$jsonPath.message', json['message']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'message');
       }
       Location location;
       if (json.containsKey('location')) {
         location = Location.fromJson(
-            jsonDecoder, jsonPath + '.location', json['location']);
+            jsonDecoder, '$jsonPath.location', json['location']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'location');
       }
@@ -1282,46 +1281,46 @@
       ElementKind kind;
       if (json.containsKey('kind')) {
         kind =
-            ElementKind.fromJson(jsonDecoder, jsonPath + '.kind', json['kind']);
+            ElementKind.fromJson(jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
       String name;
       if (json.containsKey('name')) {
-        name = jsonDecoder.decodeString(jsonPath + '.name', json['name']);
+        name = jsonDecoder.decodeString('$jsonPath.name', json['name']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'name');
       }
       Location? location;
       if (json.containsKey('location')) {
         location = Location.fromJson(
-            jsonDecoder, jsonPath + '.location', json['location']);
+            jsonDecoder, '$jsonPath.location', json['location']);
       }
       int flags;
       if (json.containsKey('flags')) {
-        flags = jsonDecoder.decodeInt(jsonPath + '.flags', json['flags']);
+        flags = jsonDecoder.decodeInt('$jsonPath.flags', json['flags']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'flags');
       }
       String? parameters;
       if (json.containsKey('parameters')) {
         parameters = jsonDecoder.decodeString(
-            jsonPath + '.parameters', json['parameters']);
+            '$jsonPath.parameters', json['parameters']);
       }
       String? returnType;
       if (json.containsKey('returnType')) {
         returnType = jsonDecoder.decodeString(
-            jsonPath + '.returnType', json['returnType']);
+            '$jsonPath.returnType', json['returnType']);
       }
       String? typeParameters;
       if (json.containsKey('typeParameters')) {
         typeParameters = jsonDecoder.decodeString(
-            jsonPath + '.typeParameters', json['typeParameters']);
+            '$jsonPath.typeParameters', json['typeParameters']);
       }
       String? aliasedType;
       if (json.containsKey('aliasedType')) {
         aliasedType = jsonDecoder.decodeString(
-            jsonPath + '.aliasedType', json['aliasedType']);
+            '$jsonPath.aliasedType', json['aliasedType']);
       }
       return Element(kind, name, flags,
           location: location,
@@ -1748,19 +1747,19 @@
       FoldingKind kind;
       if (json.containsKey('kind')) {
         kind =
-            FoldingKind.fromJson(jsonDecoder, jsonPath + '.kind', json['kind']);
+            FoldingKind.fromJson(jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
@@ -1828,19 +1827,19 @@
       HighlightRegionType type;
       if (json.containsKey('type')) {
         type = HighlightRegionType.fromJson(
-            jsonDecoder, jsonPath + '.type', json['type']);
+            jsonDecoder, '$jsonPath.type', json['type']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'type');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
@@ -2522,29 +2521,29 @@
       KytheVName source;
       if (json.containsKey('source')) {
         source = KytheVName.fromJson(
-            jsonDecoder, jsonPath + '.source', json['source']);
+            jsonDecoder, '$jsonPath.source', json['source']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'source');
       }
       String? kind;
       if (json.containsKey('kind')) {
-        kind = jsonDecoder.decodeString(jsonPath + '.kind', json['kind']);
+        kind = jsonDecoder.decodeString('$jsonPath.kind', json['kind']);
       }
       KytheVName? target;
       if (json.containsKey('target')) {
         target = KytheVName.fromJson(
-            jsonDecoder, jsonPath + '.target', json['target']);
+            jsonDecoder, '$jsonPath.target', json['target']);
       }
       String fact;
       if (json.containsKey('fact')) {
-        fact = jsonDecoder.decodeString(jsonPath + '.fact', json['fact']);
+        fact = jsonDecoder.decodeString('$jsonPath.fact', json['fact']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'fact');
       }
       List<int>? value;
       if (json.containsKey('value')) {
         value = jsonDecoder.decodeList(
-            jsonPath + '.value', json['value'], jsonDecoder.decodeInt);
+            '$jsonPath.value', json['value'], jsonDecoder.decodeInt);
       }
       return KytheEntry(source, fact, kind: kind, target: target, value: value);
     } else {
@@ -2637,33 +2636,33 @@
     if (json is Map) {
       String signature;
       if (json.containsKey('signature')) {
-        signature = jsonDecoder.decodeString(
-            jsonPath + '.signature', json['signature']);
+        signature =
+            jsonDecoder.decodeString('$jsonPath.signature', json['signature']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'signature');
       }
       String corpus;
       if (json.containsKey('corpus')) {
-        corpus = jsonDecoder.decodeString(jsonPath + '.corpus', json['corpus']);
+        corpus = jsonDecoder.decodeString('$jsonPath.corpus', json['corpus']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'corpus');
       }
       String root;
       if (json.containsKey('root')) {
-        root = jsonDecoder.decodeString(jsonPath + '.root', json['root']);
+        root = jsonDecoder.decodeString('$jsonPath.root', json['root']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'root');
       }
       String path;
       if (json.containsKey('path')) {
-        path = jsonDecoder.decodeString(jsonPath + '.path', json['path']);
+        path = jsonDecoder.decodeString('$jsonPath.path', json['path']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'path');
       }
       String language;
       if (json.containsKey('language')) {
         language =
-            jsonDecoder.decodeString(jsonPath + '.language', json['language']);
+            jsonDecoder.decodeString('$jsonPath.language', json['language']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'language');
       }
@@ -2739,7 +2738,7 @@
       List<Position> positions;
       if (json.containsKey('positions')) {
         positions = jsonDecoder.decodeList(
-            jsonPath + '.positions',
+            '$jsonPath.positions',
             json['positions'],
             (String jsonPath, Object? json) =>
                 Position.fromJson(jsonDecoder, jsonPath, json));
@@ -2748,14 +2747,14 @@
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       List<LinkedEditSuggestion> suggestions;
       if (json.containsKey('suggestions')) {
         suggestions = jsonDecoder.decodeList(
-            jsonPath + '.suggestions',
+            '$jsonPath.suggestions',
             json['suggestions'],
             (String jsonPath, Object? json) =>
                 LinkedEditSuggestion.fromJson(jsonDecoder, jsonPath, json));
@@ -2840,14 +2839,14 @@
     if (json is Map) {
       String value;
       if (json.containsKey('value')) {
-        value = jsonDecoder.decodeString(jsonPath + '.value', json['value']);
+        value = jsonDecoder.decodeString('$jsonPath.value', json['value']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'value');
       }
       LinkedEditSuggestionKind kind;
       if (json.containsKey('kind')) {
         kind = LinkedEditSuggestionKind.fromJson(
-            jsonDecoder, jsonPath + '.kind', json['kind']);
+            jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
@@ -2996,44 +2995,44 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       int startLine;
       if (json.containsKey('startLine')) {
         startLine =
-            jsonDecoder.decodeInt(jsonPath + '.startLine', json['startLine']);
+            jsonDecoder.decodeInt('$jsonPath.startLine', json['startLine']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'startLine');
       }
       int startColumn;
       if (json.containsKey('startColumn')) {
-        startColumn = jsonDecoder.decodeInt(
-            jsonPath + '.startColumn', json['startColumn']);
+        startColumn =
+            jsonDecoder.decodeInt('$jsonPath.startColumn', json['startColumn']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'startColumn');
       }
       int? endLine;
       if (json.containsKey('endLine')) {
-        endLine = jsonDecoder.decodeInt(jsonPath + '.endLine', json['endLine']);
+        endLine = jsonDecoder.decodeInt('$jsonPath.endLine', json['endLine']);
       }
       int? endColumn;
       if (json.containsKey('endColumn')) {
         endColumn =
-            jsonDecoder.decodeInt(jsonPath + '.endColumn', json['endColumn']);
+            jsonDecoder.decodeInt('$jsonPath.endColumn', json['endColumn']);
       }
       return Location(file, offset, length, startLine, startColumn,
           endLine: endLine, endColumn: endColumn);
@@ -3119,20 +3118,20 @@
     if (json is Map) {
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       List<int> targets;
       if (json.containsKey('targets')) {
         targets = jsonDecoder.decodeList(
-            jsonPath + '.targets', json['targets'], jsonDecoder.decodeInt);
+            '$jsonPath.targets', json['targets'], jsonDecoder.decodeInt);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'targets');
       }
@@ -3225,52 +3224,52 @@
       ElementKind kind;
       if (json.containsKey('kind')) {
         kind =
-            ElementKind.fromJson(jsonDecoder, jsonPath + '.kind', json['kind']);
+            ElementKind.fromJson(jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
       int fileIndex;
       if (json.containsKey('fileIndex')) {
         fileIndex =
-            jsonDecoder.decodeInt(jsonPath + '.fileIndex', json['fileIndex']);
+            jsonDecoder.decodeInt('$jsonPath.fileIndex', json['fileIndex']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'fileIndex');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       int startLine;
       if (json.containsKey('startLine')) {
         startLine =
-            jsonDecoder.decodeInt(jsonPath + '.startLine', json['startLine']);
+            jsonDecoder.decodeInt('$jsonPath.startLine', json['startLine']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'startLine');
       }
       int startColumn;
       if (json.containsKey('startColumn')) {
-        startColumn = jsonDecoder.decodeInt(
-            jsonPath + '.startColumn', json['startColumn']);
+        startColumn =
+            jsonDecoder.decodeInt('$jsonPath.startColumn', json['startColumn']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'startColumn');
       }
       int? codeOffset;
       if (json.containsKey('codeOffset')) {
         codeOffset =
-            jsonDecoder.decodeInt(jsonPath + '.codeOffset', json['codeOffset']);
+            jsonDecoder.decodeInt('$jsonPath.codeOffset', json['codeOffset']);
       }
       int? codeLength;
       if (json.containsKey('codeLength')) {
         codeLength =
-            jsonDecoder.decodeInt(jsonPath + '.codeLength', json['codeLength']);
+            jsonDecoder.decodeInt('$jsonPath.codeLength', json['codeLength']);
       }
       return NavigationTarget(
           kind, fileIndex, offset, length, startLine, startColumn,
@@ -3358,21 +3357,21 @@
     if (json is Map) {
       Element element;
       if (json.containsKey('element')) {
-        element = Element.fromJson(
-            jsonDecoder, jsonPath + '.element', json['element']);
+        element =
+            Element.fromJson(jsonDecoder, '$jsonPath.element', json['element']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'element');
       }
       List<int> offsets;
       if (json.containsKey('offsets')) {
         offsets = jsonDecoder.decodeList(
-            jsonPath + '.offsets', json['offsets'], jsonDecoder.decodeInt);
+            '$jsonPath.offsets', json['offsets'], jsonDecoder.decodeInt);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offsets');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
@@ -3458,41 +3457,41 @@
     if (json is Map) {
       Element element;
       if (json.containsKey('element')) {
-        element = Element.fromJson(
-            jsonDecoder, jsonPath + '.element', json['element']);
+        element =
+            Element.fromJson(jsonDecoder, '$jsonPath.element', json['element']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'element');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       int codeOffset;
       if (json.containsKey('codeOffset')) {
         codeOffset =
-            jsonDecoder.decodeInt(jsonPath + '.codeOffset', json['codeOffset']);
+            jsonDecoder.decodeInt('$jsonPath.codeOffset', json['codeOffset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'codeOffset');
       }
       int codeLength;
       if (json.containsKey('codeLength')) {
         codeLength =
-            jsonDecoder.decodeInt(jsonPath + '.codeLength', json['codeLength']);
+            jsonDecoder.decodeInt('$jsonPath.codeLength', json['codeLength']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'codeLength');
       }
       List<Outline>? children;
       if (json.containsKey('children')) {
         children = jsonDecoder.decodeList(
-            jsonPath + '.children',
+            '$jsonPath.children',
             json['children'],
             (String jsonPath, Object? json) =>
                 Outline.fromJson(jsonDecoder, jsonPath, json));
@@ -3579,27 +3578,27 @@
     if (json is Map) {
       ParameterKind kind;
       if (json.containsKey('kind')) {
-        kind = ParameterKind.fromJson(
-            jsonDecoder, jsonPath + '.kind', json['kind']);
+        kind =
+            ParameterKind.fromJson(jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
       String name;
       if (json.containsKey('name')) {
-        name = jsonDecoder.decodeString(jsonPath + '.name', json['name']);
+        name = jsonDecoder.decodeString('$jsonPath.name', json['name']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'name');
       }
       String type;
       if (json.containsKey('type')) {
-        type = jsonDecoder.decodeString(jsonPath + '.type', json['type']);
+        type = jsonDecoder.decodeString('$jsonPath.type', json['type']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'type');
       }
       String? defaultValue;
       if (json.containsKey('defaultValue')) {
         defaultValue = jsonDecoder.decodeString(
-            jsonPath + '.defaultValue', json['defaultValue']);
+            '$jsonPath.defaultValue', json['defaultValue']);
       }
       return ParameterInfo(kind, name, type, defaultValue: defaultValue);
     } else {
@@ -3736,13 +3735,13 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
@@ -3919,31 +3918,31 @@
     if (json is Map) {
       String? id;
       if (json.containsKey('id')) {
-        id = jsonDecoder.decodeString(jsonPath + '.id', json['id']);
+        id = jsonDecoder.decodeString('$jsonPath.id', json['id']);
       }
       RefactoringMethodParameterKind kind;
       if (json.containsKey('kind')) {
         kind = RefactoringMethodParameterKind.fromJson(
-            jsonDecoder, jsonPath + '.kind', json['kind']);
+            jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
       String type;
       if (json.containsKey('type')) {
-        type = jsonDecoder.decodeString(jsonPath + '.type', json['type']);
+        type = jsonDecoder.decodeString('$jsonPath.type', json['type']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'type');
       }
       String name;
       if (json.containsKey('name')) {
-        name = jsonDecoder.decodeString(jsonPath + '.name', json['name']);
+        name = jsonDecoder.decodeString('$jsonPath.name', json['name']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'name');
       }
       String? parameters;
       if (json.containsKey('parameters')) {
         parameters = jsonDecoder.decodeString(
-            jsonPath + '.parameters', json['parameters']);
+            '$jsonPath.parameters', json['parameters']);
       }
       return RefactoringMethodParameter(kind, type, name,
           id: id, parameters: parameters);
@@ -4083,21 +4082,21 @@
       RefactoringProblemSeverity severity;
       if (json.containsKey('severity')) {
         severity = RefactoringProblemSeverity.fromJson(
-            jsonDecoder, jsonPath + '.severity', json['severity']);
+            jsonDecoder, '$jsonPath.severity', json['severity']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'severity');
       }
       String message;
       if (json.containsKey('message')) {
         message =
-            jsonDecoder.decodeString(jsonPath + '.message', json['message']);
+            jsonDecoder.decodeString('$jsonPath.message', json['message']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'message');
       }
       Location? location;
       if (json.containsKey('location')) {
         location = Location.fromJson(
-            jsonDecoder, jsonPath + '.location', json['location']);
+            jsonDecoder, '$jsonPath.location', json['location']);
       }
       return RefactoringProblem(severity, message, location: location);
     } else {
@@ -4319,14 +4318,14 @@
       String message;
       if (json.containsKey('message')) {
         message =
-            jsonDecoder.decodeString(jsonPath + '.message', json['message']);
+            jsonDecoder.decodeString('$jsonPath.message', json['message']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'message');
       }
       List<SourceFileEdit> edits;
       if (json.containsKey('edits')) {
         edits = jsonDecoder.decodeList(
-            jsonPath + '.edits',
+            '$jsonPath.edits',
             json['edits'],
             (String jsonPath, Object? json) =>
                 SourceFileEdit.fromJson(jsonDecoder, jsonPath, json));
@@ -4336,7 +4335,7 @@
       List<LinkedEditGroup> linkedEditGroups;
       if (json.containsKey('linkedEditGroups')) {
         linkedEditGroups = jsonDecoder.decodeList(
-            jsonPath + '.linkedEditGroups',
+            '$jsonPath.linkedEditGroups',
             json['linkedEditGroups'],
             (String jsonPath, Object? json) =>
                 LinkedEditGroup.fromJson(jsonDecoder, jsonPath, json));
@@ -4346,16 +4345,16 @@
       Position? selection;
       if (json.containsKey('selection')) {
         selection = Position.fromJson(
-            jsonDecoder, jsonPath + '.selection', json['selection']);
+            jsonDecoder, '$jsonPath.selection', json['selection']);
       }
       int? selectionLength;
       if (json.containsKey('selectionLength')) {
         selectionLength = jsonDecoder.decodeInt(
-            jsonPath + '.selectionLength', json['selectionLength']);
+            '$jsonPath.selectionLength', json['selectionLength']);
       }
       String? id;
       if (json.containsKey('id')) {
-        id = jsonDecoder.decodeString(jsonPath + '.id', json['id']);
+        id = jsonDecoder.decodeString('$jsonPath.id', json['id']);
       }
       return SourceChange(message,
           edits: edits,
@@ -4487,26 +4486,26 @@
     if (json is Map) {
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       String replacement;
       if (json.containsKey('replacement')) {
         replacement = jsonDecoder.decodeString(
-            jsonPath + '.replacement', json['replacement']);
+            '$jsonPath.replacement', json['replacement']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'replacement');
       }
       String? id;
       if (json.containsKey('id')) {
-        id = jsonDecoder.decodeString(jsonPath + '.id', json['id']);
+        id = jsonDecoder.decodeString('$jsonPath.id', json['id']);
       }
       return SourceEdit(offset, length, replacement, id: id);
     } else {
@@ -4588,21 +4587,21 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       int fileStamp;
       if (json.containsKey('fileStamp')) {
         fileStamp =
-            jsonDecoder.decodeInt(jsonPath + '.fileStamp', json['fileStamp']);
+            jsonDecoder.decodeInt('$jsonPath.fileStamp', json['fileStamp']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'fileStamp');
       }
       List<SourceEdit> edits;
       if (json.containsKey('edits')) {
         edits = jsonDecoder.decodeList(
-            jsonPath + '.edits',
+            '$jsonPath.edits',
             json['edits'],
             (String jsonPath, Object? json) =>
                 SourceEdit.fromJson(jsonDecoder, jsonPath, json));
diff --git a/pkg/analyzer_plugin/lib/protocol/protocol_generated.dart b/pkg/analyzer_plugin/lib/protocol/protocol_generated.dart
index 634de11..1644405 100644
--- a/pkg/analyzer_plugin/lib/protocol/protocol_generated.dart
+++ b/pkg/analyzer_plugin/lib/protocol/protocol_generated.dart
@@ -39,14 +39,14 @@
       AnalysisError error;
       if (json.containsKey('error')) {
         error = AnalysisError.fromJson(
-            jsonDecoder, jsonPath + '.error', json['error']);
+            jsonDecoder, '$jsonPath.error', json['error']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'error');
       }
       List<PrioritizedSourceChange> fixes;
       if (json.containsKey('fixes')) {
         fixes = jsonDecoder.decodeList(
-            jsonPath + '.fixes',
+            '$jsonPath.fixes',
             json['fixes'],
             (String jsonPath, Object? json) =>
                 PrioritizedSourceChange.fromJson(jsonDecoder, jsonPath, json));
@@ -111,14 +111,14 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       List<AnalysisError> errors;
       if (json.containsKey('errors')) {
         errors = jsonDecoder.decodeList(
-            jsonPath + '.errors',
+            '$jsonPath.errors',
             json['errors'],
             (String jsonPath, Object? json) =>
                 AnalysisError.fromJson(jsonDecoder, jsonPath, json));
@@ -192,14 +192,14 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       List<FoldingRegion> regions;
       if (json.containsKey('regions')) {
         regions = jsonDecoder.decodeList(
-            jsonPath + '.regions',
+            '$jsonPath.regions',
             json['regions'],
             (String jsonPath, Object? json) =>
                 FoldingRegion.fromJson(jsonDecoder, jsonPath, json));
@@ -279,19 +279,19 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
@@ -372,14 +372,14 @@
       List<String> files;
       if (json.containsKey('files')) {
         files = jsonDecoder.decodeList(
-            jsonPath + '.files', json['files'], jsonDecoder.decodeString);
+            '$jsonPath.files', json['files'], jsonDecoder.decodeString);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'files');
       }
       List<NavigationTarget> targets;
       if (json.containsKey('targets')) {
         targets = jsonDecoder.decodeList(
-            jsonPath + '.targets',
+            '$jsonPath.targets',
             json['targets'],
             (String jsonPath, Object? json) =>
                 NavigationTarget.fromJson(jsonDecoder, jsonPath, json));
@@ -389,7 +389,7 @@
       List<NavigationRegion> regions;
       if (json.containsKey('regions')) {
         regions = jsonDecoder.decodeList(
-            jsonPath + '.regions',
+            '$jsonPath.regions',
             json['regions'],
             (String jsonPath, Object? json) =>
                 NavigationRegion.fromJson(jsonDecoder, jsonPath, json));
@@ -469,7 +469,7 @@
       List<WatchEvent> events;
       if (json.containsKey('events')) {
         events = jsonDecoder.decodeList(
-            jsonPath + '.events',
+            '$jsonPath.events',
             json['events'],
             (String jsonPath, Object? json) =>
                 WatchEvent.fromJson(jsonDecoder, jsonPath, json));
@@ -559,14 +559,14 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       List<HighlightRegion> regions;
       if (json.containsKey('regions')) {
         regions = jsonDecoder.decodeList(
-            jsonPath + '.regions',
+            '$jsonPath.regions',
             json['regions'],
             (String jsonPath, Object? json) =>
                 HighlightRegion.fromJson(jsonDecoder, jsonPath, json));
@@ -650,14 +650,14 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       List<NavigationRegion> regions;
       if (json.containsKey('regions')) {
         regions = jsonDecoder.decodeList(
-            jsonPath + '.regions',
+            '$jsonPath.regions',
             json['regions'],
             (String jsonPath, Object? json) =>
                 NavigationRegion.fromJson(jsonDecoder, jsonPath, json));
@@ -667,7 +667,7 @@
       List<NavigationTarget> targets;
       if (json.containsKey('targets')) {
         targets = jsonDecoder.decodeList(
-            jsonPath + '.targets',
+            '$jsonPath.targets',
             json['targets'],
             (String jsonPath, Object? json) =>
                 NavigationTarget.fromJson(jsonDecoder, jsonPath, json));
@@ -677,7 +677,7 @@
       List<String> files;
       if (json.containsKey('files')) {
         files = jsonDecoder.decodeList(
-            jsonPath + '.files', json['files'], jsonDecoder.decodeString);
+            '$jsonPath.files', json['files'], jsonDecoder.decodeString);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'files');
       }
@@ -756,14 +756,14 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       List<Occurrences> occurrences;
       if (json.containsKey('occurrences')) {
         occurrences = jsonDecoder.decodeList(
-            jsonPath + '.occurrences',
+            '$jsonPath.occurrences',
             json['occurrences'],
             (String jsonPath, Object? json) =>
                 Occurrences.fromJson(jsonDecoder, jsonPath, json));
@@ -838,14 +838,14 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       List<Outline> outline;
       if (json.containsKey('outline')) {
         outline = jsonDecoder.decodeList(
-            jsonPath + '.outline',
+            '$jsonPath.outline',
             json['outline'],
             (String jsonPath, Object? json) =>
                 Outline.fromJson(jsonDecoder, jsonPath, json));
@@ -984,7 +984,7 @@
       List<ContextRoot> roots;
       if (json.containsKey('roots')) {
         roots = jsonDecoder.decodeList(
-            jsonPath + '.roots',
+            '$jsonPath.roots',
             json['roots'],
             (String jsonPath, Object? json) =>
                 ContextRoot.fromJson(jsonDecoder, jsonPath, json));
@@ -1070,7 +1070,7 @@
       List<String> files;
       if (json.containsKey('files')) {
         files = jsonDecoder.decodeList(
-            jsonPath + '.files', json['files'], jsonDecoder.decodeString);
+            '$jsonPath.files', json['files'], jsonDecoder.decodeString);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'files');
       }
@@ -1153,7 +1153,7 @@
       Map<AnalysisService, List<String>> subscriptions;
       if (json.containsKey('subscriptions')) {
         subscriptions = jsonDecoder.decodeMap(
-            jsonPath + '.subscriptions', json['subscriptions'],
+            '$jsonPath.subscriptions', json['subscriptions'],
             keyDecoder: (String jsonPath, Object? json) =>
                 AnalysisService.fromJson(jsonDecoder, jsonPath, json),
             valueDecoder: (String jsonPath, Object? json) => jsonDecoder
@@ -1245,7 +1245,7 @@
     if (json is Map) {
       Map<String, Object> files;
       if (json.containsKey('files')) {
-        files = jsonDecoder.decodeMap(jsonPath + '.files', json['files'],
+        files = jsonDecoder.decodeMap('$jsonPath.files', json['files'],
             valueDecoder: (String jsonPath, Object? json) =>
                 jsonDecoder.decodeUnion(jsonPath, json, 'type', {
                   'add': (String jsonPath, Object? json) =>
@@ -1341,13 +1341,13 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
@@ -1433,21 +1433,21 @@
       int replacementOffset;
       if (json.containsKey('replacementOffset')) {
         replacementOffset = jsonDecoder.decodeInt(
-            jsonPath + '.replacementOffset', json['replacementOffset']);
+            '$jsonPath.replacementOffset', json['replacementOffset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'replacementOffset');
       }
       int replacementLength;
       if (json.containsKey('replacementLength')) {
         replacementLength = jsonDecoder.decodeInt(
-            jsonPath + '.replacementLength', json['replacementLength']);
+            '$jsonPath.replacementLength', json['replacementLength']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'replacementLength');
       }
       List<CompletionSuggestion> results;
       if (json.containsKey('results')) {
         results = jsonDecoder.decodeList(
-            jsonPath + '.results',
+            '$jsonPath.results',
             json['results'],
             (String jsonPath, Object? json) =>
                 CompletionSuggestion.fromJson(jsonDecoder, jsonPath, json));
@@ -1536,21 +1536,21 @@
     if (json is Map) {
       String root;
       if (json.containsKey('root')) {
-        root = jsonDecoder.decodeString(jsonPath + '.root', json['root']);
+        root = jsonDecoder.decodeString('$jsonPath.root', json['root']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'root');
       }
       List<String> exclude;
       if (json.containsKey('exclude')) {
         exclude = jsonDecoder.decodeList(
-            jsonPath + '.exclude', json['exclude'], jsonDecoder.decodeString);
+            '$jsonPath.exclude', json['exclude'], jsonDecoder.decodeString);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'exclude');
       }
       String? optionsFile;
       if (json.containsKey('optionsFile')) {
         optionsFile = jsonDecoder.decodeString(
-            jsonPath + '.optionsFile', json['optionsFile']);
+            '$jsonPath.optionsFile', json['optionsFile']);
       }
       return ContextRoot(root, exclude, optionsFile: optionsFile);
     } else {
@@ -1666,19 +1666,19 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
@@ -1748,7 +1748,7 @@
       List<PrioritizedSourceChange> assists;
       if (json.containsKey('assists')) {
         assists = jsonDecoder.decodeList(
-            jsonPath + '.assists',
+            '$jsonPath.assists',
             json['assists'],
             (String jsonPath, Object? json) =>
                 PrioritizedSourceChange.fromJson(jsonDecoder, jsonPath, json));
@@ -1824,19 +1824,19 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
@@ -1912,7 +1912,7 @@
       List<RefactoringKind> kinds;
       if (json.containsKey('kinds')) {
         kinds = jsonDecoder.decodeList(
-            jsonPath + '.kinds',
+            '$jsonPath.kinds',
             json['kinds'],
             (String jsonPath, Object? json) =>
                 RefactoringKind.fromJson(jsonDecoder, jsonPath, json));
@@ -1985,13 +1985,13 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
@@ -2057,7 +2057,7 @@
       List<AnalysisErrorFixes> fixes;
       if (json.containsKey('fixes')) {
         fixes = jsonDecoder.decodeList(
-            jsonPath + '.fixes',
+            '$jsonPath.fixes',
             json['fixes'],
             (String jsonPath, Object? json) =>
                 AnalysisErrorFixes.fromJson(jsonDecoder, jsonPath, json));
@@ -2153,39 +2153,39 @@
       RefactoringKind kind;
       if (json.containsKey('kind')) {
         kind = RefactoringKind.fromJson(
-            jsonDecoder, jsonPath + '.kind', json['kind']);
+            jsonDecoder, '$jsonPath.kind', json['kind']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'kind');
       }
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       bool validateOnly;
       if (json.containsKey('validateOnly')) {
         validateOnly = jsonDecoder.decodeBool(
-            jsonPath + '.validateOnly', json['validateOnly']);
+            '$jsonPath.validateOnly', json['validateOnly']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'validateOnly');
       }
       RefactoringOptions? options;
       if (json.containsKey('options')) {
         options = RefactoringOptions.fromJson(
-            jsonDecoder, jsonPath + '.options', json['options'], kind);
+            jsonDecoder, '$jsonPath.options', json['options'], kind);
       }
       return EditGetRefactoringParams(kind, file, offset, length, validateOnly,
           options: options);
@@ -2307,7 +2307,7 @@
       List<RefactoringProblem> initialProblems;
       if (json.containsKey('initialProblems')) {
         initialProblems = jsonDecoder.decodeList(
-            jsonPath + '.initialProblems',
+            '$jsonPath.initialProblems',
             json['initialProblems'],
             (String jsonPath, Object? json) =>
                 RefactoringProblem.fromJson(jsonDecoder, jsonPath, json));
@@ -2317,7 +2317,7 @@
       List<RefactoringProblem> optionsProblems;
       if (json.containsKey('optionsProblems')) {
         optionsProblems = jsonDecoder.decodeList(
-            jsonPath + '.optionsProblems',
+            '$jsonPath.optionsProblems',
             json['optionsProblems'],
             (String jsonPath, Object? json) =>
                 RefactoringProblem.fromJson(jsonDecoder, jsonPath, json));
@@ -2327,7 +2327,7 @@
       List<RefactoringProblem> finalProblems;
       if (json.containsKey('finalProblems')) {
         finalProblems = jsonDecoder.decodeList(
-            jsonPath + '.finalProblems',
+            '$jsonPath.finalProblems',
             json['finalProblems'],
             (String jsonPath, Object? json) =>
                 RefactoringProblem.fromJson(jsonDecoder, jsonPath, json));
@@ -2337,16 +2337,16 @@
       RefactoringFeedback? feedback;
       if (json.containsKey('feedback')) {
         feedback = RefactoringFeedback.fromJson(
-            jsonDecoder, jsonPath + '.feedback', json['feedback'], json);
+            jsonDecoder, '$jsonPath.feedback', json['feedback'], json);
       }
       SourceChange? change;
       if (json.containsKey('change')) {
         change = SourceChange.fromJson(
-            jsonDecoder, jsonPath + '.change', json['change']);
+            jsonDecoder, '$jsonPath.change', json['change']);
       }
       List<String>? potentialEdits;
       if (json.containsKey('potentialEdits')) {
-        potentialEdits = jsonDecoder.decodeList(jsonPath + '.potentialEdits',
+        potentialEdits = jsonDecoder.decodeList('$jsonPath.potentialEdits',
             json['potentialEdits'], jsonDecoder.decodeString);
       }
       return EditGetRefactoringResult(
@@ -2470,35 +2470,35 @@
       List<int>? coveringExpressionOffsets;
       if (json.containsKey('coveringExpressionOffsets')) {
         coveringExpressionOffsets = jsonDecoder.decodeList(
-            jsonPath + '.coveringExpressionOffsets',
+            '$jsonPath.coveringExpressionOffsets',
             json['coveringExpressionOffsets'],
             jsonDecoder.decodeInt);
       }
       List<int>? coveringExpressionLengths;
       if (json.containsKey('coveringExpressionLengths')) {
         coveringExpressionLengths = jsonDecoder.decodeList(
-            jsonPath + '.coveringExpressionLengths',
+            '$jsonPath.coveringExpressionLengths',
             json['coveringExpressionLengths'],
             jsonDecoder.decodeInt);
       }
       List<String> names;
       if (json.containsKey('names')) {
         names = jsonDecoder.decodeList(
-            jsonPath + '.names', json['names'], jsonDecoder.decodeString);
+            '$jsonPath.names', json['names'], jsonDecoder.decodeString);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'names');
       }
       List<int> offsets;
       if (json.containsKey('offsets')) {
         offsets = jsonDecoder.decodeList(
-            jsonPath + '.offsets', json['offsets'], jsonDecoder.decodeInt);
+            '$jsonPath.offsets', json['offsets'], jsonDecoder.decodeInt);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offsets');
       }
       List<int> lengths;
       if (json.containsKey('lengths')) {
         lengths = jsonDecoder.decodeList(
-            jsonPath + '.lengths', json['lengths'], jsonDecoder.decodeInt);
+            '$jsonPath.lengths', json['lengths'], jsonDecoder.decodeInt);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'lengths');
       }
@@ -2581,14 +2581,14 @@
     if (json is Map) {
       String name;
       if (json.containsKey('name')) {
-        name = jsonDecoder.decodeString(jsonPath + '.name', json['name']);
+        name = jsonDecoder.decodeString('$jsonPath.name', json['name']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'name');
       }
       bool extractAll;
       if (json.containsKey('extractAll')) {
-        extractAll = jsonDecoder.decodeBool(
-            jsonPath + '.extractAll', json['extractAll']);
+        extractAll =
+            jsonDecoder.decodeBool('$jsonPath.extractAll', json['extractAll']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'extractAll');
       }
@@ -2686,41 +2686,41 @@
     if (json is Map) {
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       String returnType;
       if (json.containsKey('returnType')) {
         returnType = jsonDecoder.decodeString(
-            jsonPath + '.returnType', json['returnType']);
+            '$jsonPath.returnType', json['returnType']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'returnType');
       }
       List<String> names;
       if (json.containsKey('names')) {
         names = jsonDecoder.decodeList(
-            jsonPath + '.names', json['names'], jsonDecoder.decodeString);
+            '$jsonPath.names', json['names'], jsonDecoder.decodeString);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'names');
       }
       bool canCreateGetter;
       if (json.containsKey('canCreateGetter')) {
         canCreateGetter = jsonDecoder.decodeBool(
-            jsonPath + '.canCreateGetter', json['canCreateGetter']);
+            '$jsonPath.canCreateGetter', json['canCreateGetter']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'canCreateGetter');
       }
       List<RefactoringMethodParameter> parameters;
       if (json.containsKey('parameters')) {
         parameters = jsonDecoder.decodeList(
-            jsonPath + '.parameters',
+            '$jsonPath.parameters',
             json['parameters'],
             (String jsonPath, Object? json) =>
                 RefactoringMethodParameter.fromJson(
@@ -2731,14 +2731,14 @@
       List<int> offsets;
       if (json.containsKey('offsets')) {
         offsets = jsonDecoder.decodeList(
-            jsonPath + '.offsets', json['offsets'], jsonDecoder.decodeInt);
+            '$jsonPath.offsets', json['offsets'], jsonDecoder.decodeInt);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offsets');
       }
       List<int> lengths;
       if (json.containsKey('lengths')) {
         lengths = jsonDecoder.decodeList(
-            jsonPath + '.lengths', json['lengths'], jsonDecoder.decodeInt);
+            '$jsonPath.lengths', json['lengths'], jsonDecoder.decodeInt);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'lengths');
       }
@@ -2849,27 +2849,27 @@
       String returnType;
       if (json.containsKey('returnType')) {
         returnType = jsonDecoder.decodeString(
-            jsonPath + '.returnType', json['returnType']);
+            '$jsonPath.returnType', json['returnType']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'returnType');
       }
       bool createGetter;
       if (json.containsKey('createGetter')) {
         createGetter = jsonDecoder.decodeBool(
-            jsonPath + '.createGetter', json['createGetter']);
+            '$jsonPath.createGetter', json['createGetter']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'createGetter');
       }
       String name;
       if (json.containsKey('name')) {
-        name = jsonDecoder.decodeString(jsonPath + '.name', json['name']);
+        name = jsonDecoder.decodeString('$jsonPath.name', json['name']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'name');
       }
       List<RefactoringMethodParameter> parameters;
       if (json.containsKey('parameters')) {
         parameters = jsonDecoder.decodeList(
-            jsonPath + '.parameters',
+            '$jsonPath.parameters',
             json['parameters'],
             (String jsonPath, Object? json) =>
                 RefactoringMethodParameter.fromJson(
@@ -2879,8 +2879,8 @@
       }
       bool extractAll;
       if (json.containsKey('extractAll')) {
-        extractAll = jsonDecoder.decodeBool(
-            jsonPath + '.extractAll', json['extractAll']);
+        extractAll =
+            jsonDecoder.decodeBool('$jsonPath.extractAll', json['extractAll']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'extractAll');
       }
@@ -2962,14 +2962,14 @@
     if (json is Map) {
       String name;
       if (json.containsKey('name')) {
-        name = jsonDecoder.decodeString(jsonPath + '.name', json['name']);
+        name = jsonDecoder.decodeString('$jsonPath.name', json['name']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'name');
       }
       int occurrences;
       if (json.containsKey('occurrences')) {
-        occurrences = jsonDecoder.decodeInt(
-            jsonPath + '.occurrences', json['occurrences']);
+        occurrences =
+            jsonDecoder.decodeInt('$jsonPath.occurrences', json['occurrences']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'occurrences');
       }
@@ -3047,20 +3047,20 @@
     if (json is Map) {
       String? className;
       if (json.containsKey('className')) {
-        className = jsonDecoder.decodeString(
-            jsonPath + '.className', json['className']);
+        className =
+            jsonDecoder.decodeString('$jsonPath.className', json['className']);
       }
       String methodName;
       if (json.containsKey('methodName')) {
         methodName = jsonDecoder.decodeString(
-            jsonPath + '.methodName', json['methodName']);
+            '$jsonPath.methodName', json['methodName']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'methodName');
       }
       bool isDeclaration;
       if (json.containsKey('isDeclaration')) {
         isDeclaration = jsonDecoder.decodeBool(
-            jsonPath + '.isDeclaration', json['isDeclaration']);
+            '$jsonPath.isDeclaration', json['isDeclaration']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'isDeclaration');
       }
@@ -3130,14 +3130,14 @@
       bool deleteSource;
       if (json.containsKey('deleteSource')) {
         deleteSource = jsonDecoder.decodeBool(
-            jsonPath + '.deleteSource', json['deleteSource']);
+            '$jsonPath.deleteSource', json['deleteSource']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'deleteSource');
       }
       bool inlineAll;
       if (json.containsKey('inlineAll')) {
         inlineAll =
-            jsonDecoder.decodeBool(jsonPath + '.inlineAll', json['inlineAll']);
+            jsonDecoder.decodeBool('$jsonPath.inlineAll', json['inlineAll']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'inlineAll');
       }
@@ -3199,7 +3199,7 @@
     if (json is Map) {
       String file;
       if (json.containsKey('file')) {
-        file = jsonDecoder.decodeString(jsonPath + '.file', json['file']);
+        file = jsonDecoder.decodeString('$jsonPath.file', json['file']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'file');
       }
@@ -3269,7 +3269,7 @@
       List<KytheEntry> entries;
       if (json.containsKey('entries')) {
         entries = jsonDecoder.decodeList(
-            jsonPath + '.entries',
+            '$jsonPath.entries',
             json['entries'],
             (String jsonPath, Object? json) =>
                 KytheEntry.fromJson(jsonDecoder, jsonPath, json));
@@ -3279,7 +3279,7 @@
       List<String> files;
       if (json.containsKey('files')) {
         files = jsonDecoder.decodeList(
-            jsonPath + '.files', json['files'], jsonDecoder.decodeString);
+            '$jsonPath.files', json['files'], jsonDecoder.decodeString);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'files');
       }
@@ -3362,7 +3362,7 @@
       String newFile;
       if (json.containsKey('newFile')) {
         newFile =
-            jsonDecoder.decodeString(jsonPath + '.newFile', json['newFile']);
+            jsonDecoder.decodeString('$jsonPath.newFile', json['newFile']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'newFile');
       }
@@ -3431,22 +3431,21 @@
     if (json is Map) {
       bool isFatal;
       if (json.containsKey('isFatal')) {
-        isFatal =
-            jsonDecoder.decodeBool(jsonPath + '.isFatal', json['isFatal']);
+        isFatal = jsonDecoder.decodeBool('$jsonPath.isFatal', json['isFatal']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'isFatal');
       }
       String message;
       if (json.containsKey('message')) {
         message =
-            jsonDecoder.decodeString(jsonPath + '.message', json['message']);
+            jsonDecoder.decodeString('$jsonPath.message', json['message']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'message');
       }
       String stackTrace;
       if (json.containsKey('stackTrace')) {
         stackTrace = jsonDecoder.decodeString(
-            jsonPath + '.stackTrace', json['stackTrace']);
+            '$jsonPath.stackTrace', json['stackTrace']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'stackTrace');
       }
@@ -3564,21 +3563,21 @@
       String byteStorePath;
       if (json.containsKey('byteStorePath')) {
         byteStorePath = jsonDecoder.decodeString(
-            jsonPath + '.byteStorePath', json['byteStorePath']);
+            '$jsonPath.byteStorePath', json['byteStorePath']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'byteStorePath');
       }
       String sdkPath;
       if (json.containsKey('sdkPath')) {
         sdkPath =
-            jsonDecoder.decodeString(jsonPath + '.sdkPath', json['sdkPath']);
+            jsonDecoder.decodeString('$jsonPath.sdkPath', json['sdkPath']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'sdkPath');
       }
       String version;
       if (json.containsKey('version')) {
         version =
-            jsonDecoder.decodeString(jsonPath + '.version', json['version']);
+            jsonDecoder.decodeString('$jsonPath.version', json['version']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'version');
       }
@@ -3674,34 +3673,32 @@
       bool isCompatible;
       if (json.containsKey('isCompatible')) {
         isCompatible = jsonDecoder.decodeBool(
-            jsonPath + '.isCompatible', json['isCompatible']);
+            '$jsonPath.isCompatible', json['isCompatible']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'isCompatible');
       }
       String name;
       if (json.containsKey('name')) {
-        name = jsonDecoder.decodeString(jsonPath + '.name', json['name']);
+        name = jsonDecoder.decodeString('$jsonPath.name', json['name']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'name');
       }
       String version;
       if (json.containsKey('version')) {
         version =
-            jsonDecoder.decodeString(jsonPath + '.version', json['version']);
+            jsonDecoder.decodeString('$jsonPath.version', json['version']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'version');
       }
       String? contactInfo;
       if (json.containsKey('contactInfo')) {
         contactInfo = jsonDecoder.decodeString(
-            jsonPath + '.contactInfo', json['contactInfo']);
+            '$jsonPath.contactInfo', json['contactInfo']);
       }
       List<String> interestingFiles;
       if (json.containsKey('interestingFiles')) {
-        interestingFiles = jsonDecoder.decodeList(
-            jsonPath + '.interestingFiles',
-            json['interestingFiles'],
-            jsonDecoder.decodeString);
+        interestingFiles = jsonDecoder.decodeList('$jsonPath.interestingFiles',
+            json['interestingFiles'], jsonDecoder.decodeString);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'interestingFiles');
       }
@@ -3790,14 +3787,14 @@
       int priority;
       if (json.containsKey('priority')) {
         priority =
-            jsonDecoder.decodeInt(jsonPath + '.priority', json['priority']);
+            jsonDecoder.decodeInt('$jsonPath.priority', json['priority']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'priority');
       }
       SourceChange change;
       if (json.containsKey('change')) {
         change = SourceChange.fromJson(
-            jsonDecoder, jsonPath + '.change', json['change']);
+            jsonDecoder, '$jsonPath.change', json['change']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'change');
       }
@@ -3936,27 +3933,27 @@
     if (json is Map) {
       int offset;
       if (json.containsKey('offset')) {
-        offset = jsonDecoder.decodeInt(jsonPath + '.offset', json['offset']);
+        offset = jsonDecoder.decodeInt('$jsonPath.offset', json['offset']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'offset');
       }
       int length;
       if (json.containsKey('length')) {
-        length = jsonDecoder.decodeInt(jsonPath + '.length', json['length']);
+        length = jsonDecoder.decodeInt('$jsonPath.length', json['length']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'length');
       }
       String elementKindName;
       if (json.containsKey('elementKindName')) {
         elementKindName = jsonDecoder.decodeString(
-            jsonPath + '.elementKindName', json['elementKindName']);
+            '$jsonPath.elementKindName', json['elementKindName']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'elementKindName');
       }
       String oldName;
       if (json.containsKey('oldName')) {
         oldName =
-            jsonDecoder.decodeString(jsonPath + '.oldName', json['oldName']);
+            jsonDecoder.decodeString('$jsonPath.oldName', json['oldName']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'oldName');
       }
@@ -4019,7 +4016,7 @@
       String newName;
       if (json.containsKey('newName')) {
         newName =
-            jsonDecoder.decodeString(jsonPath + '.newName', json['newName']);
+            jsonDecoder.decodeString('$jsonPath.newName', json['newName']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'newName');
       }
@@ -4086,21 +4083,21 @@
       RequestErrorCode code;
       if (json.containsKey('code')) {
         code = RequestErrorCode.fromJson(
-            jsonDecoder, jsonPath + '.code', json['code']);
+            jsonDecoder, '$jsonPath.code', json['code']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'code');
       }
       String message;
       if (json.containsKey('message')) {
         message =
-            jsonDecoder.decodeString(jsonPath + '.message', json['message']);
+            jsonDecoder.decodeString('$jsonPath.message', json['message']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'message');
       }
       String? stackTrace;
       if (json.containsKey('stackTrace')) {
         stackTrace = jsonDecoder.decodeString(
-            jsonPath + '.stackTrace', json['stackTrace']);
+            '$jsonPath.stackTrace', json['stackTrace']);
       }
       return RequestError(code, message, stackTrace: stackTrace);
     } else {
@@ -4246,13 +4243,13 @@
       WatchEventType type;
       if (json.containsKey('type')) {
         type = WatchEventType.fromJson(
-            jsonDecoder, jsonPath + '.type', json['type']);
+            jsonDecoder, '$jsonPath.type', json['type']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'type');
       }
       String path;
       if (json.containsKey('path')) {
-        path = jsonDecoder.decodeString(jsonPath + '.path', json['path']);
+        path = jsonDecoder.decodeString('$jsonPath.path', json['path']);
       } else {
         throw jsonDecoder.mismatch(jsonPath, 'path');
       }
diff --git a/pkg/analyzer_plugin/lib/src/channel/isolate_channel.dart b/pkg/analyzer_plugin/lib/src/channel/isolate_channel.dart
index f7cdfcb..4fc7d7d 100644
--- a/pkg/analyzer_plugin/lib/src/channel/isolate_channel.dart
+++ b/pkg/analyzer_plugin/lib/src/channel/isolate_channel.dart
@@ -215,7 +215,7 @@
         onDone();
       }
       close();
-      return null;
+      return;
     }
 
     var channelReady = Completer<void>();
diff --git a/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart b/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
index 262911a..6f37b19 100644
--- a/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
+++ b/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
@@ -21,8 +21,9 @@
 void addAllEditsForSource(
     SourceFileEdit sourceFileEdit, Iterable<SourceEdit> edits,
     {bool insertBeforeExisting = false}) {
-  edits.forEach((edit) =>
-      sourceFileEdit.add(edit, insertBeforeExisting: insertBeforeExisting));
+  for (var edit in edits) {
+    sourceFileEdit.add(edit, insertBeforeExisting: insertBeforeExisting);
+  }
 }
 
 /// Adds the given [sourceEdit] to the list in [sourceFileEdit] while preserving
@@ -108,9 +109,9 @@
 /// are applied in the order they appear in [edits]. Access via
 /// SourceEdit.applySequence().
 String applySequenceOfEdits(String code, Iterable<SourceEdit> edits) {
-  edits.forEach((SourceEdit edit) {
+  for (var edit in edits) {
     code = edit.apply(code);
-  });
+  }
   return code;
 }
 
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
index 0f6f1db..080188d 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
@@ -312,7 +312,7 @@
   /// [offset] such that the positions are offset by the given [delta].
   /// Positions occur in linked edit groups and as the post-change selection.
   void _updatePositions(int offset, int delta) {
-    void _updatePosition(Position position) {
+    void updatePosition(Position position) {
       if (position.offset >= offset && !_lockedPositions.contains(position)) {
         position.offset = position.offset + delta;
       }
@@ -320,12 +320,12 @@
 
     for (var group in _linkedEditGroups.values) {
       for (var position in group.positions) {
-        _updatePosition(position);
+        updatePosition(position);
       }
     }
     var selection = _selection;
     if (selection != null) {
-      _updatePosition(selection);
+      updatePosition(selection);
     }
   }
 }
@@ -639,7 +639,9 @@
 
   @override
   void addSuggestions(LinkedEditSuggestionKind kind, Iterable<String> values) {
-    values.forEach((value) => addSuggestion(kind, value));
+    for (var value in values) {
+      addSuggestion(kind, value);
+    }
   }
 
   @override
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
index a884ea3..70b8e89 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
@@ -526,7 +526,7 @@
   static Token? _computeDroppedToken(
       AstNode containingNode, Object? entity, int offset) {
     // Find the last token of the member before the entity.
-    var previousMember;
+    SyntacticEntity? previousMember;
     for (var member in containingNode.childEntities) {
       if (entity == member) {
         break;
diff --git a/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart b/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart
index 728782a..2dfb787 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart
@@ -116,9 +116,9 @@
       declaredLocalVar(loopVariable.identifier, loopVariable.type);
     } else if (forLoopParts is ForPartsWithDeclarations) {
       var varList = forLoopParts.variables;
-      varList.variables.forEach((VariableDeclaration varDecl) {
+      for (var varDecl in varList.variables) {
         declaredLocalVar(varDecl.name, varList.type);
-      });
+      }
     }
     visitNode(node);
   }
@@ -131,9 +131,9 @@
       declaredLocalVar(loopVariable.identifier, loopVariable.type);
     } else if (forLoopParts is ForPartsWithDeclarations) {
       var varList = forLoopParts.variables;
-      varList.variables.forEach((VariableDeclaration varDecl) {
+      for (var varDecl in varList.variables) {
         declaredLocalVar(varDecl.name, varList.type);
-      });
+      }
     }
     visitNode(node);
   }
@@ -214,9 +214,9 @@
   void _visitClassOrMixinMembers(List<ClassMember> members) {
     for (var member in members) {
       if (member is FieldDeclaration) {
-        member.fields.variables.forEach((VariableDeclaration varDecl) {
+        for (var varDecl in member.fields.variables) {
           declaredField(member, varDecl);
-        });
+        }
       } else if (member is MethodDeclaration) {
         declaredMethod(member);
         _visitTypeParameters(member, member.typeParameters);
@@ -225,7 +225,7 @@
   }
 
   void _visitCompilationUnit(CompilationUnit node) {
-    node.declarations.forEach((Declaration declaration) {
+    for (var declaration in node.declarations) {
       if (declaration is ClassDeclaration) {
         declaredClass(declaration);
         _visitTypeParameters(declaration, declaration.typeParameters);
@@ -251,9 +251,9 @@
         );
       } else if (declaration is TopLevelVariableDeclaration) {
         var varList = declaration.variables;
-        varList.variables.forEach((VariableDeclaration varDecl) {
+        for (var varDecl in varList.variables) {
           declaredTopLevelVar(varList, varDecl);
-        });
+        }
       } else if (declaration is ClassTypeAlias) {
         declaredClassTypeAlias(declaration);
         _visitTypeParameters(declaration, declaration.typeParameters);
@@ -272,12 +272,12 @@
         declaredMixin(declaration);
         _visitTypeParameters(declaration, declaration.typeParameters);
       }
-    });
+    }
   }
 
   void _visitParamList(FormalParameterList? paramList) {
     if (paramList != null) {
-      paramList.parameters.forEach((FormalParameter param) {
+      for (var param in paramList.parameters) {
         NormalFormalParameter? normalParam;
         if (param is DefaultFormalParameter) {
           normalParam = param.parameter;
@@ -294,7 +294,7 @@
         }
         var name = param.identifier;
         declaredParam(name!, type);
-      });
+      }
     }
   }
 
diff --git a/pkg/analyzer_plugin/lib/utilities/fixes/fixes.dart b/pkg/analyzer_plugin/lib/utilities/fixes/fixes.dart
index 4971543..77592cb 100644
--- a/pkg/analyzer_plugin/lib/utilities/fixes/fixes.dart
+++ b/pkg/analyzer_plugin/lib/utilities/fixes/fixes.dart
@@ -114,7 +114,7 @@
   int get hashCode => id.hashCode;
 
   @override
-  bool operator ==(o) => o is FixKind && o.id == id;
+  bool operator ==(other) => other is FixKind && other.id == id;
 
   @override
   String toString() => id;
diff --git a/pkg/analyzer_plugin/pubspec.yaml b/pkg/analyzer_plugin/pubspec.yaml
index 11bb975..2b61963 100644
--- a/pkg/analyzer_plugin/pubspec.yaml
+++ b/pkg/analyzer_plugin/pubspec.yaml
@@ -19,6 +19,7 @@
 # See also https://dart.dev/tools/pub/dependencies.
 dev_dependencies:
   analyzer_utilities: any
+  lints: any
   meta: any
   path: any
   test_reflective_loader: any
diff --git a/pkg/analyzer_plugin/test/integration/support/integration_tests.dart b/pkg/analyzer_plugin/test/integration/support/integration_tests.dart
index 830140c..b71c0ae 100644
--- a/pkg/analyzer_plugin/test/integration/support/integration_tests.dart
+++ b/pkg/analyzer_plugin/test/integration/support/integration_tests.dart
@@ -447,6 +447,7 @@
         return;
       }
       _recordStdio('RECV: $trimmedLine');
+      // ignore: prefer_typing_uninitialized_variables
       var message;
       try {
         message = json.decoder.convert(trimmedLine);
diff --git a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
index 4d9d8e9..09bae68 100644
--- a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
@@ -2,6 +2,8 @@
 // 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.
 
+// ignore_for_file: camel_case_types
+
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
@@ -1743,7 +1745,7 @@
 
   Future<void> _assertWriteType(String typeCode, {String? declarations}) async {
     var path = convertPath('/home/test/lib/test.dart');
-    var content = (declarations ?? '') + '$typeCode v;';
+    var content = '${declarations ?? ''}$typeCode v;';
     addSource(path, content);
 
     var f = await _getTopLevelAccessorElement(path, 'v');
diff --git a/pkg/analyzer_plugin/test/src/utilities/change_builder/dart/import_library_element_test.dart b/pkg/analyzer_plugin/test/src/utilities/change_builder/dart/import_library_element_test.dart
index 7a9aef8..157e8ab 100644
--- a/pkg/analyzer_plugin/test/src/utilities/change_builder/dart/import_library_element_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/change_builder/dart/import_library_element_test.dart
@@ -2,6 +2,8 @@
 // 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.
 
+// ignore_for_file: camel_case_types
+
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
diff --git a/pkg/analyzer_plugin/test/utilities/range_factory_test.dart b/pkg/analyzer_plugin/test/utilities/range_factory_test.dart
index e3ffd03..6825c53 100644
--- a/pkg/analyzer_plugin/test/utilities/range_factory_test.dart
+++ b/pkg/analyzer_plugin/test/utilities/range_factory_test.dart
@@ -2,6 +2,8 @@
 // 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.
 
+// ignore_for_file: camel_case_types
+
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/source/source_range.dart';
 import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart b/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart
index cc470a3..aa38822 100644
--- a/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart
+++ b/pkg/analyzer_plugin/tool/spec/codegen_dart_protocol.dart
@@ -563,7 +563,7 @@
         for (var field in type.fields) {
           var fieldNameString = literalString(field.name);
           var fieldAccessor = 'json[$fieldNameString]';
-          var jsonPath = 'jsonPath + ${literalString('.${field.name}')}';
+          var jsonPath = literalString('\$jsonPath.${field.name}');
           if (field.value != null) {
             var valueString = literalString(field.value as String);
             writeln('if ($fieldAccessor != $valueString) {');
diff --git a/pkg/analyzer_plugin/tool/spec/codegen_protocol_constants.dart b/pkg/analyzer_plugin/tool/spec/codegen_protocol_constants.dart
index 611e583..40d6e68 100644
--- a/pkg/analyzer_plugin/tool/spec/codegen_protocol_constants.dart
+++ b/pkg/analyzer_plugin/tool/spec/codegen_protocol_constants.dart
@@ -103,14 +103,14 @@
     if (type == null) {
       return;
     }
-    type.fields.forEach((TypeObjectField field) {
+    for (var field in type.fields) {
       var name = field.name;
       var components = <String>[];
       components.add(parentName);
       components.addAll(_split(name));
       var fieldConstantName = _fromComponents(components);
       constants.add(_Constant(fieldConstantName, "'$name'"));
-    });
+    }
   }
 
   /// Return a name generated by converting each of the given [components] to an
diff --git a/pkg/dart2wasm/analysis_options.yaml b/pkg/dart2wasm/analysis_options.yaml
new file mode 100644
index 0000000..c36c2c5
--- /dev/null
+++ b/pkg/dart2wasm/analysis_options.yaml
@@ -0,0 +1 @@
+include: package:lints/core.yaml
diff --git a/pkg/dart2wasm/lib/closures.dart b/pkg/dart2wasm/lib/closures.dart
index 7929e21..221113c 100644
--- a/pkg/dart2wasm/lib/closures.dart
+++ b/pkg/dart2wasm/lib/closures.dart
@@ -293,7 +293,9 @@
     bool outerMost = currentContext == null;
     Context? oldContext = currentContext;
     Context? parent = currentContext;
-    while (parent != null && parent.isEmpty) parent = parent.parent;
+    while (parent != null && parent.isEmpty) {
+      parent = parent.parent;
+    }
     currentContext = Context(node, parent);
     if (closures.isThisCaptured && outerMost) {
       currentContext!.containsThis = true;
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 113b1bc..56dca65 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -357,7 +357,7 @@
   }
 
   void _implicitReturn() {
-    if (function.type.outputs.length > 0) {
+    if (function.type.outputs.isNotEmpty) {
       w.ValueType returnType = function.type.outputs[0];
       if (returnType is w.RefType && returnType.nullable) {
         // Dart body may have an implicit return null.
@@ -706,7 +706,9 @@
   }
 
   bool _hasLogicalOperator(Expression condition) {
-    while (condition is Not) condition = condition.operand;
+    while (condition is Not) {
+      condition = condition.operand;
+    }
     return condition is LogicalExpression;
   }
 
diff --git a/pkg/dart2wasm/lib/dispatch_table.dart b/pkg/dart2wasm/lib/dispatch_table.dart
index 06c6347..9817d7d 100644
--- a/pkg/dart2wasm/lib/dispatch_table.dart
+++ b/pkg/dart2wasm/lib/dispatch_table.dart
@@ -282,7 +282,9 @@
       selector.offset = offset;
       for (int classId in selector.classIds) {
         int entry = offset + classId;
-        while (table.length <= entry) table.add(null);
+        while (table.length <= entry) {
+          table.add(null);
+        }
         assert(table[entry] == null);
         table[entry] = selector.targets[classId];
       }
diff --git a/pkg/dart2wasm/lib/intrinsics.dart b/pkg/dart2wasm/lib/intrinsics.dart
index e4d3da9..f7b12e47 100644
--- a/pkg/dart2wasm/lib/intrinsics.dart
+++ b/pkg/dart2wasm/lib/intrinsics.dart
@@ -508,7 +508,7 @@
         code(b);
         return outType;
       }
-    } else if (node.arguments.positional.length == 0) {
+    } else if (node.arguments.positional.isEmpty) {
       // Unary operator
       Expression operand = node.receiver;
       w.ValueType opType = translator.translateType(receiverType);
@@ -1010,9 +1010,9 @@
       ClassInfo intInfo = translator.classInfo[translator.boxedIntClass]!;
       ClassInfo doubleInfo = translator.classInfo[translator.boxedDoubleClass]!;
       w.Local cid = function.addLocal(w.NumType.i32);
-      w.Label ref_eq = b.block();
+      w.Label refEq = b.block();
       b.local_get(first);
-      b.br_on_null(ref_eq);
+      b.br_on_null(refEq);
       b.struct_get(translator.topInfo.struct, FieldIndex.classId);
       b.local_tee(cid);
 
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index 50e7b0a..4fe9d4c 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -2,6 +2,8 @@
 // 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.
 
+// ignore_for_file: non_constant_identifier_names
+
 import 'dart:typed_data';
 
 import 'package:dart2wasm/class_info.dart';
@@ -540,7 +542,9 @@
   }
 
   w.ArrayType arrayTypeForDartType(DartType type) {
-    while (type is TypeParameterType) type = type.bound;
+    while (type is TypeParameterType) {
+      type = type.bound;
+    }
     return wasmArrayType(
         translateStorageType(type), type.toText(defaultAstTextStrategy));
   }
diff --git a/pkg/dart2wasm/pubspec.yaml b/pkg/dart2wasm/pubspec.yaml
index f4ed37e..a8cd88a 100644
--- a/pkg/dart2wasm/pubspec.yaml
+++ b/pkg/dart2wasm/pubspec.yaml
@@ -11,3 +11,7 @@
   kernel: any
   vm: any
   wasm_builder: any
+
+# Use 'any' constraints here; we get our versions from the DEPS file.
+dev_dependencies:
+  lints: any
diff --git a/pkg/expect/analysis_options.yaml b/pkg/expect/analysis_options.yaml
new file mode 100644
index 0000000..c36c2c5
--- /dev/null
+++ b/pkg/expect/analysis_options.yaml
@@ -0,0 +1 @@
+include: package:lints/core.yaml
diff --git a/pkg/expect/lib/expect.dart b/pkg/expect/lib/expect.dart
index e7413dd17..26ddcc0 100644
--- a/pkg/expect/lib/expect.dart
+++ b/pkg/expect/lib/expect.dart
@@ -2,10 +2,8 @@
 // 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.
 
-/**
- * This library contains an Expect class with static methods that can be used
- * for simple unit-tests.
- */
+/// This library contains an Expect class with static methods that can be used
+/// for simple unit-tests.
 library expect;
 
 import 'package:meta/meta.dart';
@@ -16,26 +14,22 @@
 /// Whether the program is running with sound null safety.
 bool get hasSoundNullSafety => !hasUnsoundNullSafety;
 
-/**
- * Expect is used for tests that do not want to make use of the
- * Dart unit test library - for example, the core language tests.
- * Third parties are discouraged from using this, and should use
- * the expect() function in the unit test library instead for
- * test assertions.
- */
+/// Expect is used for tests that do not want to make use of the
+/// Dart unit test library - for example, the core language tests.
+/// Third parties are discouraged from using this, and should use
+/// the expect() function in the unit test library instead for
+/// test assertions.
 class Expect {
-  /**
-   * Return a slice of a string.
-   *
-   * The slice will contain at least the substring from [start] to the lower of
-   * [end] and `start + length`.
-   * If the result is no more than `length - 10` characters long,
-   * context may be added by extending the range of the slice, by decreasing
-   * [start] and increasing [end], up to at most length characters.
-   * If the start or end of the slice are not matching the start or end of
-   * the string, ellipses are added before or after the slice.
-   * Characters other than printable ASCII are escaped.
-   */
+  /// Return a slice of a string.
+  ///
+  /// The slice will contain at least the substring from [start] to the lower of
+  /// [end] and `start + length`.
+  /// If the result is no more than `length - 10` characters long,
+  /// context may be added by extending the range of the slice, by decreasing
+  /// [start] and increasing [end], up to at most length characters.
+  /// If the start or end of the slice are not matching the start or end of
+  /// the string, ellipses are added before or after the slice.
+  /// Characters other than printable ASCII are escaped.
   static String _truncateString(String string, int start, int end, int length) {
     if (end - start > length) {
       end = start + length;
@@ -48,7 +42,7 @@
       if (start < 0) start = 0;
       if (end > string.length) end = string.length;
     }
-    StringBuffer buf = new StringBuffer();
+    StringBuffer buf = StringBuffer();
     if (start > 0) buf.write("...");
     _escapeSubstring(buf, string, 0, string.length);
     if (end < string.length) buf.write("...");
@@ -58,7 +52,7 @@
   /// Return the string with characters that are not printable ASCII characters
   /// escaped as either "\xXX" codes or "\uXXXX" codes.
   static String _escapeString(String string) {
-    StringBuffer buf = new StringBuffer();
+    StringBuffer buf = StringBuffer();
     _escapeSubstring(buf, string, 0, string.length);
     return buf.toString();
   }
@@ -85,16 +79,14 @@
     }
   }
 
-  /**
-   * Find the difference between two strings.
-   *
-   * This finds the first point where two strings differ, and returns
-   * a text describing the difference.
-   *
-   * For small strings (length less than 20) nothing is done, and "" is
-   * returned. Small strings can be compared visually, but for longer strings
-   * only a slice containing the first difference will be shown.
-   */
+  /// Find the difference between two strings.
+  ///
+  /// This finds the first point where two strings differ, and returns
+  /// a text describing the difference.
+  ///
+  /// For small strings (length less than 20) nothing is done, and "" is
+  /// returned. Small strings can be compared visually, but for longer strings
+  /// only a slice containing the first difference will be shown.
   static String _stringDifference(String expected, String actual) {
     if (expected.length < 20 && actual.length < 20) return "";
     for (int i = 0; i < expected.length && i < actual.length; i++) {
@@ -115,9 +107,7 @@
     return "";
   }
 
-  /**
-   * Checks whether the expected and actual values are equal (using `==`).
-   */
+  /// Checks whether the expected and actual values are equal (using `==`).
   static void equals(dynamic expected, dynamic actual, [String reason = ""]) {
     if (expected == actual) return;
     String msg = _getMessage(reason);
@@ -132,64 +122,50 @@
     _fail("Expect.equals(expected: <$expected>, actual: <$actual>$msg) fails.");
   }
 
-  /**
-   * Checks whether the actual value is a bool and its value is true.
-   */
+  /// Checks whether the actual value is a bool and its value is true.
   static void isTrue(dynamic actual, [String reason = ""]) {
     if (_identical(actual, true)) return;
     String msg = _getMessage(reason);
     _fail("Expect.isTrue($actual$msg) fails.");
   }
 
-  /**
-   * Checks whether the actual value is a bool and its value is false.
-   */
+  /// Checks whether the actual value is a bool and its value is false.
   static void isFalse(dynamic actual, [String reason = ""]) {
     if (_identical(actual, false)) return;
     String msg = _getMessage(reason);
     _fail("Expect.isFalse($actual$msg) fails.");
   }
 
-  /**
-   * Checks whether [actual] is null.
-   */
+  /// Checks whether [actual] is null.
   static void isNull(dynamic actual, [String reason = ""]) {
     if (null == actual) return;
     String msg = _getMessage(reason);
     _fail("Expect.isNull(actual: <$actual>$msg) fails.");
   }
 
-  /**
-   * Checks whether [actual] is not null.
-   */
+  /// Checks whether [actual] is not null.
   static void isNotNull(dynamic actual, [String reason = ""]) {
     if (null != actual) return;
     String msg = _getMessage(reason);
     _fail("Expect.isNotNull(actual: <$actual>$msg) fails.");
   }
 
-  /**
-   * Checks whether the Iterable [actual] is empty.
-   */
+  /// Checks whether the Iterable [actual] is empty.
   static void isEmpty(Iterable actual, [String reason = ""]) {
     if (actual.isEmpty) return;
     String msg = _getMessage(reason);
     _fail("Expect.isEmpty(actual: <$actual>$msg) fails.");
   }
 
-  /**
-   * Checks whether the Iterable [actual] is not empty.
-   */
+  /// Checks whether the Iterable [actual] is not empty.
   static void isNotEmpty(Iterable actual, [String reason = ""]) {
     if (actual.isNotEmpty) return;
     String msg = _getMessage(reason);
     _fail("Expect.isNotEmpty(actual: <$actual>$msg) fails.");
   }
 
-  /**
-   * Checks whether the expected and actual values are identical
-   * (using `identical`).
-   */
+  /// Checks whether the expected and actual values are identical
+  /// (using `identical`).
   static void identical(dynamic expected, dynamic actual,
       [String reason = ""]) {
     if (_identical(expected, actual)) return;
@@ -205,17 +181,15 @@
         "fails.");
   }
 
-  /**
-   * Finds equivalence classes of objects (by index) wrt. identity.
-   *
-   * Returns a list of lists of identical object indices per object.
-   * That is, `objects[i]` is identical to objects with indices in
-   * `_findEquivalences(objects)[i]`.
-   *
-   * Uses `[]` for objects that are only identical to themselves.
-   */
+  /// Finds equivalence classes of objects (by index) wrt. identity.
+  ///
+  /// Returns a list of lists of identical object indices per object.
+  /// That is, `objects[i]` is identical to objects with indices in
+  /// `_findEquivalences(objects)[i]`.
+  ///
+  /// Uses `[]` for objects that are only identical to themselves.
   static List<List<int>> _findEquivalences(List<dynamic> objects) {
-    var equivalences = new List<List<int>>.generate(objects.length, (_) => []);
+    var equivalences = List<List<int>>.generate(objects.length, (_) => []);
     for (int i = 0; i < objects.length; i++) {
       if (equivalences[i].isNotEmpty) continue;
       var o = objects[i];
@@ -261,7 +235,7 @@
     var equivalences = _findEquivalences(objects);
     var first = equivalences[0];
     if (first.isNotEmpty && first.length == objects.length) return;
-    var buffer = new StringBuffer("Expect.allIdentical([");
+    var buffer = StringBuffer("Expect.allIdentical([");
     _writeEquivalences(objects, equivalences, buffer);
     buffer
       ..write("]")
@@ -270,19 +244,15 @@
     _fail(buffer.toString());
   }
 
-  /**
-   * Checks whether the expected and actual values are *not* identical
-   * (using `identical`).
-   */
+  /// Checks whether the expected and actual values are *not* identical
+  /// (using `identical`).
   static void notIdentical(var unexpected, var actual, [String reason = ""]) {
     if (!_identical(unexpected, actual)) return;
     String msg = _getMessage(reason);
     _fail("Expect.notIdentical(expected and actual: <$actual>$msg) fails.");
   }
 
-  /**
-   * Checks that no two [objects] are `identical`.
-   */
+  /// Checks that no two [objects] are `identical`.
   static void allDistinct(List<dynamic> objects, [String reason = ""]) {
     String msg = _getMessage(reason);
     var equivalences = _findEquivalences(objects);
@@ -295,7 +265,7 @@
       }
     }
     if (!hasEquivalence) return;
-    var buffer = new StringBuffer("Expect.allDistinct([");
+    var buffer = StringBuffer("Expect.allDistinct([");
     _writeEquivalences(objects, equivalences, buffer);
     buffer
       ..write("]")
@@ -310,11 +280,9 @@
     _fail("Expect.fail('$msg')");
   }
 
-  /**
-   * Failure if the difference between expected and actual is greater than the
-   * given tolerance. If no tolerance is given, tolerance is assumed to be the
-   * value 4 significant digits smaller than the value given for expected.
-   */
+  /// Failure if the difference between expected and actual is greater than the
+  /// given tolerance. If no tolerance is given, tolerance is assumed to be the
+  /// value 4 significant digits smaller than the value given for expected.
   static void approxEquals(num expected, num actual,
       [num tolerance = -1, String reason = ""]) {
     if (tolerance < 0) {
@@ -335,12 +303,10 @@
         "fails.");
   }
 
-  /**
-   * Checks that all elements in [expected] and [actual] are equal `==`.
-   * This is different than the typical check for identity equality `identical`
-   * used by the standard list implementation.  It should also produce nicer
-   * error messages than just calling `Expect.equals(expected, actual)`.
-   */
+  /// Checks that all elements in [expected] and [actual] are equal `==`.
+  /// This is different than the typical check for identity equality `identical`
+  /// used by the standard list implementation.  It should also produce nicer
+  /// error messages than just calling `Expect.equals(expected, actual)`.
   static void listEquals(List expected, List actual, [String reason = ""]) {
     String msg = _getMessage(reason);
     int n = (expected.length < actual.length) ? expected.length : actual.length;
@@ -360,11 +326,9 @@
     }
   }
 
-  /**
-   * Checks that all [expected] and [actual] have the same set of keys (using
-   * the semantics of [Map.containsKey] to determine what "same" means. For
-   * each key, checks that the values in both maps are equal using `==`.
-   */
+  /// Checks that all [expected] and [actual] have the same set of keys (using
+  /// the semantics of [Map.containsKey] to determine what "same" means. For
+  /// each key, checks that the values in both maps are equal using `==`.
   static void mapEquals(Map expected, Map actual, [String reason = ""]) {
     String msg = _getMessage(reason);
 
@@ -385,10 +349,8 @@
     }
   }
 
-  /**
-   * Specialized equality test for strings. When the strings don't match,
-   * this method shows where the mismatch starts and ends.
-   */
+  /// Specialized equality test for strings. When the strings don't match,
+  /// this method shows where the mismatch starts and ends.
   static void stringEquals(String expected, String actual,
       [String reason = ""]) {
     if (expected == actual) return;
@@ -506,23 +468,21 @@
     }
   }
 
-  /**
-   * Checks that every element of [expected] is also in [actual], and that
-   * every element of [actual] is also in [expected].
-   */
+  /// Checks that every element of [expected] is also in [actual], and that
+  /// every element of [actual] is also in [expected].
   static void setEquals(Iterable expected, Iterable actual,
       [String reason = ""]) {
-    final missingSet = new Set.from(expected);
+    final missingSet = Set.from(expected);
     missingSet.removeAll(actual);
-    final extraSet = new Set.from(actual);
+    final extraSet = Set.from(actual);
     extraSet.removeAll(expected);
 
     if (extraSet.isEmpty && missingSet.isEmpty) return;
     String msg = _getMessage(reason);
 
-    StringBuffer sb = new StringBuffer("Expect.setEquals($msg) fails");
+    StringBuffer sb = StringBuffer("Expect.setEquals($msg) fails");
     // Report any missing items.
-    if (!missingSet.isEmpty) {
+    if (missingSet.isNotEmpty) {
       sb.write('\nExpected collection does not contain: ');
     }
 
@@ -531,7 +491,7 @@
     }
 
     // Report any extra items.
-    if (!extraSet.isEmpty) {
+    if (extraSet.isNotEmpty) {
       sb.write('\nExpected collection should not contain: ');
     }
 
@@ -541,11 +501,9 @@
     _fail(sb.toString());
   }
 
-  /**
-   * Checks that [expected] is equivalent to [actual].
-   *
-   * If the objects are iterables or maps, recurses into them.
-   */
+  /// Checks that [expected] is equivalent to [actual].
+  ///
+  /// If the objects are iterables or maps, recurses into them.
   static void deepEquals(dynamic expected, dynamic actual) {
     // Early exit check for equality.
     if (expected == actual) return;
@@ -595,30 +553,28 @@
 
   static bool _defaultCheck([dynamic _]) => true;
 
-  /**
-   * Verifies that [computation] throws a [T].
-   *
-   * Calls the [computation] function and fails if that call doesn't throw,
-   * throws something which is not a [T], or throws a [T] which does not
-   * satisfy the optional [check] function.
-   *
-   * Returns the accepted thrown [T] object, if one is caught.
-   * This value can be checked further, instead of checking it in the [check]
-   * function. For example, to check the content of the thrown object,
-   * you could write this:
-   * ```
-   * var e = Expect.throws<MyException>(myThrowingFunction);
-   * Expect.isTrue(e.myMessage.contains("WARNING"));
-   * ```
-   * The type variable can be omitted, in which case it defaults to [Object],
-   * and the (sub-)type of the object can be checked in [check] instead.
-   * This was traditionally done before Dart had generic methods.
-   *
-   * If `computation` fails another test expectation
-   * (i.e., throws an [ExpectException]),
-   * that exception cannot be caught and accepted by [Expect.throws].
-   * The test is still considered failing.
-   */
+  /// Verifies that [computation] throws a [T].
+  ///
+  /// Calls the [computation] function and fails if that call doesn't throw,
+  /// throws something which is not a [T], or throws a [T] which does not
+  /// satisfy the optional [check] function.
+  ///
+  /// Returns the accepted thrown [T] object, if one is caught.
+  /// This value can be checked further, instead of checking it in the [check]
+  /// function. For example, to check the content of the thrown object,
+  /// you could write this:
+  /// ```
+  /// var e = Expect.throws<MyException>(myThrowingFunction);
+  /// Expect.isTrue(e.myMessage.contains("WARNING"));
+  /// ```
+  /// The type variable can be omitted, in which case it defaults to [Object],
+  /// and the (sub-)type of the object can be checked in [check] instead.
+  /// This was traditionally done before Dart had generic methods.
+  ///
+  /// If `computation` fails another test expectation
+  /// (i.e., throws an [ExpectException]),
+  /// that exception cannot be caught and accepted by [Expect.throws].
+  /// The test is still considered failing.
   static T throws<T extends Object>(void Function() computation,
       [bool Function(T error)? check, String? reason]) {
     // TODO(vsm): Make check and reason nullable or change call sites.
@@ -739,7 +695,7 @@
 
   @alwaysThrows
   static Never _fail(String message) {
-    throw new ExpectException(message);
+    throw ExpectException(message);
   }
 }
 
diff --git a/pkg/expect/lib/minitest.dart b/pkg/expect/lib/minitest.dart
index 0021ada..9368dc6 100644
--- a/pkg/expect/lib/minitest.dart
+++ b/pkg/expect/lib/minitest.dart
@@ -25,17 +25,17 @@
 
 import 'package:expect/expect.dart';
 
-typedef dynamic _Action();
-typedef void _ExpectationFunction(dynamic actual);
+typedef _Action = dynamic Function();
+typedef _ExpectationFunction = void Function(dynamic actual);
 
-final List<_Group> _groups = [new _Group()];
+final List<_Group> _groups = [_Group()];
 
-final Object isFalse = new _Expectation(Expect.isFalse);
-final Object isNotNull = new _Expectation(Expect.isNotNull);
-final Object isNull = new _Expectation(Expect.isNull);
-final Object isTrue = new _Expectation(Expect.isTrue);
+final Object isFalse = _Expectation(Expect.isFalse);
+final Object isNotNull = _Expectation(Expect.isNotNull);
+final Object isNull = _Expectation(Expect.isNull);
+final Object isTrue = _Expectation(Expect.isTrue);
 
-final Object returnsNormally = new _Expectation((actual) {
+final Object returnsNormally = _Expectation((actual) {
   try {
     (actual as _Action)();
   } catch (error) {
@@ -43,39 +43,39 @@
   }
 });
 
-final Object throws = new _Expectation((actual) {
+final Object throws = _Expectation((actual) {
   Expect.throws(actual as _Action);
 });
 
-final Object throwsArgumentError = new _Expectation((actual) {
+final Object throwsArgumentError = _Expectation((actual) {
   Expect.throws(actual as _Action, (error) => error is ArgumentError);
 });
 
-final Object throwsNoSuchMethodError = new _Expectation((actual) {
+final Object throwsNoSuchMethodError = _Expectation((actual) {
   Expect.throws(actual as _Action, (error) => error is NoSuchMethodError);
 });
 
-final Object throwsRangeError = new _Expectation((actual) {
+final Object throwsRangeError = _Expectation((actual) {
   Expect.throws(actual as _Action, (error) => error is RangeError);
 });
 
-final Object throwsStateError = new _Expectation((actual) {
+final Object throwsStateError = _Expectation((actual) {
   Expect.throws(actual as _Action, (error) => error is StateError);
 });
 
-final Object throwsUnsupportedError = new _Expectation((actual) {
+final Object throwsUnsupportedError = _Expectation((actual) {
   Expect.throws(actual as _Action, (error) => error is UnsupportedError);
 });
 
 /// The test runner should call this once after running a test file.
 void finishTests() {
   _groups.clear();
-  _groups.add(new _Group());
+  _groups.add(_Group());
 }
 
 void group(String description, body()) {
   // TODO(rnystrom): Do something useful with the description.
-  _groups.add(new _Group());
+  _groups.add(_Group());
 
   try {
     var result = body();
@@ -138,48 +138,48 @@
   Expect.fail(message);
 }
 
-Object equals(dynamic value) => new _Expectation((actual) {
+Object equals(dynamic value) => _Expectation((actual) {
       Expect.deepEquals(value, actual);
     });
 
-Object notEquals(dynamic value) => new _Expectation((actual) {
+Object notEquals(dynamic value) => _Expectation((actual) {
       Expect.notEquals(value, actual);
     });
 
-Object unorderedEquals(dynamic value) => new _Expectation((actual) {
+Object unorderedEquals(dynamic value) => _Expectation((actual) {
       Expect.setEquals(value as Iterable, actual as Iterable);
     });
 
 Object predicate(bool fn(dynamic value), [String description = ""]) =>
-    new _Expectation((actual) {
+    _Expectation((actual) {
       Expect.isTrue(fn(actual), description);
     });
 
-Object inInclusiveRange(num min, num max) => new _Expectation((actual) {
+Object inInclusiveRange(num min, num max) => _Expectation((actual) {
       var actualNum = actual as num;
       if (actualNum < min || actualNum > max) {
         fail("Expected $actualNum to be in the inclusive range [$min, $max].");
       }
     });
 
-Object greaterThan(num value) => new _Expectation((actual) {
+Object greaterThan(num value) => _Expectation((actual) {
       var actualNum = actual as num;
       if (actualNum <= value) {
         fail("Expected $actualNum to be greater than $value.");
       }
     });
 
-Object same(dynamic value) => new _Expectation((actual) {
+Object same(dynamic value) => _Expectation((actual) {
       Expect.identical(value, actual);
     });
 
-Object closeTo(num value, num tolerance) => new _Expectation((actual) {
+Object closeTo(num value, num tolerance) => _Expectation((actual) {
       Expect.approxEquals(value, actual as num, tolerance);
     });
 
 /// Succeeds if the actual value is any of the given strings. Unlike matcher's
 /// [anyOf], this only works with strings and requires an explicit list.
-Object anyOf(List<String> expected) => new _Expectation((actual) {
+Object anyOf(List<String> expected) => _Expectation((actual) {
       for (var string in expected) {
         if (actual == string) return;
       }
diff --git a/pkg/expect/pubspec.yaml b/pkg/expect/pubspec.yaml
index 5f045c2..96dd1ea 100644
--- a/pkg/expect/pubspec.yaml
+++ b/pkg/expect/pubspec.yaml
@@ -15,3 +15,7 @@
 dependencies:
   meta: any
   smith: any
+
+# Use 'any' constraints here; we get our versions from the DEPS file.
+dev_dependencies:
+  lints: any
diff --git a/pkg/expect/test/distinct_test.dart b/pkg/expect/test/distinct_test.dart
index 5750782..78dd0cf 100644
--- a/pkg/expect/test/distinct_test.dart
+++ b/pkg/expect/test/distinct_test.dart
@@ -5,11 +5,11 @@
 import "package:expect/expect.dart";
 
 main() {
-  var o1 = new Object();
-  var o2 = new Object();
-  var o3 = new Object();
-  var c1 = new C(0);
-  var c2 = new C(0);
+  var o1 = Object();
+  var o2 = Object();
+  var o3 = Object();
+  var c1 = C(0);
+  var c2 = C(0);
 
   // Successful checks.
   Expect.notIdentical(o1, o2, "msg");
@@ -28,7 +28,7 @@
     c2,
     [1]
   ], "msg");
-  Expect.allDistinct(new List.generate(100, (_) => new Object()));
+  Expect.allDistinct(List.generate(100, (_) => Object()));
 
   fails((msg) {
     Expect.notIdentical(o1, o1, msg);
@@ -64,14 +64,14 @@
     Expect.allDistinct([o1, o2, o3, o3], msg);
   });
   fails((msg) {
-    var list = new List.generate(100, (_) => new Object());
+    var list = List.generate(100, (_) => Object());
     list.add(list[0]);
     Expect.allDistinct(list, msg);
   });
 }
 
 class C {
-  final x;
+  final Object x;
   const C(this.x);
   int get hashCode => x.hashCode;
   bool operator ==(Object other) => other is C && x == other.x;
diff --git a/pkg/meta/analysis_options.yaml b/pkg/meta/analysis_options.yaml
new file mode 100644
index 0000000..572dd23
--- /dev/null
+++ b/pkg/meta/analysis_options.yaml
@@ -0,0 +1 @@
+include: package:lints/recommended.yaml
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index ba14be9..076f2c9 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -2,6 +2,8 @@
 // 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.
 
+// ignore_for_file: library_private_types_in_public_api
+
 /// Annotations that developers can use to express the intentions that otherwise
 /// can't be deduced by statically analyzing the source code.
 ///
diff --git a/pkg/meta/pubspec.yaml b/pkg/meta/pubspec.yaml
index 4c5deeb..b621828 100644
--- a/pkg/meta/pubspec.yaml
+++ b/pkg/meta/pubspec.yaml
@@ -8,3 +8,10 @@
 
 environment:
   sdk: ">=2.12.0 <3.0.0"
+
+# We use 'any' version constraints here as we get our package versions from
+# the dart-lang/sdk repo's DEPS file. Note that this is a special case; the
+# best practice for packages is to specify their compatible version ranges.
+# See also https://dart.dev/tools/pub/dependencies.
+dev_dependencies:
+  lints: any
diff --git a/pkg/modular_test/analysis_options.yaml b/pkg/modular_test/analysis_options.yaml
new file mode 100644
index 0000000..c36c2c5
--- /dev/null
+++ b/pkg/modular_test/analysis_options.yaml
@@ -0,0 +1 @@
+include: package:lints/core.yaml
diff --git a/pkg/modular_test/lib/src/generic_runner.dart b/pkg/modular_test/lib/src/generic_runner.dart
index fe2a85f..30d903c 100644
--- a/pkg/modular_test/lib/src/generic_runner.dart
+++ b/pkg/modular_test/lib/src/generic_runner.dart
@@ -107,8 +107,8 @@
       continue;
     }
 
-    var watch = new Stopwatch()..start();
-    var outcome = new _TestOutcome(test.name);
+    var watch = Stopwatch()..start();
+    var outcome = _TestOutcome(test.name);
     try {
       await test.run();
       if (options.verbose) stdout.write('pass\n');
diff --git a/pkg/modular_test/lib/src/io_pipeline.dart b/pkg/modular_test/lib/src/io_pipeline.dart
index 5a1066e..fa49508 100644
--- a/pkg/modular_test/lib/src/io_pipeline.dart
+++ b/pkg/modular_test/lib/src/io_pipeline.dart
@@ -58,9 +58,9 @@
   final bool saveIntermediateResultsForTesting;
 
   IOPipeline(List<IOModularStep> steps,
-      {this.saveIntermediateResultsForTesting: false,
-      bool cacheSharedModules: false})
-      : _registry = cacheSharedModules ? new ConfigurationRegistry() : null,
+      {this.saveIntermediateResultsForTesting = false,
+      bool cacheSharedModules = false})
+      : _registry = cacheSharedModules ? ConfigurationRegistry() : null,
         super(steps, cacheSharedModules);
 
   @override
@@ -156,7 +156,7 @@
   }
 
   String _toFileName(Module module, DataId dataId,
-      {bool configSpecific: false}) {
+      {bool configSpecific = false}) {
     var prefix =
         cacheSharedModules && configSpecific && _currentConfiguration != null
             ? _currentConfiguration
diff --git a/pkg/modular_test/lib/src/loader.dart b/pkg/modular_test/lib/src/loader.dart
index f846a41..04800396 100644
--- a/pkg/modular_test/lib/src/loader.dart
+++ b/pkg/modular_test/lib/src/loader.dart
@@ -112,7 +112,7 @@
   var sortedModules = modules.values.toList()
     ..sort((a, b) => a.name.compareTo(b.name));
   var sortedFlags = spec.flags.toList()..sort();
-  return new ModularTest(sortedModules, mainModule, sortedFlags);
+  return ModularTest(sortedModules, mainModule, sortedFlags);
 }
 
 /// Returns all source files recursively found in a folder as relative URIs.
@@ -202,7 +202,7 @@
       }
     }
   }
-  sources..sort((a, b) => a.path.compareTo(b.path));
+  sources.sort((a, b) => a.path.compareTo(b.path));
   return Module('sdk', [], root, sources, isSdk: true, isShared: true);
 }
 
@@ -267,7 +267,7 @@
 }
 
 Never _invalidTest(String message) {
-  throw new InvalidTestError(message);
+  throw InvalidTestError(message);
 }
 
 class InvalidTestError extends Error {
diff --git a/pkg/modular_test/lib/src/memory_pipeline.dart b/pkg/modular_test/lib/src/memory_pipeline.dart
index 13025aa..8100440 100644
--- a/pkg/modular_test/lib/src/memory_pipeline.dart
+++ b/pkg/modular_test/lib/src/memory_pipeline.dart
@@ -36,8 +36,8 @@
   final List<Map<Module, Map<DataId, Object>>> _resultCache;
 
   MemoryPipeline(this._sources, List<MemoryModularStep> steps,
-      {bool cacheSharedModules: false})
-      : _registry = cacheSharedModules ? new ConfigurationRegistry() : null,
+      {bool cacheSharedModules = false})
+      : _registry = cacheSharedModules ? ConfigurationRegistry() : null,
         _resultCache = cacheSharedModules ? [] : const [],
         super(steps, cacheSharedModules);
 
diff --git a/pkg/modular_test/lib/src/pipeline.dart b/pkg/modular_test/lib/src/pipeline.dart
index 16377b8..dee4a68 100644
--- a/pkg/modular_test/lib/src/pipeline.dart
+++ b/pkg/modular_test/lib/src/pipeline.dart
@@ -49,13 +49,13 @@
   final bool notOnSdk;
 
   ModularStep(
-      {this.needsSources: true,
-      this.dependencyDataNeeded: const [],
-      this.moduleDataNeeded: const [],
-      this.resultData: const [],
-      this.onlyOnMain: false,
-      this.onlyOnSdk: false,
-      this.notOnSdk: false});
+      {this.needsSources = true,
+      this.dependencyDataNeeded = const [],
+      this.moduleDataNeeded = const [],
+      this.resultData = const [],
+      this.onlyOnMain = false,
+      this.onlyOnSdk = false,
+      this.notOnSdk = false});
 
   /// Notifies that the step was not executed, but cached instead.
   void notifyCached(Module module) {}
diff --git a/pkg/modular_test/lib/src/runner.dart b/pkg/modular_test/lib/src/runner.dart
index 916f002..4c01c05 100644
--- a/pkg/modular_test/lib/src/runner.dart
+++ b/pkg/modular_test/lib/src/runner.dart
@@ -20,13 +20,13 @@
     IOPipeline pipeline) async {
   var dir = Directory.fromUri(suiteFolder);
   var entries = (await dir.list(recursive: false).toList())
-      .where((e) => e is Directory)
-      .map((e) => new _PipelineTest(e.uri, suiteFolder, options, pipeline))
+      .whereType<Directory>()
+      .map((e) => _PipelineTest(e.uri, suiteFolder, options, pipeline))
       .toList();
 
   await generic.runSuite(
       entries,
-      new generic.RunnerOptions(
+      generic.RunnerOptions(
           suiteName: suiteName,
           configurationName: options.configurationName,
           filter: options.filter,
@@ -67,7 +67,7 @@
   bool useSdk = false;
 
   static Options parse(List<String> args) {
-    var parser = new ArgParser()
+    var parser = ArgParser()
       ..addFlag('verbose',
           abbr: 'v',
           defaultsTo: false,
diff --git a/pkg/modular_test/lib/src/suite.dart b/pkg/modular_test/lib/src/suite.dart
index 2821b97..2ed0798 100644
--- a/pkg/modular_test/lib/src/suite.dart
+++ b/pkg/modular_test/lib/src/suite.dart
@@ -66,11 +66,11 @@
 
   Module(this.name, this.dependencies, this.rootUri, this.sources,
       {this.mainSource,
-      this.isPackage: false,
-      this.isMain: false,
+      this.isPackage = false,
+      this.isMain = false,
       this.packageBase,
-      this.isShared: false,
-      this.isSdk: false}) {
+      this.isShared = false,
+      this.isSdk = false}) {
     if (!_validModuleName.hasMatch(name)) {
       throw ArgumentError("invalid module name: $name");
     }
@@ -114,7 +114,7 @@
   String toString() => '[module $name]';
 
   String debugString() {
-    var buffer = new StringBuffer();
+    var buffer = StringBuffer();
     buffer.write('   ');
     buffer.write(name);
     buffer.write(': ');
@@ -129,7 +129,7 @@
   }
 }
 
-final RegExp _validModuleName = new RegExp(r'^[a-zA-Z_][a-zA-Z0-9_]*$');
+final RegExp _validModuleName = RegExp(r'^[a-zA-Z_][a-zA-Z0-9_]*$');
 
 /// Helper to compute transitive dependencies from [module].
 Set<Module> computeTransitiveDependencies(Module module) {
diff --git a/pkg/modular_test/lib/src/test_specification_parser.dart b/pkg/modular_test/lib/src/test_specification_parser.dart
index 2253df8..1a007d6 100644
--- a/pkg/modular_test/lib/src/test_specification_parser.dart
+++ b/pkg/modular_test/lib/src/test_specification_parser.dart
@@ -108,8 +108,7 @@
       _invalidSpecification("packages is not a map");
     }
   }
-  return new TestSpecification(
-      normalizedFlags, normalizedMap, normalizedPackages);
+  return TestSpecification(normalizedFlags, normalizedMap, normalizedPackages);
 }
 
 /// Data specifying details about a modular test including dependencies and
@@ -139,7 +138,7 @@
 }
 
 _invalidSpecification(String message) {
-  throw new InvalidSpecificationError(message);
+  throw InvalidSpecificationError(message);
 }
 
 class InvalidSpecificationError extends Error {
diff --git a/pkg/modular_test/pubspec.yaml b/pkg/modular_test/pubspec.yaml
index 1a20237..8292fc7 100644
--- a/pkg/modular_test/pubspec.yaml
+++ b/pkg/modular_test/pubspec.yaml
@@ -19,4 +19,5 @@
 dev_dependencies:
   async_helper: any
   expect: any
+  lints: any
   test: any
diff --git a/pkg/modular_test/test/io_pipeline_test.dart b/pkg/modular_test/test/io_pipeline_test.dart
index 46cbaf9..af83b9f 100644
--- a/pkg/modular_test/test/io_pipeline_test.dart
+++ b/pkg/modular_test/test/io_pipeline_test.dart
@@ -16,7 +16,7 @@
     uri = Directory.systemTemp.uri.resolve("io_modular_test_root$i/");
     i++;
   }
-  runPipelineTest(new IOPipelineTestStrategy(uri));
+  runPipelineTest(IOPipelineTestStrategy(uri));
 }
 
 /// The strategy implementation to exercise the pipeline test on a
@@ -30,14 +30,14 @@
   @override
   Future<Pipeline<IOModularStep>> createPipeline(
       Map<Uri, String> sources, List<IOModularStep> steps,
-      {bool cacheSharedModules: false}) async {
+      {bool cacheSharedModules = false}) async {
     await Directory.fromUri(testRootUri).create();
     for (var uri in sources.keys) {
-      var file = new File.fromUri(uri);
+      var file = File.fromUri(uri);
       await file.create(recursive: true);
       file.writeAsStringSync(sources[uri]!);
     }
-    return new IOPipeline(steps,
+    return IOPipeline(steps,
         saveIntermediateResultsForTesting: true,
         cacheSharedModules: cacheSharedModules);
   }
@@ -46,7 +46,7 @@
   IOModularStep createSourceOnlyStep(
           {required String Function(Map<Uri, String?>) action,
           required DataId resultId,
-          bool requestSources: true}) =>
+          bool requestSources = true}) =>
       SourceOnlyStep(action, resultId, requestSources);
 
   @override
@@ -54,7 +54,7 @@
           {required String Function(String) action,
           required DataId inputId,
           required DataId resultId,
-          bool requestModuleData: true}) =>
+          bool requestModuleData = true}) =>
       ModuleDataStep(action, inputId, resultId, requestModuleData);
 
   @override
@@ -63,7 +63,7 @@
           required DataId inputId,
           required DataId depId,
           required DataId resultId,
-          bool requestDependenciesData: true}) =>
+          bool requestDependenciesData = true}) =>
       LinkStep(action, inputId, depId, resultId, requestDependenciesData);
 
   @override
@@ -72,7 +72,7 @@
           required DataId inputId,
           required DataId depId,
           required DataId resultId,
-          bool requestDependenciesData: true}) =>
+          bool requestDependenciesData = true}) =>
       MainOnlyStep(action, inputId, depId, resultId, requestDependenciesData);
 
   @override
diff --git a/pkg/modular_test/test/loader/loader_test.dart b/pkg/modular_test/test/loader/loader_test.dart
index 8fadfef..395b4b7 100644
--- a/pkg/modular_test/test/loader/loader_test.dart
+++ b/pkg/modular_test/test/loader/loader_test.dart
@@ -59,7 +59,7 @@
 }
 
 String _dumpAsText(ModularTest test) {
-  var buffer = new StringBuffer();
+  var buffer = StringBuffer();
   bool isFirst = true;
   for (var module in test.modules) {
     if (isFirst) {
@@ -103,7 +103,7 @@
   String? filter;
 
   static _Options parse(List<String> args) {
-    var parser = new ArgParser()
+    var parser = ArgParser()
       ..addFlag('update',
           abbr: 'u',
           defaultsTo: false,
diff --git a/pkg/modular_test/test/memory_pipeline_test.dart b/pkg/modular_test/test/memory_pipeline_test.dart
index 894ee21..cc145cf 100644
--- a/pkg/modular_test/test/memory_pipeline_test.dart
+++ b/pkg/modular_test/test/memory_pipeline_test.dart
@@ -10,7 +10,7 @@
 import 'pipeline_common.dart';
 
 main() {
-  runPipelineTest(new MemoryPipelineTestStrategy());
+  runPipelineTest(MemoryPipelineTestStrategy());
 }
 
 /// The strategy implementation to exercise the pipeline test on a
@@ -23,8 +23,8 @@
   @override
   FutureOr<Pipeline<MemoryModularStep>> createPipeline(
       Map<Uri, String> sources, List<MemoryModularStep> steps,
-      {bool cacheSharedModules: false}) {
-    return new MemoryPipeline(sources, steps,
+      {bool cacheSharedModules = false}) {
+    return MemoryPipeline(sources, steps,
         cacheSharedModules: cacheSharedModules);
   }
 
@@ -32,7 +32,7 @@
   MemoryModularStep createSourceOnlyStep(
           {required String Function(Map<Uri, String?>) action,
           required DataId resultId,
-          bool requestSources: true}) =>
+          bool requestSources = true}) =>
       SourceOnlyStep(action, resultId, requestSources);
 
   @override
@@ -40,7 +40,7 @@
           {required String Function(String) action,
           required DataId inputId,
           required DataId resultId,
-          bool requestModuleData: true}) =>
+          bool requestModuleData = true}) =>
       ModuleDataStep(action, inputId, resultId, requestModuleData);
 
   @override
@@ -49,7 +49,7 @@
           required DataId inputId,
           required DataId depId,
           required DataId resultId,
-          bool requestDependenciesData: true}) =>
+          bool requestDependenciesData = true}) =>
       LinkStep(action, inputId, depId, resultId, requestDependenciesData);
 
   @override
@@ -58,7 +58,7 @@
           required DataId inputId,
           required DataId depId,
           required DataId resultId,
-          bool requestDependenciesData: true}) =>
+          bool requestDependenciesData = true}) =>
       MainOnlyStep(action, inputId, depId, resultId, requestDependenciesData);
 
   @override
diff --git a/pkg/modular_test/test/pipeline_common.dart b/pkg/modular_test/test/pipeline_common.dart
index 688d1e4..8d392ac 100644
--- a/pkg/modular_test/test/pipeline_common.dart
+++ b/pkg/modular_test/test/pipeline_common.dart
@@ -29,14 +29,14 @@
   /// by other methods in this strategy to ensure they are compatible with to
   /// the pipeline created here.
   FutureOr<Pipeline<S>> createPipeline(Map<Uri, String> sources, List<S> steps,
-      {bool cacheSharedModules: false});
+      {bool cacheSharedModules = false});
 
   /// Create a step that applies [action] on all input files of the module, and
   /// emits a result with the given [id]
   S createSourceOnlyStep(
       {required String Function(Map<Uri, String?>) action,
       required DataId resultId,
-      bool requestSources: true});
+      bool requestSources = true});
 
   /// Create a step that applies [action] on the module [inputId] data, and
   /// emits a result with the given [resultId].
@@ -44,7 +44,7 @@
       {required String Function(String) action,
       required DataId inputId,
       required DataId resultId,
-      bool requestModuleData: true});
+      bool requestModuleData = true});
 
   /// Create a step that applies [action] on the module [inputId] data and the
   /// the [depId] data of dependencies and finally emits a result with the given
@@ -56,7 +56,7 @@
       required DataId inputId,
       required DataId depId,
       required DataId resultId,
-      bool requestDependenciesData: true});
+      bool requestDependenciesData = true});
 
   /// Create a step that applies [action] only on the main module [inputId] data
   /// and the [depId] data of transitive dependencies and finally emits a
@@ -69,7 +69,7 @@
       required DataId inputId,
       required DataId depId,
       required DataId resultId,
-      bool requestDependenciesData: true});
+      bool requestDependenciesData = true});
 
   /// Create a step that applies [action1] and [action2] on the module [inputId]
   /// data, and emits two results with the given [result1Id] and [result2Id].
@@ -315,8 +315,8 @@
 
   test('no reuse of existing results if not caching', () async {
     int i = 1;
-    const counterId = const DataId("counter");
-    const linkId = const DataId("link");
+    const counterId = DataId("counter");
+    const linkId = DataId("link");
     // This step is not idempotent, we do this purposely to test whether caching
     // is taking place.
     var counterStep = testStrategy.createSourceOnlyStep(
@@ -347,8 +347,8 @@
 
   test('caching reuses existing results for the same configuration', () async {
     int i = 1;
-    const counterId = const DataId("counter");
-    const linkId = const DataId("link");
+    const counterId = DataId("counter");
+    const linkId = DataId("link");
     var counterStep = testStrategy.createSourceOnlyStep(
         action: (_) => '${i++}', resultId: counterId);
     var linkStep = testStrategy.createLinkStep(
@@ -377,8 +377,8 @@
 
   test('no reuse of existing results on different configurations', () async {
     int i = 1;
-    const counterId = const DataId("counter");
-    const linkId = const DataId("link");
+    const counterId = DataId("counter");
+    const linkId = DataId("link");
     // This step is not idempotent, we do this purposely to test whether caching
     // is taking place.
     var counterStep = testStrategy.createSourceOnlyStep(
@@ -420,7 +420,7 @@
 DataId _joinId = const DataId("join");
 
 String _concat(Map<Uri, String?> sources) {
-  var buffer = new StringBuffer();
+  var buffer = StringBuffer();
   sources.forEach((uri, contents) {
     buffer.write("$uri: $contents\n");
   });
@@ -431,7 +431,7 @@
 String _uppercase(String contents) => contents.toUpperCase();
 
 String _replaceAndJoin(String moduleData, List<String?> depContents) {
-  var buffer = new StringBuffer();
+  var buffer = StringBuffer();
   depContents.forEach(buffer.writeln);
   buffer.write(moduleData.replaceAll(".dart:", ""));
   return '$buffer';
diff --git a/pkg/modular_test/test/validate_pipeline_test.dart b/pkg/modular_test/test/validate_pipeline_test.dart
index 431d91a..90711a6 100644
--- a/pkg/modular_test/test/validate_pipeline_test.dart
+++ b/pkg/modular_test/test/validate_pipeline_test.dart
@@ -72,7 +72,7 @@
 }
 
 validateSteps(List<ModularStep> steps) {
-  new _NoopPipeline(steps);
+  _NoopPipeline(steps);
 }
 
 /// An implementation of [Pipeline] that simply validates the steps, but doesn't
diff --git a/pkg/smith/analysis_options.yaml b/pkg/smith/analysis_options.yaml
index 55af634..055ac10 100644
--- a/pkg/smith/analysis_options.yaml
+++ b/pkg/smith/analysis_options.yaml
@@ -1,3 +1,5 @@
+include: package:lints/recommended.yaml
+
 analyzer:
   language:
     strict-casts: true
diff --git a/pkg/smith/lib/configuration.dart b/pkg/smith/lib/configuration.dart
index 3202bf6..5cf0e02 100644
--- a/pkg/smith/lib/configuration.dart
+++ b/pkg/smith/lib/configuration.dart
@@ -432,12 +432,14 @@
     return true;
   }
 
+  @override
   bool operator ==(Object other) =>
       other is Configuration && name == other.name && optionsEqual(other);
 
   int _toBinary(List<bool> bits) =>
       bits.fold(0, (sum, bit) => (sum << 1) ^ (bit ? 1 : 0));
 
+  @override
   int get hashCode =>
       name.hashCode ^
       architecture.hashCode ^
@@ -468,6 +470,7 @@
         useQemu
       ]);
 
+  @override
   String toString() {
     var buffer = StringBuffer();
     buffer.write(name);
@@ -576,6 +579,7 @@
   static const x64 = Architecture._('x64');
   static const x64c = Architecture._('x64c');
   static const arm = Architecture._('arm');
+  // ignore: constant_identifier_names
   static const arm_x64 = Architecture._('arm_x64');
   static const arm64 = Architecture._('arm64');
   static const arm64c = Architecture._('arm64c');
@@ -988,5 +992,6 @@
 
   const NamedEnum(this.name);
 
+  @override
   String toString() => name;
 }
diff --git a/pkg/smith/pubspec.yaml b/pkg/smith/pubspec.yaml
index e92131c..995e14a 100644
--- a/pkg/smith/pubspec.yaml
+++ b/pkg/smith/pubspec.yaml
@@ -9,3 +9,4 @@
 # Use 'any' constraints here; we get our versions from the DEPS file.
 dev_dependencies:
   expect: any
+  lints: any
diff --git a/pkg/smith/test/test_helpers.dart b/pkg/smith/test/test_helpers.dart
index c44ee2c..8a9cef9 100644
--- a/pkg/smith/test/test_helpers.dart
+++ b/pkg/smith/test/test_helpers.dart
@@ -14,7 +14,7 @@
   }
 }
 
-void expectFormatError(String error, test()) {
+void expectFormatError(String error, Function() test) {
   try {
     test();
   } on FormatException catch (e) {
diff --git a/pkg/status_file/analysis_options.yaml b/pkg/status_file/analysis_options.yaml
index b5516058..e306536 100644
--- a/pkg/status_file/analysis_options.yaml
+++ b/pkg/status_file/analysis_options.yaml
@@ -2,6 +2,8 @@
 # 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.
 
+include: package:lints/recommended.yaml
+
 analyzer:
   errors:
     # Allow having TODOs in the code
diff --git a/pkg/status_file/bin/format.dart b/pkg/status_file/bin/format.dart
index f78916c..eb0f2f4 100644
--- a/pkg/status_file/bin/format.dart
+++ b/pkg/status_file/bin/format.dart
@@ -15,10 +15,10 @@
 
   var path = arguments[0];
 
-  if (new File(path).existsSync()) {
+  if (File(path).existsSync()) {
     formatFile(path);
-  } else if (new Directory(path).existsSync()) {
-    for (var entry in new Directory(path).listSync(recursive: true)) {
+  } else if (Directory(path).existsSync()) {
+    for (var entry in Directory(path).listSync(recursive: true)) {
       if (!entry.path.endsWith(".status")) continue;
 
       formatFile(entry.path);
@@ -28,8 +28,8 @@
 
 void formatFile(String path) {
   try {
-    var statusFile = new StatusFile.read(path);
-    new File(path).writeAsStringSync(statusFile.serialize());
+    var statusFile = StatusFile.read(path);
+    File(path).writeAsStringSync(statusFile.serialize());
     print("Formatted $path");
   } on SyntaxError catch (error) {
     stderr.writeln("Could not parse $path:\n$error");
diff --git a/pkg/status_file/bin/lint.dart b/pkg/status_file/bin/lint.dart
index fd9f6a0a..73105ea 100644
--- a/pkg/status_file/bin/lint.dart
+++ b/pkg/status_file/bin/lint.dart
@@ -11,7 +11,7 @@
 import 'package:status_file/utils.dart';
 
 ArgParser buildParser() {
-  var parser = new ArgParser();
+  var parser = ArgParser();
   parser.addFlag("check-for-disjunctions",
       negatable: false,
       defaultsTo: false,
@@ -78,7 +78,7 @@
       filesWithErrors.add(path);
     }
   } else if (FileSystemEntity.isDirectorySync(path)) {
-    new Directory(path).listSync(recursive: true).forEach((entry) {
+    Directory(path).listSync(recursive: true).forEach((entry) {
       if (!canLint(entry.path)) {
         return;
       }
@@ -98,7 +98,7 @@
 
 bool lintText(List<String> text, {bool checkForDisjunctions = false}) {
   try {
-    var statusFile = new StatusFile.parse("stdin", text);
+    var statusFile = StatusFile.parse("stdin", text);
     return lintStatusFile(statusFile,
         checkForDisjunctions: checkForDisjunctions);
   } on status_file.SyntaxError {
@@ -109,7 +109,7 @@
 
 bool lintFile(String path, {bool checkForDisjunctions = false}) {
   try {
-    var statusFile = new StatusFile.read(path);
+    var statusFile = StatusFile.read(path);
     return lintStatusFile(statusFile,
         checkForDisjunctions: checkForDisjunctions);
   } on status_file.SyntaxError catch (error) {
@@ -128,7 +128,7 @@
     return true;
   }
   if (statusFile.path.isNotEmpty) {
-    print("${statusFile.path}");
+    print(statusFile.path);
   }
   var errors = lintingErrors.toList();
   errors.sort((a, b) => a.lineNumber.compareTo((b.lineNumber)));
diff --git a/pkg/status_file/bin/normalize.dart b/pkg/status_file/bin/normalize.dart
index d65e42e..232cf92 100644
--- a/pkg/status_file/bin/normalize.dart
+++ b/pkg/status_file/bin/normalize.dart
@@ -12,7 +12,7 @@
 import 'package:status_file/utils.dart';
 
 ArgParser buildParser() {
-  var parser = new ArgParser();
+  var parser = ArgParser();
   parser.addFlag("overwrite",
       abbr: 'w',
       negatable: false,
@@ -48,7 +48,7 @@
     if (FileSystemEntity.isFileSync(path)) {
       normalizeFile(path, overwrite);
     } else if (FileSystemEntity.isDirectorySync(path)) {
-      new Directory(path).listSync(recursive: true).forEach((entry) {
+      Directory(path).listSync(recursive: true).forEach((entry) {
         if (!canLint(entry.path)) {
           return;
         }
@@ -60,10 +60,10 @@
 
 bool normalizeFile(String path, bool writeFile) {
   try {
-    var statusFile = new StatusFile.read(path);
+    var statusFile = StatusFile.read(path);
     var normalizedStatusFile = normalizeStatusFile(statusFile);
     if (writeFile) {
-      new File(path).writeAsStringSync(normalizedStatusFile.toString());
+      File(path).writeAsStringSync(normalizedStatusFile.toString());
       print("Normalized $path");
     } else {
       print(normalizedStatusFile);
diff --git a/pkg/status_file/bin/remove_non_essential_entries.dart b/pkg/status_file/bin/remove_non_essential_entries.dart
index 8f481c0..a7c1f5d 100644
--- a/pkg/status_file/bin/remove_non_essential_entries.dart
+++ b/pkg/status_file/bin/remove_non_essential_entries.dart
@@ -159,7 +159,7 @@
             String conditionPrefix = section.condition != Expression.always
                 ? "${section.condition}"
                 : "";
-            String issueText = await getIssueText(comment, resolveIssueState);
+            String issueText = getIssueText(comment, resolveIssueState);
             String statusLine = "$conditionPrefix\t$testName\t$expectations"
                 "\t$comment\t$issueText";
             comments.add(statusLine);
@@ -217,7 +217,7 @@
 }
 
 String formatComments(List<String> comments) {
-  StringBuffer sb = new StringBuffer();
+  StringBuffer sb = StringBuffer();
   for (String statusLine in comments) {
     sb.writeln(statusLine);
   }
diff --git a/pkg/status_file/lib/canonical_status_file.dart b/pkg/status_file/lib/canonical_status_file.dart
index c20924f..750e9fa 100644
--- a/pkg/status_file/lib/canonical_status_file.dart
+++ b/pkg/status_file/lib/canonical_status_file.dart
@@ -14,24 +14,24 @@
 /// Matches the header that begins a new section, like:
 ///
 ///     [ $compiler == dart2js && $minified ]
-final RegExp _sectionPattern = new RegExp(r"^\[(.+?)\]");
+final RegExp _sectionPattern = RegExp(r"^\[(.+?)\]");
 
 /// Matches an entry that defines the status for a path in the current section,
 /// like:
 ///
 ///     some/path/to/some_test: Pass || Fail
-final RegExp _entryPattern = new RegExp(r"^([^:#]+):([^#]+)(#.*)?");
+final RegExp _entryPattern = RegExp(r"^([^:#]+):([^#]+)(#.*)?");
 
 /// Matches an issue number in a comment, like:
 ///
 ///     blah_test: Fail # Issue 1234
 ///                       ^^^^
-final RegExp _issuePattern = new RegExp(r"[Ii]ssue (\d+)");
+final RegExp _issuePattern = RegExp(r"[Ii]ssue (\d+)");
 
 /// Matches a comment and indented comment, like:
 ///
 ///     < white space > #
-final RegExp _commentPattern = new RegExp(r"^(\s*)#");
+final RegExp _commentPattern = RegExp(r"^(\s*)#");
 
 /// A parsed status file, which describes how a collection of tests are
 /// expected to behave under various configurations and conditions.
@@ -80,7 +80,7 @@
   ///
   /// Throws a [SyntaxError] if the file could not be parsed.
   StatusFile.read(this.path) {
-    _parse(new File(path).readAsLinesSync());
+    _parse(File(path).readAsLinesSync());
   }
 
   /// Parses lines of strings coming from a status file at [path].
@@ -152,11 +152,10 @@
         break;
       }
       if (line.isEmpty) {
-        sectionHeaderComments.add(new EmptyEntry(_lineCount));
+        sectionHeaderComments.add(EmptyEntry(_lineCount));
         lastEmptyLine = _lineCount;
       } else {
-        sectionHeaderComments
-            .add(new CommentEntry(_lineCount, new Comment(line)));
+        sectionHeaderComments.add(CommentEntry(_lineCount, Comment(line)));
       }
     }
 
@@ -178,7 +177,7 @@
     // The current section whose rules are being parsed. Initialized to an
     // implicit section that matches everything.
     StatusSection section =
-        new StatusSection(Expression.always, -1, implicitSectionHeaderComments);
+        StatusSection(Expression.always, -1, implicitSectionHeaderComments);
     section.entries.addAll(entries);
     sections.add(section);
 
@@ -186,12 +185,12 @@
       var line = lines[_lineCount - 1];
 
       fail(String message, [List<String>? errors]) {
-        throw new SyntaxError(_shortPath, _lineCount, line, message, errors);
+        throw SyntaxError(_shortPath, _lineCount, line, message, errors);
       }
 
       // If it is an empty line
       if (line.isEmpty) {
-        section.entries.add(new EmptyEntry(_lineCount));
+        section.entries.add(EmptyEntry(_lineCount));
         continue;
       }
 
@@ -200,8 +199,7 @@
       if (match != null) {
         try {
           var condition = Expression.parse(match[1]!.trim());
-          section =
-              new StatusSection(condition, _lineCount, sectionHeaderComments);
+          section = StatusSection(condition, _lineCount, sectionHeaderComments);
           sections.add(section);
           // Reset section header comments.
           sectionHeaderComments = [];
@@ -226,10 +224,10 @@
         });
         if (match[3] == null) {
           section.entries
-              .add(new StatusEntry(path, _lineCount, expectations, null));
+              .add(StatusEntry(path, _lineCount, expectations, null));
         } else {
-          section.entries.add(new StatusEntry(
-              path, _lineCount, expectations, new Comment(match[3]!)));
+          section.entries.add(
+              StatusEntry(path, _lineCount, expectations, Comment(match[3]!)));
         }
         continue;
       }
@@ -238,7 +236,7 @@
       // section or the next section
       match = _commentPattern.firstMatch(line);
       if (match != null) {
-        var commentEntry = new CommentEntry(_lineCount, new Comment(line));
+        var commentEntry = CommentEntry(_lineCount, Comment(line));
         if (hasBreakFromPreviousSection(_lineCount) &&
             commentBelongsToNextSectionHeader(_lineCount)) {
           sectionHeaderComments.add(commentEntry);
@@ -253,7 +251,7 @@
 
     // There are no comment entries in [sectionHeaderComments], because of the
     // check for [commentBelongsToSectionHeader].
-    assert(sectionHeaderComments.length == 0);
+    assert(sectionHeaderComments.isEmpty);
   }
 
   bool get isEmpty => sections.length == 1 && sections[0].isEmpty();
@@ -269,7 +267,7 @@
 
       if (errors.isNotEmpty) {
         var s = errors.length > 1 ? "s" : "";
-        throw new SyntaxError(_shortPath, section.lineNumber,
+        throw SyntaxError(_shortPath, section.lineNumber,
             "[ ${section.condition} ]", 'Validation error$s', errors);
       }
     }
@@ -283,8 +281,9 @@
 
   /// Returns the status file as a string. This preserves comments and gives a
   /// "canonical" rendering of the status file that can be saved back to disc.
+  @override
   String toString() {
-    var buffer = new StringBuffer();
+    var buffer = StringBuffer();
     sections.forEach(buffer.write);
     return buffer.toString();
   }
@@ -317,7 +316,7 @@
 
   @override
   String toString() {
-    var buffer = new StringBuffer();
+    var buffer = StringBuffer();
     sectionHeaderComments.forEach(buffer.writeln);
     if (condition != Expression.always) {
       buffer.writeln("[ $condition ]");
diff --git a/pkg/status_file/lib/expectation.dart b/pkg/status_file/lib/expectation.dart
index 6a0223c..a8fa99d 100644
--- a/pkg/status_file/lib/expectation.dart
+++ b/pkg/status_file/lib/expectation.dart
@@ -5,7 +5,7 @@
 /// The possible outcomes from running a test.
 class Expectation {
   /// The test completed normally and did what it intended to do.
-  static final Expectation pass = new Expectation._('Pass');
+  static final Expectation pass = Expectation._('Pass');
 
   /// The process aborted in a way that is not a potential runtime error coming
   /// from the test itself. This is not considered a failure. It means an
@@ -20,22 +20,22 @@
   ///   internal exception in dart2js itself.
   ///
   /// * The browser process crashes.
-  static final Expectation crash = new Expectation._('Crash');
+  static final Expectation crash = Expectation._('Crash');
 
   /// The test did not complete (either successfully or unsuccessfully) in the
   /// amount of time that the test runner gave it.
-  static final Expectation timeout = new Expectation._('Timeout');
+  static final Expectation timeout = Expectation._('Timeout');
 
   /// The test completed but did not produce the intended output.
   ///
   /// This status is rarely used directly. Instead, most of the expectations
   /// below refine this into more specific reasons *why* it failed.
-  static final Expectation fail = new Expectation._('Fail');
+  static final Expectation fail = Expectation._('Fail');
 
   /// The test compiled and began executing but then threw an uncaught
   /// exception or produced the wrong output.
   static final Expectation runtimeError =
-      new Expectation._('RuntimeError', group: fail);
+      Expectation._('RuntimeError', group: fail);
 
   /// The test failed with an error at compile time and did not execute any
   /// code.
@@ -44,70 +44,70 @@
   /// * For an analyzer test, means the analyzer reported a static error.
   /// * For a dart2js test, means dart2js reported a compile error.
   static final Expectation compileTimeError =
-      new Expectation._('CompileTimeError', group: fail);
+      Expectation._('CompileTimeError', group: fail);
 
   /// The test was parsed by the spec_parser, and there was a syntax error.
   static final Expectation syntaxError =
-      new Expectation._('SyntaxError', group: fail);
+      Expectation._('SyntaxError', group: fail);
 
   /// The test itself contains a comment with `@runtime-error` in it,
   /// indicating it should have produced a runtime error when run. But when it
   /// was run, the test completed without error.
   static final Expectation missingRuntimeError =
-      new Expectation._('MissingRuntimeError', group: fail);
+      Expectation._('MissingRuntimeError', group: fail);
 
   /// The test itself contains a comment with `@syntax-error` in it,
   /// indicating it should have produced a syntax error when compiled. But when
   /// it was compiled, no error was reported.
   static final Expectation missingSyntaxError =
-      new Expectation._('MissingSyntaxError', group: fail);
+      Expectation._('MissingSyntaxError', group: fail);
 
   /// The test itself contains a comment with `@compile-error` in it,
   /// indicating it should have produced an error when compiled. But when it
   /// was compiled, no error was reported.
   static final Expectation missingCompileTimeError =
-      new Expectation._('MissingCompileTimeError', group: fail);
+      Expectation._('MissingCompileTimeError', group: fail);
 
   /// When the test is processed by analyzer, a static warning should be
   /// reported.
   static final Expectation staticWarning =
-      new Expectation._('StaticWarning', group: fail);
+      Expectation._('StaticWarning', group: fail);
 
   /// The test itself contains a comment with `@static-warning` in it,
   /// indicating analyzer should report a static warning when analyzing it, but
   /// analysis did not produce any warnings.
   static final Expectation missingStaticWarning =
-      new Expectation._('MissingStaticWarning', group: fail);
+      Expectation._('MissingStaticWarning', group: fail);
 
   /// An invocation of "pub get" exited with a non-zero exit code.
   // TODO(rnystrom): Is this still used? If not, remove.
   static final Expectation pubGetError =
-      new Expectation._('PubGetError', group: fail);
+      Expectation._('PubGetError', group: fail);
 
   /// The stdout or stderr produced by the test was not valid UTF-8 and could
   /// not be decoded.
   // TODO(rnystrom): The only test that uses this expectation is the one that
   // tests that the test runner handles this expectation. Remove it?
   static final Expectation nonUtf8Error =
-      new Expectation._('NonUtf8Output', group: fail);
+      Expectation._('NonUtf8Output', group: fail);
 
   /// The stdout or stderr produced by the test was too long and had to be
   /// truncated by the test runner.
   static final Expectation truncatedOutput =
-      new Expectation._('TruncatedOutput', group: fail);
+      Expectation._('TruncatedOutput', group: fail);
 
   /// The VM exited with the special exit code 252.
   static final Expectation dartkCrash =
-      new Expectation._('DartkCrash', group: crash);
+      Expectation._('DartkCrash', group: crash);
 
   /// A timeout occurred in a test using the Kernel-based front end.
   static final Expectation dartkTimeout =
-      new Expectation._('DartkTimeout', group: timeout);
+      Expectation._('DartkTimeout', group: timeout);
 
   /// A compile error was reported on a test compiled using the Kernel-based
   /// front end.
   static final Expectation dartkCompileTimeError =
-      new Expectation._('DartkCompileTimeError', group: compileTimeError);
+      Expectation._('DartkCompileTimeError', group: compileTimeError);
 
   // "meta expectations"
   /// A marker applied to a test to indicate that the other non-pass
@@ -121,17 +121,17 @@
   // static error should be reported. It leads to perpetually larger status
   // files and means a reader of a test can't tell what the intended behavior
   // actually is without knowing which status files mention it. Remove.
-  static final Expectation ok = new Expectation._('OK', isMeta: true);
+  static final Expectation ok = Expectation._('OK', isMeta: true);
 
   /// A marker that indicates the test takes longer to complete than most tests.
   /// Tells the test runner to increase the timeout when running it.
-  static final Expectation slow = new Expectation._('Slow', isMeta: true);
+  static final Expectation slow = Expectation._('Slow', isMeta: true);
 
   /// A marker that indicates the test takes a lot longer to complete than most
   /// tests.
   /// Tells the test runner to increase the timeout when running it.
   static final Expectation extraSlow =
-      new Expectation._('ExtraSlow', isMeta: true, group: skip);
+      Expectation._('ExtraSlow', isMeta: true, group: skip);
 
   /// Tells the test runner to not attempt to run the test.
   ///
@@ -139,7 +139,7 @@
   /// the expected results at all. This expectation should be avoided since it's
   /// doesn't indicate *why* the test is being skipped and means we won't
   /// notice if the actual behavior of the test changes.
-  static final Expectation skip = new Expectation._('Skip', isMeta: true);
+  static final Expectation skip = Expectation._('Skip', isMeta: true);
 
   /// Tells the test runner to skip the test because it takes too long to
   /// complete.
@@ -147,7 +147,7 @@
   /// Prefer this over timeout since this avoids wasting CPU resources running
   /// a test we know won't complete.
   static final Expectation skipSlow =
-      new Expectation._('SkipSlow', isMeta: true, group: skip);
+      Expectation._('SkipSlow', isMeta: true, group: skip);
 
   /// Skips this test because it is not intended to be meaningful for a certain
   /// reason or on some configuration.
@@ -155,21 +155,21 @@
   /// For example, tests that use dart:io are SkipByDesign on the browser since
   /// dart:io isn't supported there.
   static final Expectation skipByDesign =
-      new Expectation._('SkipByDesign', isMeta: true);
+      Expectation._('SkipByDesign', isMeta: true);
 
   /// Can be returned by the test runner to say the result should be ignored,
   /// and assumed to meet the expectations, due to an infrastructure failure.
   ///
   /// This should not appear in status files.
-  static final Expectation ignore = new Expectation._('Ignore');
+  static final Expectation ignore = Expectation._('Ignore');
 
   /// Used by pkg/front_end/lib/src/fasta/testing, but not used by test.dart.
   /// Included here so that we can parse .status files that contain it.
   static final Expectation verificationError =
-      new Expectation._('VerificationError');
+      Expectation._('VerificationError');
 
   /// Maps case-insensitive names to expectations.
-  static Map<String, Expectation> _all = new Map.fromIterable(<Expectation>[
+  static final Map<String, Expectation> _all = Map.fromIterable(<Expectation>[
     pass,
     crash,
     timeout,
@@ -199,7 +199,7 @@
   static Expectation find(String name) {
     var expectation = _all[name.toLowerCase()];
     if (expectation == null) {
-      throw new ArgumentError("Could not find an expectation named '$name'.");
+      throw ArgumentError("Could not find an expectation named '$name'.");
     }
 
     return expectation;
@@ -211,7 +211,7 @@
   /// Whether this expectation is a test outcome. If not, it's a "meta marker".
   final bool isOutcome;
 
-  Expectation._(this._name, {Expectation? group, bool isMeta: false})
+  Expectation._(this._name, {Expectation? group, bool isMeta = false})
       : _group = group,
         isOutcome = !isMeta;
 
@@ -229,5 +229,6 @@
     return false;
   }
 
+  @override
   String toString() => _name;
 }
diff --git a/pkg/status_file/lib/src/disjunctive.dart b/pkg/status_file/lib/src/disjunctive.dart
index b768f69..d235b83 100644
--- a/pkg/status_file/lib/src/disjunctive.dart
+++ b/pkg/status_file/lib/src/disjunctive.dart
@@ -5,8 +5,8 @@
 import 'expression.dart';
 import '../environment.dart';
 
-final Expression T = new LogicExpression.and([]);
-final Expression F = new LogicExpression.or([]);
+final Expression T = LogicExpression.and([]);
+final Expression F = LogicExpression.or([]);
 
 // Token to combine left and right value of a comparison expression in a
 // variable expression.
@@ -32,7 +32,7 @@
   } else if (minTerms.isEmpty) {
     return F;
   }
-  var disjunctiveNormalForm = new LogicExpression.or(minTerms);
+  var disjunctiveNormalForm = LogicExpression.or(minTerms);
   disjunctiveNormalForm = _minimizeByComplementation(disjunctiveNormalForm);
   return _recoverComparisonExpressions(disjunctiveNormalForm);
 }
@@ -101,10 +101,10 @@
     return onesInA - onesInB;
   });
   var combinedMinSets = _combineMinSets(
-      clauses.map((e) => [new LogicExpression.and(e)]).toList(), []);
+      clauses.map((e) => [LogicExpression.and(e)]).toList(), []);
   List<List<LogicExpression>> minCover = _findMinCover(combinedMinSets, []);
   var finalOperands = minCover.map((minSet) => _reduceMinSet(minSet)).toList();
-  return new LogicExpression.or(finalOperands).normalize();
+  return LogicExpression.or(finalOperands).normalize();
 }
 
 /// Computes all assignments of literals that make the [expression] evaluate to
@@ -113,7 +113,7 @@
   var variables = _getVariables(expression);
   bool hasNotSatisfiableAssignment = false;
   List<Expression> satisfiableTerms = <Expression>[];
-  var environment = new TruthTableEnvironment(variables);
+  var environment = TruthTableEnvironment(variables);
   for (int i = 0; i < 1 << variables.length; i++) {
     environment.setConfiguration(i);
     if (expression.evaluate(environment)) {
@@ -125,7 +125,7 @@
           operands.add(variables[j]);
         }
       }
-      satisfiableTerms.add(new LogicExpression.and(operands));
+      satisfiableTerms.add(LogicExpression.and(operands));
     } else {
       hasNotSatisfiableAssignment = true;
     }
@@ -175,7 +175,7 @@
 List<List<LogicExpression>> _combineMinSets(List<List<LogicExpression>> minSets,
     List<List<LogicExpression>> primeImplicants) {
   List<List<LogicExpression>> combined = <List<LogicExpression>>[];
-  var addedInThisIteration = new Set<List<LogicExpression>>();
+  var addedInThisIteration = <List<LogicExpression>>{};
   for (var i = 0; i < minSets.length; i++) {
     var minSet = minSets[i];
     var combinedMinSet = false;
@@ -255,7 +255,7 @@
       negative.remove(neg);
     }
   }
-  return new LogicExpression.and(positive..addAll(negative));
+  return LogicExpression.and(positive..addAll(negative));
 }
 
 /// [_findMinCover] finds the minimum cover of [primaryImplicants]. Finding a
@@ -316,11 +316,12 @@
 }
 
 // Computes the difference between two sets of expressions in disjunctive normal
-// form. if the difference is a negation, the difference is only counted once.
-List<Expression> _difference(List<Expression> As, List<Expression> Bs) {
-  var difference = <Expression>[]
-    ..addAll(As.where((a) => _findFirst(a, Bs) == null))
-    ..addAll(Bs.where((b) => _findFirst(b, As) == null));
+// form. If the difference is a negation, the difference is only counted once.
+List<Expression> _difference(List<Expression> aList, List<Expression> bList) {
+  var difference = <Expression>[
+    ...aList.where((a) => _findFirst(a, bList) == null),
+    ...bList.where((b) => _findFirst(b, aList) == null),
+  ];
   for (var expression in difference.toList()) {
     if (_isNegatedExpression(expression)) {
       if (_findFirst(negate(expression), difference) != null) {
@@ -390,37 +391,37 @@
 List<Expression> _getVariables(Expression expression) {
   if (expression is LogicExpression) {
     var variables = <Expression>[];
-    expression.operands.forEach(
-        (e) => _getVariables(e).forEach((v) => _addIfNotPresent(v, variables)));
+    for (var e in expression.operands) {
+      _getVariables(e).forEach((v) => _addIfNotPresent(v, variables));
+    }
     return variables;
   }
   if (expression is VariableExpression) {
-    return [new VariableExpression(expression.variable)];
+    return [VariableExpression(expression.variable)];
   }
   if (expression is ComparisonExpression) {
-    throw new Exception("Cannot use ComparisonExpression for variables");
+    throw Exception("Cannot use ComparisonExpression for variables");
   }
   return [];
 }
 
-Expression negate(Expression expression, {bool positive: false}) {
+Expression negate(Expression expression, {bool positive = false}) {
   if (expression is LogicExpression && expression.isOr) {
-    return new LogicExpression.and(expression.operands
+    return LogicExpression.and(expression.operands
         .map((e) => negate(e, positive: !positive))
         .toList());
   }
   if (expression is LogicExpression && expression.isAnd) {
-    return new LogicExpression.or(expression.operands
+    return LogicExpression.or(expression.operands
         .map((e) => negate(e, positive: !positive))
         .toList());
   }
   if (expression is ComparisonExpression) {
-    return new ComparisonExpression(
+    return ComparisonExpression(
         expression.left, expression.right, !expression.negate);
   }
   if (expression is VariableExpression) {
-    return new VariableExpression(expression.variable,
-        negate: !expression.negate);
+    return VariableExpression(expression.variable, negate: !expression.negate);
   }
   return expression;
 }
@@ -429,16 +430,15 @@
 // we can se individual variables truthiness in the [TruthTableEnvironment].
 Expression _comparisonExpressionsToVariableExpressions(Expression expression) {
   if (expression is LogicExpression) {
-    return new LogicExpression(
+    return LogicExpression(
         expression.op,
         expression.operands
             .map((exp) => _comparisonExpressionsToVariableExpressions(exp))
             .toList());
   }
   if (expression is ComparisonExpression) {
-    return new VariableExpression(
-        new Variable(
-            expression.left.name + _comparisonToken + expression.right),
+    return VariableExpression(
+        Variable(expression.left.name + _comparisonToken + expression.right),
         negate: expression.negate);
   }
   return expression;
@@ -446,7 +446,7 @@
 
 Expression _recoverComparisonExpressions(Expression expression) {
   if (expression is LogicExpression) {
-    return new LogicExpression(
+    return LogicExpression(
         expression.op,
         expression.operands
             .map((exp) => _recoverComparisonExpressions(exp))
@@ -455,8 +455,8 @@
   if (expression is VariableExpression &&
       expression.variable.name.contains(_comparisonToken)) {
     int tokenIndex = expression.variable.name.indexOf(_comparisonToken);
-    return new ComparisonExpression(
-        new Variable(expression.variable.name.substring(0, tokenIndex)),
+    return ComparisonExpression(
+        Variable(expression.variable.name.substring(0, tokenIndex)),
         expression.variable.name
             .substring(tokenIndex + _comparisonToken.length),
         expression.negate);
diff --git a/pkg/status_file/lib/src/expression.dart b/pkg/status_file/lib/src/expression.dart
index 9baf6aa..603e812 100644
--- a/pkg/status_file/lib/src/expression.dart
+++ b/pkg/status_file/lib/src/expression.dart
@@ -29,7 +29,7 @@
   /// Expressions evaluate as expected, with values of variables found in an
   /// environment passed to the evaluator.
   static Expression parse(String expression) =>
-      new _ExpressionParser(expression).parse();
+      _ExpressionParser(expression).parse();
 
   const Expression();
 
@@ -68,6 +68,7 @@
   /// This is useful for things like sorting lists of expressions or
   /// normalizing a list of subexpressions. The rough logic is that higher
   /// precedence and alphabetically lower expressions come first.
+  @override
   int compareTo(Expression other) {
     var comparison = _typeComparison.compareTo(other._typeComparison);
     if (comparison != 0) return comparison;
@@ -104,7 +105,7 @@
   String lookup(Environment environment) {
     var value = environment.lookUp(name);
     if (value == null) {
-      throw new Exception("Could not find '$name' in environment "
+      throw Exception("Could not find '$name' in environment "
           "while evaluating status file expression.");
     }
 
@@ -153,25 +154,29 @@
 
   ComparisonExpression(this.left, this.right, this.negate);
 
+  @override
   void validate(Environment environment, List<String> errors) {
     environment.validate(left.name, right, errors);
   }
 
+  @override
   bool evaluate(Environment environment) {
     return negate != (left.lookup(environment) == right);
   }
 
+  @override
   Expression normalize() {
     // Replace Boolean comparisons with a straight variable expression.
     if (right == "true") {
-      return new VariableExpression(left, negate: negate);
+      return VariableExpression(left, negate: negate);
     } else if (right == "false") {
-      return new VariableExpression(left, negate: !negate);
+      return VariableExpression(left, negate: !negate);
     } else {
       return this;
     }
   }
 
+  @override
   int _compareToMyType(ComparisonExpression other) {
     if (left.name != other.left.name) {
       return left.name.compareTo(other.left.name);
@@ -186,8 +191,10 @@
 
   // Comparisons come before variables so that "$compiler == ..." and
   // "$runtime == ..." appear on the left in status expressions.
+  @override
   int get _typeComparison => 1;
 
+  @override
   String toString() => "\$${left.name} ${negate ? '!=' : '=='} $right";
 }
 
@@ -214,17 +221,21 @@
 
   VariableExpression(this.variable, {this.negate = false});
 
+  @override
   void validate(Environment environment, List<String> errors) {
     // It must be a Boolean, so it should allow either Boolean value.
     environment.validate(variable.name, "true", errors);
   }
 
+  @override
   bool evaluate(Environment environment) =>
       negate != (variable.lookup(environment) == "true");
 
   /// Variable expressions are fine as they are.
+  @override
   Expression normalize() => this;
 
+  @override
   int _compareToMyType(VariableExpression other) {
     if (variable.name != other.variable.name) {
       return variable.name.compareTo(other.variable.name);
@@ -233,8 +244,10 @@
     return _compareBool(negate, other.negate);
   }
 
+  @override
   int get _typeComparison => 2;
 
+  @override
   String toString() => "${negate ? "!" : ""}\$${variable.name}";
 }
 
@@ -253,12 +266,14 @@
   bool get isAnd => op == _Token.and;
   bool get isOr => op == _Token.or;
 
+  @override
   void validate(Environment environment, List<String> errors) {
     for (var operand in operands) {
       operand.validate(environment, errors);
     }
   }
 
+  @override
   bool evaluate(Environment environment) {
     if (op == _Token.and) {
       return operands.every((operand) => operand.evaluate(environment));
@@ -267,6 +282,7 @@
     }
   }
 
+  @override
   LogicExpression normalize() {
     // Normalize the order of the clauses. Since there is no short-circuiting,
     // a || b means the same as b || a. Picking a standard order lets us
@@ -274,12 +290,12 @@
     // order.
 
     // Recurse into the operands, sort them, and remove duplicates.
-    var normalized = new LogicExpression(
+    var normalized = LogicExpression(
             op, operands.map((operand) => operand.normalize()).toList())
         .operands;
     normalized = flatten(normalized);
-    var ordered = new SplayTreeSet<Expression>.from(normalized).toList();
-    return new LogicExpression(op, ordered);
+    var ordered = SplayTreeSet<Expression>.from(normalized).toList();
+    return LogicExpression(op, ordered);
   }
 
   List<Expression> flatten(List<Expression> operands) {
@@ -294,6 +310,7 @@
     return newOperands;
   }
 
+  @override
   int _compareToMyType(LogicExpression other) {
     // Put "&&" before "||".
     if (op != other.op) return op == _Token.and ? -1 : 1;
@@ -311,8 +328,10 @@
     return 0;
   }
 
+  @override
   int get _typeComparison => 3;
 
+  @override
   String toString() {
     String parenthesize(Expression operand) {
       var result = operand.toString();
@@ -331,14 +350,14 @@
 class _ExpressionParser {
   final _Scanner _scanner;
 
-  _ExpressionParser(String expression) : _scanner = new _Scanner(expression);
+  _ExpressionParser(String expression) : _scanner = _Scanner(expression);
 
   Expression parse() {
     var expression = _parseOr();
 
     // Should consume entire string.
     if (_scanner.hasMore) {
-      throw new FormatException("Unexpected input after expression");
+      throw FormatException("Unexpected input after expression");
     }
 
     return expression;
@@ -352,7 +371,7 @@
 
     if (operands.length == 1) return operands.single;
 
-    return new LogicExpression(_Token.or, operands);
+    return LogicExpression(_Token.or, operands);
   }
 
   Expression _parseAnd() {
@@ -363,7 +382,7 @@
 
     if (operands.length == 1) return operands.single;
 
-    return new LogicExpression(_Token.and, operands);
+    return LogicExpression(_Token.and, operands);
   }
 
   Expression _parsePrimary() {
@@ -372,7 +391,7 @@
     if (_scanner.match(_Token.leftParen)) {
       var value = _parseOr();
       if (!_scanner.match(_Token.rightParen)) {
-        throw new FormatException("Missing right parenthesis in expression");
+        throw FormatException("Missing right parenthesis in expression");
       }
 
       return value;
@@ -386,16 +405,16 @@
     // The only atomic booleans are of the form $variable == value or
     // of the form $variable.
     if (!_scanner.match(_Token.dollar)) {
-      throw new FormatException(
+      throw FormatException(
           "Expected \$ in expression, got ${_scanner.current}");
     }
 
     if (!_scanner.isIdentifier) {
-      throw new FormatException(
+      throw FormatException(
           "Expected identifier in expression, got ${_scanner.current}");
     }
 
-    var left = new Variable(_scanner.current!);
+    var left = Variable(_scanner.current!);
     _scanner.advance();
 
     if (!negate &&
@@ -404,14 +423,14 @@
       var isNotEquals = _scanner.advance() == _Token.notEqual;
 
       if (!_scanner.isIdentifier) {
-        throw new FormatException(
+        throw FormatException(
             "Expected value in expression, got ${_scanner.current}");
       }
 
       var right = _scanner.advance()!;
-      return new ComparisonExpression(left, right, isNotEquals);
+      return ComparisonExpression(left, right, isNotEquals);
     } else {
-      return new VariableExpression(left, negate: negate);
+      return VariableExpression(left, negate: negate);
     }
   }
 }
@@ -419,14 +438,14 @@
 /// An iterator that allows peeking at the current token.
 class _Scanner {
   /// Tokens are "(", ")", "$", "&&", "||", "!", ==", "!=", and (maximal) \w+.
-  static final _testPattern = new RegExp(r"^(?:[()$\w\s]|&&|\|\||==|!=?)+$");
-  static final _tokenPattern = new RegExp(r"[()$]|&&|\|\||==|!=?|\w+");
+  static final _testPattern = RegExp(r"^(?:[()$\w\s]|&&|\|\||==|!=?)+$");
+  static final _tokenPattern = RegExp(r"[()$]|&&|\|\||==|!=?|\w+");
 
   /// Pattern that recognizes identifier tokens.
   ///
   /// Only checks the first character, since no non-identifier token can start
   /// with a word character.
-  static final _identifierPattern = new RegExp(r"^\w");
+  static final _identifierPattern = RegExp(r"^\w");
 
   /// The token strings being iterated.
   final Iterator<String> tokenIterator;
@@ -439,7 +458,7 @@
 
   static List<String> tokenize(String expression) {
     if (!_testPattern.hasMatch(expression)) {
-      throw new FormatException("Syntax error in '$expression'");
+      throw FormatException("Syntax error in '$expression'");
     }
 
     return _tokenPattern
diff --git a/pkg/status_file/lib/status_file.dart b/pkg/status_file/lib/status_file.dart
index 86a37a5..db995ae 100644
--- a/pkg/status_file/lib/status_file.dart
+++ b/pkg/status_file/lib/status_file.dart
@@ -13,19 +13,19 @@
 /// Matches the header that begins a new section, like:
 ///
 ///     [ $compiler == dart2js && $minified ]
-final _sectionPattern = new RegExp(r"^\[(.+?)\]");
+final _sectionPattern = RegExp(r"^\[(.+?)\]");
 
 /// Matches an entry that defines the status for a path in the current section,
 /// like:
 ///
 ///     some/path/to/some_test: Pass || Fail
-final _entryPattern = new RegExp(r"^([^:#]+):(.*)");
+final _entryPattern = RegExp(r"^([^:#]+):(.*)");
 
 /// Matches an issue number in a comment, like:
 ///
 ///     blah_test: Fail # Issue 1234
 ///                       ^^^^
-final _issuePattern = new RegExp(r"[Ii]ssue (\d+)");
+final _issuePattern = RegExp(r"[Ii]ssue (\d+)");
 
 /// A parsed status file, which describes how a collection of tests are
 /// expected to behave under various configurations and conditions.
@@ -55,14 +55,14 @@
   ///
   /// Throws a [SyntaxError] if the file could not be parsed.
   StatusFile.read(this.path) {
-    var lines = new File(path).readAsLinesSync();
+    var lines = File(path).readAsLinesSync();
     _comments.length = lines.length + 1;
 
     for (var line in lines) {
       _lineCount++;
 
       fail(String message, [List<String>? errors]) {
-        throw new SyntaxError(_shortPath, _lineCount, line, message, errors);
+        throw SyntaxError(_shortPath, _lineCount, line, message, errors);
       }
 
       // Strip off the comment and whitespace.
@@ -84,7 +84,7 @@
       if (match != null) {
         try {
           var condition = Expression.parse(match[1]!.trim());
-          sections.add(new StatusSection(condition, _lineCount));
+          sections.add(StatusSection(condition, _lineCount));
         } on FormatException {
           fail("Status expression syntax error");
         }
@@ -111,11 +111,11 @@
         // If we haven't found a section header yet, create an implicit section
         // that matches everything.
         if (sections.isEmpty) {
-          sections.add(new StatusSection(Expression.always, -1));
+          sections.add(StatusSection(Expression.always, -1));
         }
 
         sections.last.entries
-            .add(new StatusEntry(path, _lineCount, expectations, issue));
+            .add(StatusEntry(path, _lineCount, expectations, issue));
         continue;
       }
 
@@ -138,7 +138,7 @@
 
       if (errors.isNotEmpty) {
         var s = errors.length > 1 ? "s" : "";
-        throw new SyntaxError(_shortPath, section.lineNumber,
+        throw SyntaxError(_shortPath, section.lineNumber,
             "[ ${section.condition} ]", 'Validation error$s', errors);
       }
     }
@@ -158,8 +158,9 @@
     return int.parse(match[1]!);
   }
 
+  @override
   String toString() {
-    var buffer = new StringBuffer();
+    var buffer = StringBuffer();
     for (var section in sections) {
       buffer.writeln("[ ${section.condition} ]");
 
@@ -180,7 +181,7 @@
   /// Unlike [toString()], this preserves comments and gives a "canonical"
   /// rendering of the status file that can be saved back to disc.
   String serialize() {
-    var buffer = new StringBuffer();
+    var buffer = StringBuffer();
 
     var lastLine = 0;
     var needBlankLine = false;
@@ -283,8 +284,9 @@
 
   SyntaxError(this.file, this.lineNumber, this.line, this.message, this.errors);
 
+  @override
   String toString() {
-    var buffer = new StringBuffer();
+    var buffer = StringBuffer();
     buffer.writeln('$message in "$file" line $lineNumber:');
     buffer.writeln(line);
 
diff --git a/pkg/status_file/lib/status_file_linter.dart b/pkg/status_file/lib/status_file_linter.dart
index 7f1e29b..b5cc2b4 100644
--- a/pkg/status_file/lib/status_file_linter.dart
+++ b/pkg/status_file/lib/status_file_linter.dart
@@ -11,6 +11,7 @@
   final String message;
   LintingError(this.lineNumber, this.message);
 
+  @override
   String toString() {
     return "Error at line $lineNumber: $message";
   }
@@ -55,14 +56,14 @@
     for (var entry in section.entries) {
       seenStatusEntry = seenStatusEntry || entry is StatusEntry;
       if (seenStatusEntry && entry is CommentEntry) {
-        lintingErrors.add(new LintingError(
-            entry.lineNumber, "Comment is on a line by itself."));
+        lintingErrors.add(
+            LintingError(entry.lineNumber, "Comment is on a line by itself."));
       }
     }
     return lintingErrors;
   }
   return section.entries.whereType<CommentEntry>().map((entry) =>
-      new LintingError(entry.lineNumber, "Comment is on a line by itself."));
+      LintingError(entry.lineNumber, "Comment is on a line by itself."));
 }
 
 /// Checks for disjunctions in headers. Disjunctions should be separated out.
@@ -84,7 +85,7 @@
 Iterable<LintingError> lintDisjunctionsInHeader(StatusSection section) {
   if (section.condition.toString().contains("||")) {
     return [
-      new LintingError(
+      LintingError(
           section.lineNumber,
           "Expression contains '||'. Please split the expression into multiple "
           "separate sections.")
@@ -104,7 +105,7 @@
   var witness = _findNotEqualWitness<String>(sortedList, entries);
   if (witness != null) {
     return [
-      new LintingError(
+      LintingError(
           section.lineNumber,
           "Test paths are not alphabetically ordered in section. "
           "${witness.first} should come before ${witness.second}.")
@@ -119,7 +120,7 @@
   var normalized = section.condition.normalize().toString();
   if (nonNormalized != normalized) {
     return [
-      new LintingError(
+      LintingError(
           section.lineNumber,
           "Condition expression should be '$normalized' "
           "but was '$nonNormalized'.")
@@ -140,10 +141,10 @@
       if (entry.path == otherEntry.path &&
           _findNotEqualWitness(entry.expectations, otherEntry.expectations) ==
               null) {
-        errors.add(new LintingError(
+        errors.add(LintingError(
             section.lineNumber,
             "The status entry "
-            "'${entry}' is duplicated on lines "
+            "'$entry' is duplicated on lines "
             "${entry.lineNumber} and ${otherEntry.lineNumber}."));
       }
     }
@@ -182,7 +183,7 @@
   var witness = _findNotEqualWitness<StatusSection>(sorted, unsorted);
   if (witness != null) {
     return [
-      new LintingError(
+      LintingError(
           witness.second!.lineNumber,
           "Section expressions are not correctly ordered in file. "
           "'${witness.first!.condition}' on line ${witness.first!.lineNumber} "
@@ -203,7 +204,7 @@
     var section = sorted[i];
     var previousSection = sorted[i - 1];
     if (section.condition.compareTo(previousSection.condition) == 0) {
-      errors.add(new LintingError(
+      errors.add(LintingError(
           section.lineNumber,
           "The condition "
           "'${section.condition}' is duplicated on lines "
@@ -219,11 +220,11 @@
   }
   for (var i = 0; i < math.max(first.length, second.length); i++) {
     if (i >= second.length) {
-      return new ListNotEqualWitness(first[i], null);
+      return ListNotEqualWitness(first[i], null);
     } else if (i >= first.length) {
-      return new ListNotEqualWitness(null, second[i]);
+      return ListNotEqualWitness(null, second[i]);
     } else if (first[i] != second[i]) {
-      return new ListNotEqualWitness(first[i], second[i]);
+      return ListNotEqualWitness(first[i], second[i]);
     }
   }
   return null;
diff --git a/pkg/status_file/lib/status_file_normalizer.dart b/pkg/status_file/lib/status_file_normalizer.dart
index 73e1727..a3895b7 100644
--- a/pkg/status_file/lib/status_file_normalizer.dart
+++ b/pkg/status_file/lib/status_file_normalizer.dart
@@ -9,10 +9,10 @@
 
 StatusFile normalizeStatusFile(StatusFile statusFile) {
   StatusFile newStatusFile = _sortSectionsAndCombine(statusFile);
-  newStatusFile.sections.forEach((section) {
+  for (var section in newStatusFile.sections) {
     _sortEntriesInSection(section);
     _oneLineBetweenSections(section);
-  });
+  }
   // Remove empty line at the end of the file
   newStatusFile.sections.last.entries.removeLast();
   return newStatusFile;
@@ -44,32 +44,32 @@
 void _oneLineBetweenSections(StatusSection section) {
   section.entries.removeWhere((entry) => entry is EmptyEntry);
   section.entries
-      .add(new EmptyEntry(section.lineNumber + section.entries.length + 1));
+      .add(EmptyEntry(section.lineNumber + section.entries.length + 1));
 }
 
 StatusFile _sortSectionsAndCombine(StatusFile statusFile) {
   // Create the new status file to be returned.
-  StatusFile oldStatusFile = new StatusFile.parse(
+  StatusFile oldStatusFile = StatusFile.parse(
       statusFile.path, LineSplitter.split(statusFile.toString()).toList());
   List<StatusSection> newSections = [];
   // Copy over all sections and normalize all the expressions.
-  oldStatusFile.sections.forEach((section) {
+  for (var section in oldStatusFile.sections) {
     if (section.condition != Expression.always) {
-      if (section.isEmpty()) return;
+      if (section.isEmpty()) continue;
 
-      newSections.add(new StatusSection(section.condition.normalize(),
+      newSections.add(StatusSection(section.condition.normalize(),
           section.lineNumber, section.sectionHeaderComments)
         ..entries.addAll(section.entries));
     } else {
       newSections.add(section);
     }
-  });
+  }
 
   // Sort the headers
   newSections.sort((a, b) => a.condition.compareTo(b.condition));
 
   // See if we can combine section headers by simple comparison.
-  var newStatusFile = new StatusFile(statusFile.path);
+  var newStatusFile = StatusFile(statusFile.path);
   newStatusFile.sections.add(newSections[0]);
   for (var i = 1; i < newSections.length; i++) {
     var previousSection = newSections[i - 1];
diff --git a/pkg/status_file/pubspec.yaml b/pkg/status_file/pubspec.yaml
index 70c564c..5d73b18 100644
--- a/pkg/status_file/pubspec.yaml
+++ b/pkg/status_file/pubspec.yaml
@@ -13,3 +13,4 @@
 # Use 'any' constraints here; we get our versions from the DEPS file.
 dev_dependencies:
   expect: any
+  lints: any
diff --git a/pkg/status_file/test/linter_test.dart b/pkg/status_file/test/linter_test.dart
index f97b6ca..bfd2ae3 100644
--- a/pkg/status_file/test/linter_test.dart
+++ b/pkg/status_file/test/linter_test.dart
@@ -2,6 +2,8 @@
 // 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.
 
+// ignore_for_file: non_constant_identifier_names
+
 import 'package:expect/expect.dart';
 import 'package:status_file/canonical_status_file.dart';
 import 'package:status_file/status_file_linter.dart';
@@ -36,7 +38,7 @@
 }
 
 StatusFile createFromString(String text) {
-  return new StatusFile.parse("test", text.split('\n'));
+  return StatusFile.parse("test", text.split('\n'));
 }
 
 expectError(String text, String expectedError, {bool disjunctions = false}) {
diff --git a/pkg/status_file/test/normalize_test.dart b/pkg/status_file/test/normalize_test.dart
index 27c5985..c3e4f1e 100644
--- a/pkg/status_file/test/normalize_test.dart
+++ b/pkg/status_file/test/normalize_test.dart
@@ -24,33 +24,33 @@
 void normalizeCheck() {
   var files = getStatusFiles();
   for (var file in files) {
-    print("------- " + file.path + " -------");
-    var statusFile = new StatusFile.read(file.path);
-    var statusFileOther = normalizeStatusFile(new StatusFile.read(file.path));
+    print("------- ${file.path} -------");
+    var statusFile = StatusFile.read(file.path);
+    var statusFileOther = normalizeStatusFile(StatusFile.read(file.path));
     checkSemanticallyEqual(statusFile, statusFileOther,
         warnOnDuplicateHeader: true);
     checkFileHeaderIntact(statusFile, statusFileOther);
-    print("------- " + file.path + " -------");
+    print("------- ${file.path} -------");
   }
 }
 
 void sanityCheck() {
   var files = getStatusFiles();
   for (var file in files) {
-    print("------- " + file.path + " -------");
-    var statusFile = new StatusFile.read(file.path);
-    var statusFileOther = new StatusFile.read(file.path);
+    print("------- ${file.path} -------");
+    var statusFile = StatusFile.read(file.path);
+    var statusFileOther = StatusFile.read(file.path);
     checkSemanticallyEqual(statusFile, statusFileOther,
         warnOnDuplicateHeader: true);
     checkFileHeaderIntact(statusFile, statusFileOther);
-    print("------- " + file.path + " -------");
+    print("------- ${file.path} -------");
   }
 }
 
 List<FileSystemEntity> getStatusFiles() {
   var statusFiles = <FileSystemEntity>[];
   for (var entry
-      in new Directory.fromUri(statusFilePath).listSync(recursive: true)) {
+      in Directory.fromUri(statusFilePath).listSync(recursive: true)) {
     statusFiles.add(entry);
   }
   return statusFiles;
@@ -64,7 +64,7 @@
     print(original);
     print("==================");
     print(normalized);
-    throw new Exception("The count of entries in original is "
+    throw Exception("The count of entries in original is "
         "$entriesInOriginal and the count of entries in normalized is "
         "$entriesInNormalized. Those two numbers are not the same.");
   }
@@ -77,8 +77,7 @@
 
 int countEntries(StatusFile statusFile) {
   return statusFile.sections
-      .map((section) =>
-          section.entries.where((entry) => entry is StatusEntry).length)
+      .map((section) => section.entries.whereType<StatusEntry>().length)
       .fold(0, (count, sum) => count + sum);
 }
 
@@ -96,29 +95,29 @@
             entry.path.compareTo(entryToFind.path) == 0 &&
             listEqual(entry.expectations, entryToFind.expectations))
         .toList();
-    if (matchingEntries.length == 0) {
+    if (matchingEntries.isEmpty) {
       var message = "Could not find the entry even though the section "
           "header matched on line number ${section.lineNumber}. Sections "
           "should be unique.";
       if (warnOnDuplicateHeader) {
         print(message);
       } else {
-        throw new Exception(message);
+        throw Exception(message);
       }
     } else if (matchingEntries.length == 1 && foundEntryPosition >= 0) {
-      throw new Exception("The entry '$entryToFind' on line "
+      throw Exception("The entry '$entryToFind' on line "
           "${entryToFind.lineNumber} in section ${section.condition} was "
           "already found in a previous section on line $foundEntryPosition.");
     } else if (matchingEntries.length == 1) {
       foundEntryPosition = matchingEntries[0].lineNumber;
     } else {
-      throw new Exception("The entry '$entryToFind' on line "
+      throw Exception("The entry '$entryToFind' on line "
           "${entryToFind.lineNumber} in section ${section.condition} on line "
           "${section.lineNumber} had multiple matches in section.");
     }
   }
   if (foundEntryPosition < 0) {
-    throw new Exception("Could not find entry '$entryToFind' under the "
+    throw Exception("Could not find entry '$entryToFind' under the "
         "condition $condition in the status file.");
   }
 }
@@ -128,7 +127,7 @@
   var normalizedHeader =
       normalized.sections.first.sectionHeaderComments.toString();
   if (originalHeader != normalizedHeader) {
-    throw new Exception(
+    throw Exception(
         "File headers changed.\nExpected:\n$originalHeader\n\nActual:\n$normalizedHeader");
   }
 }
diff --git a/pkg/status_file/test/parse_and_normalize_test.dart b/pkg/status_file/test/parse_and_normalize_test.dart
index a7c3338..841af03 100644
--- a/pkg/status_file/test/parse_and_normalize_test.dart
+++ b/pkg/status_file/test/parse_and_normalize_test.dart
@@ -12,16 +12,16 @@
 void main() {
   // Parse every status file in the repository.
   for (var directory in ["tests", "runtime/tests"]) {
-    for (var entry in new Directory.fromUri(repoRoot.resolve(directory))
+    for (var entry in Directory.fromUri(repoRoot.resolve(directory))
         .listSync(recursive: true)) {
       if (!entry.path.endsWith(".status")) continue;
       try {
-        var statusFile = new StatusFile.read(entry.path);
+        var statusFile = StatusFile.read(entry.path);
         statusFile.toString();
       } catch (err, st) {
         print(err);
         print(st);
-        throw new Exception("Could not parse '${entry.path}'.\n$err");
+        throw Exception("Could not parse '${entry.path}'.\n$err");
       }
     }
   }
diff --git a/pkg/status_file/test/repo_status_files_test.dart b/pkg/status_file/test/repo_status_files_test.dart
index fccd043..1a910b4 100644
--- a/pkg/status_file/test/repo_status_files_test.dart
+++ b/pkg/status_file/test/repo_status_files_test.dart
@@ -14,11 +14,11 @@
 void main() {
   // Parse every status file in the repository.
   for (var directory in ["tests", "runtime/tests"]) {
-    for (var entry in new Directory.fromUri(repoRoot.resolve(directory))
+    for (var entry in Directory.fromUri(repoRoot.resolve(directory))
         .listSync(recursive: true)) {
       if (!entry.path.endsWith(".status")) continue;
       try {
-        new StatusFile.read(entry.path);
+        StatusFile.read(entry.path);
       } catch (err, stack) {
         Expect.fail("Could not parse '${entry.path}'.\n$err\n$stack");
       }
diff --git a/pkg/status_file/test/status_expression_test.dart b/pkg/status_file/test/status_expression_test.dart
index b79d57b..279f920 100644
--- a/pkg/status_file/test/status_expression_test.dart
+++ b/pkg/status_file/test/status_expression_test.dart
@@ -12,11 +12,13 @@
 
   TestEnvironment(this._values);
 
+  @override
   void validate(String name, String value, List<String> errors) {
-    throw new UnimplementedError();
+    throw UnimplementedError();
   }
 
   /// Looks up the value of the variable with [name].
+  @override
   String? lookUp(String name) => _values[name];
 
   operator []=(String key, String value) => _values[key] = value;
@@ -39,7 +41,7 @@
       expression.toString());
 
   // Test BooleanExpression.evaluate().
-  var environment = new TestEnvironment({"arch": "dartc", "mode": "debug"});
+  var environment = TestEnvironment({"arch": "dartc", "mode": "debug"});
 
   Expect.isTrue(expression.evaluate(environment));
   environment["mode"] = "release";
@@ -67,7 +69,7 @@
 
   // Test BooleanExpression.evaluate().
   var environment =
-      new TestEnvironment({"arch": "ia32", "checked": "true", "mode": "debug"});
+      TestEnvironment({"arch": "ia32", "checked": "true", "mode": "debug"});
 
   Expect.isTrue(expression.evaluate(environment));
   environment["mode"] = "release";
@@ -88,8 +90,8 @@
   Expect.equals(
       r"$arch == ia32 && !$checked || $mode == release", expression.toString());
 
-  var environment = new TestEnvironment(
-      {"arch": "ia32", "checked": "false", "mode": "debug"});
+  var environment =
+      TestEnvironment({"arch": "ia32", "checked": "false", "mode": "debug"});
 
   Expect.isTrue(expression.evaluate(environment));
   environment["mode"] = "release";
@@ -111,7 +113,7 @@
       r"$compiler == dart2js && $runtime != ie9", expression.toString());
 
   // Test BooleanExpression.evaluate().
-  var environment = new TestEnvironment({
+  var environment = TestEnvironment({
     "compiler": "none",
     "runtime": "ie9",
   });
diff --git a/pkg/testing/analysis_options.yaml b/pkg/testing/analysis_options.yaml
index b5516058..60a02db 100644
--- a/pkg/testing/analysis_options.yaml
+++ b/pkg/testing/analysis_options.yaml
@@ -2,6 +2,8 @@
 # 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.
 
+include: package:lints/core.yaml
+
 analyzer:
   errors:
     # Allow having TODOs in the code
diff --git a/pkg/testing/lib/dart_vm_suite.dart b/pkg/testing/lib/dart_vm_suite.dart
index 09ed485..940c0ef 100644
--- a/pkg/testing/lib/dart_vm_suite.dart
+++ b/pkg/testing/lib/dart_vm_suite.dart
@@ -8,11 +8,11 @@
 
 Future<ChainContext> createContext(
     Chain suite, Map<String, String> environment) async {
-  return new VmContext();
+  return VmContext();
 }
 
 class VmContext extends ChainContext {
-  final List<Step> steps = const <Step>[const DartVmStep()];
+  final List<Step> steps = const <Step>[DartVmStep()];
 }
 
 class DartVmStep extends Step<FileBasedTestDescription, int, VmContext> {
diff --git a/pkg/testing/lib/src/analyze.dart b/pkg/testing/lib/src/analyze.dart
index 05009ec..94c79e8 100644
--- a/pkg/testing/lib/src/analyze.dart
+++ b/pkg/testing/lib/src/analyze.dart
@@ -33,7 +33,7 @@
       : super("analyze", "analyze", null);
 
   Future<Null> run(Uri packages, List<Uri>? extraUris) {
-    List<Uri> allUris = new List<Uri>.from(uris);
+    List<Uri> allUris = List<Uri>.from(uris);
     if (extraUris != null) {
       allUris.addAll(extraUris);
     }
@@ -52,7 +52,7 @@
     }).toList();
 
     List<RegExp> exclude =
-        json["exclude"].map<RegExp>((p) => new RegExp(p)).toList();
+        json["exclude"].map<RegExp>((p) => RegExp(p)).toList();
 
     Map? gitGrep = json["git grep"];
     List<String>? gitGrepPathspecs;
@@ -60,12 +60,13 @@
     if (gitGrep != null) {
       gitGrepPathspecs = gitGrep["pathspecs"] == null
           ? const <String>["."]
-          : new List<String>.from(gitGrep["pathspecs"]);
-      if (gitGrep["patterns"] != null)
-        gitGrepPatterns = new List<String>.from(gitGrep["patterns"]);
+          : List<String>.from(gitGrep["pathspecs"]);
+      if (gitGrep["patterns"] != null) {
+        gitGrepPatterns = List<String>.from(gitGrep["patterns"]);
+      }
     }
 
-    return new Analyze(
+    return Analyze(
         optionsUri, uris, exclude, gitGrepPathspecs, gitGrepPatterns);
   }
 
@@ -89,9 +90,9 @@
 
   final String message;
 
-  static final Pattern potentialSplitPattern = new RegExp(r"\\|\|");
+  static final Pattern potentialSplitPattern = RegExp(r"\\|\|");
 
-  static final Pattern unescapePattern = new RegExp(r"\\(.)");
+  static final Pattern unescapePattern = RegExp(r"\\(.)");
 
   AnalyzerDiagnostic(this.kind, this.detailedKind, this.code, this.uri,
       this.line, this.startColumn, this.endColumn, this.message);
@@ -120,13 +121,13 @@
     }
     addPart();
     if (parts.length != 8) {
-      return new AnalyzerDiagnostic.malformed(line);
+      return AnalyzerDiagnostic.malformed(line);
     }
-    return new AnalyzerDiagnostic(
+    return AnalyzerDiagnostic(
         parts[0],
         parts[1],
         parts[2],
-        Uri.base.resolveUri(new Uri.file(parts[3])),
+        Uri.base.resolveUri(Uri.file(parts[3])),
         int.parse(parts[4]),
         int.parse(parts[5]),
         int.parse(parts[6]),
@@ -145,10 +146,10 @@
 Stream<AnalyzerDiagnostic> parseAnalyzerOutput(
     Stream<List<int>> stream) async* {
   Stream<String> lines =
-      stream.transform(utf8.decoder).transform(new LineSplitter());
+      stream.transform(utf8.decoder).transform(LineSplitter());
   await for (String line in lines) {
     if (line.startsWith(">>> ")) continue;
-    yield new AnalyzerDiagnostic.fromLine(line);
+    yield AnalyzerDiagnostic.fromLine(line);
   }
 }
 
@@ -163,7 +164,7 @@
   if (uris.isEmpty) return;
   String topLevel;
   try {
-    topLevel = new Uri.directory(
+    topLevel = Uri.directory(
             (await git("rev-parse", <String>["--show-toplevel"])).trimRight())
         .toFilePath(windows: false);
   } catch (e) {
@@ -183,17 +184,17 @@
         : path;
   }
 
-  Set<String> filesToAnalyze = new Set<String>();
+  Set<String> filesToAnalyze = Set<String>();
 
   for (Uri uri in uris) {
-    if (await new Directory.fromUri(uri).exists()) {
-      await for (FileSystemEntity entity in new Directory.fromUri(uri)
-          .list(recursive: true, followLinks: false)) {
+    if (await Directory.fromUri(uri).exists()) {
+      await for (FileSystemEntity entity
+          in Directory.fromUri(uri).list(recursive: true, followLinks: false)) {
         if (entity is File && entity.path.endsWith(".dart")) {
           filesToAnalyze.add(toFilePath(entity.uri));
         }
       }
-    } else if (await new File.fromUri(uri).exists()) {
+    } else if (await File.fromUri(uri).exists()) {
       filesToAnalyze.add(toFilePath(uri));
     } else {
       throw "File not found: ${uri}";
@@ -212,7 +213,7 @@
 
   const String analyzerPath = "pkg/analyzer_cli/bin/analyzer.dart";
   Uri analyzer = Uri.base.resolve(analyzerPath);
-  if (!await new File.fromUri(analyzer).exists()) {
+  if (!await File.fromUri(analyzer).exists()) {
     throw "Couldn't find '$analyzerPath' in '${toFilePath(Uri.base)}'";
   }
   List<String> arguments = <String>[
@@ -233,14 +234,14 @@
   } else {
     print("Running dartanalyzer.");
   }
-  Stopwatch sw = new Stopwatch()..start();
+  Stopwatch sw = Stopwatch()..start();
   Process process = await startDart(
       analyzer, const <String>["--batch"], dartArguments..remove("-c"));
   process.stdin.writeln(arguments.join(" "));
   process.stdin.close();
 
   bool hasOutput = false;
-  Set<String> seen = new Set<String>();
+  Set<String> seen = Set<String>();
 
   processAnalyzerOutput(Stream<AnalyzerDiagnostic> diagnostics) async {
     await for (AnalyzerDiagnostic diagnostic in diagnostics) {
diff --git a/pkg/testing/lib/src/chain.dart b/pkg/testing/lib/src/chain.dart
index ad570dd..0ef4814 100644
--- a/pkg/testing/lib/src/chain.dart
+++ b/pkg/testing/lib/src/chain.dart
@@ -15,7 +15,7 @@
 import '../testing.dart' show FileBasedTestDescription, TestDescription;
 
 import 'test_dart/status_file_parser.dart'
-    show ReadTestExpectations, TestExpectations;
+    show readTestExpectations, TestExpectations;
 
 import 'zone_helper.dart' show runGuarded;
 
@@ -27,7 +27,7 @@
 
 import 'expectation.dart' show Expectation, ExpectationGroup, ExpectationSet;
 
-typedef Future<ChainContext> CreateContext(
+typedef CreateContext = Future<ChainContext> Function(
     Chain suite, Map<String, String> environment);
 
 /// A test suite for tool chains, for example, a compiler.
@@ -55,11 +55,11 @@
     Uri uri = base.resolve(path);
     Uri statusFile = base.resolve(json["status"]);
     List<RegExp> pattern =
-        json["pattern"].map<RegExp>((p) => new RegExp(p)).toList();
+        json["pattern"].map<RegExp>((p) => RegExp(p)).toList();
     List<RegExp> exclude =
-        json["exclude"].map<RegExp>((p) => new RegExp(p)).toList();
+        json["exclude"].map<RegExp>((p) => RegExp(p)).toList();
     bool processMultitests = json["process-multitests"] ?? false;
-    return new Chain(name, kind, source, uri, statusFile, pattern, exclude,
+    return Chain(name, kind, source, uri, statusFile, pattern, exclude,
         processMultitests);
   }
 
@@ -77,7 +77,7 @@
     sink.writeln(".createContext, environment, selectors, r'''");
     const String jsonExtraIndent = "    ";
     sink.write(jsonExtraIndent);
-    sink.writeAll(splitLines(new JsonEncoder.withIndent("  ").convert(this)),
+    sink.writeAll(splitLines(JsonEncoder.withIndent("  ").convert(this)),
         jsonExtraIndent);
     sink.writeln("''');");
   }
@@ -106,7 +106,7 @@
   Future<Null> run(Chain suite, Set<String> selectors,
       {int shards = 1,
       int shard = 0,
-      Logger logger: const StdoutLogger()}) async {
+      Logger logger = const StdoutLogger()}) async {
     assert(shards >= 1, "Invalid shards count: $shards");
     assert(0 <= shard && shard < shards,
         "Invalid shard index: $shard, not in range [0,$shards[.");
@@ -114,11 +114,11 @@
         .where((s) => s.endsWith('...'))
         .map((s) => s.substring(0, s.length - 3))
         .toList();
-    TestExpectations expectations = await ReadTestExpectations(
+    TestExpectations expectations = await readTestExpectations(
         <String>[suite.statusFile!.toFilePath()], {}, expectationSet);
     Stream<TestDescription> stream = list(suite);
     if (suite.processMultitests) {
-      stream = stream.transform(new MultitestTransformer());
+      stream = stream.transform(MultitestTransformer());
     }
     List<TestDescription> descriptions = await stream.toList();
     descriptions.sort();
@@ -156,7 +156,7 @@
         }
       }
       if (shouldSkip) continue;
-      final StringBuffer sb = new StringBuffer();
+      final StringBuffer sb = StringBuffer();
       final Step? lastStep = steps.isNotEmpty ? steps.last : null;
       final Iterator<Step> iterator = steps.iterator;
 
@@ -199,7 +199,7 @@
             }
           }, printLineOnStdout: sb.writeln);
         } else {
-          future = new Future.value(null);
+          future = Future.value(null);
         }
         future = future.then((_currentResult) async {
           Result? currentResult = _currentResult;
@@ -260,7 +260,7 @@
   }
 
   Stream<TestDescription> list(Chain suite) async* {
-    Directory testRoot = new Directory.fromUri(suite.uri);
+    Directory testRoot = Directory.fromUri(suite.uri);
     if (await testRoot.exists()) {
       Stream<FileSystemEntity> files =
           testRoot.list(recursive: true, followLinks: false);
@@ -269,7 +269,7 @@
         String path = entity.uri.path;
         if (suite.exclude.any((RegExp r) => path.contains(r))) continue;
         if (suite.pattern.any((RegExp r) => path.contains(r))) {
-          yield new FileBasedTestDescription(suite.uri, entity);
+          yield FileBasedTestDescription(suite.uri, entity);
         }
       }
     } else {
@@ -356,15 +356,15 @@
   Future<Result<O>> run(I input, C context);
 
   Result<O> unhandledError(error, StackTrace trace) {
-    return new Result<O>.crash(error, trace);
+    return Result<O>.crash(error, trace);
   }
 
-  Result<O> pass(O output) => new Result<O>.pass(output);
+  Result<O> pass(O output) => Result<O>.pass(output);
 
-  Result<O> crash(error, StackTrace trace) => new Result<O>.crash(error, trace);
+  Result<O> crash(error, StackTrace trace) => Result<O>.crash(error, trace);
 
   Result<O> fail(O output, [error, StackTrace? trace]) {
-    return new Result<O>.fail(output, error, trace);
+    return Result<O>.fail(output, error, trace);
   }
 }
 
@@ -373,7 +373,7 @@
 
   final Expectation outcome;
 
-  final error;
+  final Object? error;
 
   final StackTrace? trace;
 
@@ -389,10 +389,14 @@
   ///
   final bool canBeFixWithUpdateExpectations;
 
-  Result(this.output, this.outcome, this.error,
-      {this.trace,
-      this.autoFixCommand,
-      this.canBeFixWithUpdateExpectations: false});
+  Result(
+    this.output,
+    this.outcome,
+    this.error, {
+    this.trace,
+    this.autoFixCommand,
+    this.canBeFixWithUpdateExpectations = false,
+  });
 
   Result.pass(O output) : this(output, Expectation.Pass, null);
 
@@ -411,12 +415,11 @@
   }
 
   Result<O> copyWithOutcome(Expectation outcome) {
-    return new Result<O>(output, outcome, error, trace: trace)
-      ..logs.addAll(logs);
+    return Result<O>(output, outcome, error, trace: trace)..logs.addAll(logs);
   }
 
   Result<O2> copyWithOutput<O2>(O2 output) {
-    return new Result<O2>(output, outcome, error,
+    return Result<O2>(output, outcome, error,
         trace: trace,
         autoFixCommand: autoFixCommand,
         canBeFixWithUpdateExpectations: canBeFixWithUpdateExpectations)
@@ -428,8 +431,7 @@
 Future<Null> runChain(CreateContext f, Map<String, String> environment,
     Set<String> selectors, String jsonText) {
   return withErrorHandling(() async {
-    Chain suite =
-        new Suite.fromJsonMap(Uri.base, json.decode(jsonText)) as Chain;
+    Chain suite = Suite.fromJsonMap(Uri.base, json.decode(jsonText)) as Chain;
     print("Running ${suite.name}");
     ChainContext context = await f(suite, environment);
     return context.run(suite, selectors);
diff --git a/pkg/testing/lib/src/discover.dart b/pkg/testing/lib/src/discover.dart
index 193590b..3b1644d 100644
--- a/pkg/testing/lib/src/discover.dart
+++ b/pkg/testing/lib/src/discover.dart
@@ -22,11 +22,11 @@
 Stream<FileBasedTestDescription> listTests(List<Uri> testRoots,
     {Pattern? pattern}) {
   StreamController<FileBasedTestDescription> controller =
-      new StreamController<FileBasedTestDescription>();
+      StreamController<FileBasedTestDescription>();
   Map<Uri, StreamSubscription?> subscriptions = <Uri, StreamSubscription>{};
   for (Uri testRootUri in testRoots) {
     subscriptions[testRootUri] = null;
-    Directory testRoot = new Directory.fromUri(testRootUri);
+    Directory testRoot = Directory.fromUri(testRootUri);
     testRoot.exists().then((bool exists) {
       if (exists) {
         Stream<FileSystemEntity> stream =
@@ -75,10 +75,10 @@
 Uri computeDartSdk() {
   String? dartSdkPath = Platform.environment["DART_SDK"] ?? _dartSdk;
   if (dartSdkPath != null) {
-    return Uri.base.resolveUri(new Uri.file(dartSdkPath));
+    return Uri.base.resolveUri(Uri.file(dartSdkPath));
   } else {
     return Uri.base
-        .resolveUri(new Uri.file(Platform.resolvedExecutable))
+        .resolveUri(Uri.file(Platform.resolvedExecutable))
         .resolve("../");
   }
 }
diff --git a/pkg/testing/lib/src/error_handling.dart b/pkg/testing/lib/src/error_handling.dart
index 872f2f0..29c77e5 100644
--- a/pkg/testing/lib/src/error_handling.dart
+++ b/pkg/testing/lib/src/error_handling.dart
@@ -13,7 +13,7 @@
 import 'log.dart';
 
 Future<T?> withErrorHandling<T>(Future<T> f(), {Logger? logger}) async {
-  final ReceivePort port = new ReceivePort();
+  final ReceivePort port = ReceivePort();
   try {
     return await f();
   } catch (e, trace) {
diff --git a/pkg/testing/lib/src/expectation.dart b/pkg/testing/lib/src/expectation.dart
index 153adee..41ec9ca 100644
--- a/pkg/testing/lib/src/expectation.dart
+++ b/pkg/testing/lib/src/expectation.dart
@@ -13,20 +13,16 @@
 /// use the canonical expectation instead of a more specific one. Note this
 /// isn't implemented yet.
 class Expectation {
-  static const Expectation Pass =
-      const Expectation("Pass", ExpectationGroup.Pass);
+  static const Expectation Pass = Expectation("Pass", ExpectationGroup.Pass);
 
-  static const Expectation Crash =
-      const Expectation("Crash", ExpectationGroup.Crash);
+  static const Expectation Crash = Expectation("Crash", ExpectationGroup.Crash);
 
   static const Expectation Timeout =
-      const Expectation("Timeout", ExpectationGroup.Timeout);
+      Expectation("Timeout", ExpectationGroup.Timeout);
 
-  static const Expectation Fail =
-      const Expectation("Fail", ExpectationGroup.Fail);
+  static const Expectation Fail = Expectation("Fail", ExpectationGroup.Fail);
 
-  static const Expectation Skip =
-      const Expectation("Skip", ExpectationGroup.Skip);
+  static const Expectation Skip = Expectation("Skip", ExpectationGroup.Skip);
 
   final String name;
 
@@ -61,18 +57,17 @@
 }
 
 class ExpectationSet {
-  static const ExpectationSet Default =
-      const ExpectationSet(const <String, Expectation>{
+  static const ExpectationSet Default = ExpectationSet(<String, Expectation>{
     "pass": Expectation.Pass,
     "crash": Expectation.Crash,
     "timeout": Expectation.Timeout,
     "fail": Expectation.Fail,
     "skip": Expectation.Skip,
     "missingcompiletimeerror":
-        const Expectation("MissingCompileTimeError", ExpectationGroup.Fail),
+        Expectation("MissingCompileTimeError", ExpectationGroup.Fail),
     "missingruntimeerror":
-        const Expectation("MissingRuntimeError", ExpectationGroup.Fail),
-    "runtimeerror": const Expectation("RuntimeError", ExpectationGroup.Fail),
+        Expectation("MissingRuntimeError", ExpectationGroup.Fail),
+    "runtimeerror": Expectation("RuntimeError", ExpectationGroup.Fail),
   });
 
   final Map<String, Expectation> internalMap;
@@ -86,7 +81,7 @@
 
   factory ExpectationSet.fromJsonList(List data) {
     Map<String, Expectation> internalMap =
-        new Map<String, Expectation>.from(Default.internalMap);
+        Map<String, Expectation>.from(Default.internalMap);
     for (Map map in data) {
       String? name;
       String? group;
@@ -112,14 +107,14 @@
       if (group == null) {
         throw "No group provided in '$map'";
       }
-      Expectation expectation = new Expectation(name!, groupFromString(group!));
+      Expectation expectation = Expectation(name!, groupFromString(group!));
       name = name!.toLowerCase();
       if (internalMap.containsKey(name)) {
         throw "Duplicated expectation name: '$name'.";
       }
       internalMap[name!] = expectation;
     }
-    return new ExpectationSet(internalMap);
+    return ExpectationSet(internalMap);
   }
 }
 
diff --git a/pkg/testing/lib/src/log.dart b/pkg/testing/lib/src/log.dart
index d46ab0a..a948232 100644
--- a/pkg/testing/lib/src/log.dart
+++ b/pkg/testing/lib/src/log.dart
@@ -28,7 +28,7 @@
 
 final String eraseLine = enableAnsiEscapes ? eraseLineCodes : "";
 
-final Stopwatch wallclock = new Stopwatch()..start();
+final Stopwatch wallclock = Stopwatch()..start();
 
 bool _isVerbose = const bool.fromEnvironment("verbose");
 
@@ -195,13 +195,13 @@
   void noticeFrameworkCatchError(error, StackTrace stackTrace) {}
 }
 
-String pad(Object o, int pad, {String filler: " "}) {
+String pad(Object o, int pad, {String filler = " "}) {
   String result = (filler * pad) + "$o";
   return result.substring(result.length - pad);
 }
 
 String numberedLines(String text) {
-  StringBuffer result = new StringBuffer();
+  StringBuffer result = StringBuffer();
   int lineNumber = 1;
   List<String> lines = splitLines(text);
   int pad = "${lines.length}".length;
@@ -217,5 +217,5 @@
 }
 
 List<String> splitLines(String text) {
-  return text.split(new RegExp('^', multiLine: true));
+  return text.split(RegExp('^', multiLine: true));
 }
diff --git a/pkg/testing/lib/src/multitest.dart b/pkg/testing/lib/src/multitest.dart
index 62bb63e..14586e1 100644
--- a/pkg/testing/lib/src/multitest.dart
+++ b/pkg/testing/lib/src/multitest.dart
@@ -26,10 +26,10 @@
 
 class MultitestTransformer
     extends StreamTransformerBase<TestDescription, TestDescription> {
-  static RegExp multitestMarker = new RegExp(r"//[#/]");
+  static RegExp multitestMarker = RegExp(r"//[#/]");
   static int _multitestMarkerLength = 3;
 
-  static const List<String> validOutcomesList = const <String>[
+  static const List<String> validOutcomesList = <String>[
     "ok",
     "syntax error",
     "compile-time error",
@@ -39,8 +39,7 @@
     "checked mode compile-time error",
   ];
 
-  static final Set<String> validOutcomes =
-      new Set<String>.from(validOutcomesList);
+  static final Set<String> validOutcomes = Set<String>.from(validOutcomesList);
 
   Stream<TestDescription> bind(Stream<TestDescription> stream) async* {
     List<String> errors = <String>[];
@@ -70,7 +69,7 @@
         "none": linesWithoutAnnotations,
       };
       Map<String, Set<String>> outcomes = <String, Set<String>>{
-        "none": new Set<String>(),
+        "none": Set<String>(),
       };
       int lineNumber = 0;
       for (String line in splitLines(contents!)) {
@@ -97,11 +96,11 @@
           }
         }
         if (subtestName != null) {
-          List<String> lines = testsAsLines.putIfAbsent(subtestName,
-              () => new List<String>.from(linesWithoutAnnotations));
+          List<String> lines = testsAsLines.putIfAbsent(
+              subtestName, () => List<String>.from(linesWithoutAnnotations));
           lines.add(line);
           Set<String> subtestOutcomes =
-              outcomes.putIfAbsent(subtestName, () => new Set<String>());
+              outcomes.putIfAbsent(subtestName, () => Set<String>());
           if (subtestOutcomesList!.length != 1 ||
               subtestOutcomesList.single != "continued") {
             for (String outcome in subtestOutcomesList) {
@@ -123,14 +122,14 @@
       }
       Uri root = Uri.base.resolve("generated/");
       Directory generated =
-          new Directory.fromUri(root.resolve(multitest.shortName));
+          Directory.fromUri(root.resolve(multitest.shortName));
       generated = await generated.create(recursive: true);
       for (MapEntry<String, List<String>> entry in testsAsLines.entries) {
         String name = entry.key;
         List<String> lines = entry.value;
         Uri uri = generated.uri.resolve("${name}_generated.dart");
         FileBasedTestDescription subtest =
-            new FileBasedTestDescription(root, new File.fromUri(uri));
+            FileBasedTestDescription(root, File.fromUri(uri));
         subtest.multitestExpectations = outcomes[name];
         await subtest.file.writeAsString(lines.join(""));
         yield subtest;
diff --git a/pkg/testing/lib/src/run.dart b/pkg/testing/lib/src/run.dart
index 4567236..0db5dc7 100644
--- a/pkg/testing/lib/src/run.dart
+++ b/pkg/testing/lib/src/run.dart
@@ -54,7 +54,7 @@
     Uri? me,
     int shards = 1,
     int shard = 0,
-    Logger logger: const StdoutLogger()}) {
+    Logger logger = const StdoutLogger()}) {
   me ??= Platform.script;
   return withErrorHandling(() async {
     TestRoot testRoot = await computeTestRoot(configurationPath, me);
@@ -63,7 +63,7 @@
     for (Chain suite in testRoot.toolChains) {
       if (me == suite.source) {
         ChainContext context = await f(suite, cl.environment);
-        await context.run(suite, new Set<String>.from(cl.selectors),
+        await context.run(suite, Set<String>.from(cl.selectors),
             shards: shards, shard: shard, logger: logger);
       }
     }
@@ -104,8 +104,8 @@
     List<Suite> suites = root.suites
         .where((Suite suite) => suiteNames.contains(suite.name))
         .toList();
-    SuiteRunner runner = new SuiteRunner(suites, <String, String>{},
-        const <String>[], new Set<String>(), new Set<String>());
+    SuiteRunner runner = SuiteRunner(suites, <String, String>{},
+        const <String>[], Set<String>(), Set<String>());
     String? program = await runner.generateDartProgram();
     await runner.analyze(root.packages);
     if (program != null) {
@@ -117,8 +117,8 @@
 Future<Null> runProgram(String program, Uri packages) async {
   const StdoutLogger().logMessage("Running:");
   const StdoutLogger().logNumberedLines(program);
-  Uri dataUri = new Uri.dataFromString(program);
-  ReceivePort exitPort = new ReceivePort();
+  Uri dataUri = Uri.dataFromString(program);
+  ReceivePort exitPort = ReceivePort();
   Isolate isolate = await Isolate.spawnUri(dataUri, <String>[], null,
       paused: true,
       onExit: exitPort.sendPort,
@@ -137,7 +137,7 @@
   subscription.cancel();
   return error == null
       ? null
-      : new Future<Null>.error(error![0], new StackTrace.fromString(error![1]));
+      : Future<Null>.error(error![0], StackTrace.fromString(error![1]));
 }
 
 class SuiteRunner {
@@ -164,9 +164,9 @@
 
   Future<String?> generateDartProgram() async {
     testUris.clear();
-    StringBuffer imports = new StringBuffer();
-    StringBuffer dart = new StringBuffer();
-    StringBuffer chain = new StringBuffer();
+    StringBuffer imports = StringBuffer();
+    StringBuffer dart = StringBuffer();
+    StringBuffer chain = StringBuffer();
     bool hasRunnableTests = false;
 
     await for (FileBasedTestDescription description in listDescriptions()) {
diff --git a/pkg/testing/lib/src/run_tests.dart b/pkg/testing/lib/src/run_tests.dart
index 03d5d3d..71ae5e5 100644
--- a/pkg/testing/lib/src/run_tests.dart
+++ b/pkg/testing/lib/src/run_tests.dart
@@ -33,7 +33,7 @@
   Set<String> get skip => commaSeparated("--skip=");
 
   Set<String> commaSeparated(String prefix) {
-    return new Set<String>.from(options.expand((String s) {
+    return Set<String>.from(options.expand((String s) {
       if (!s.startsWith(prefix)) return const [];
       s = s.substring(prefix.length);
       return s.split(",");
@@ -76,7 +76,7 @@
     String configurationPath;
     if (configurationPaths.length == 1) {
       configurationPath = configurationPaths.single;
-      File file = new File(configurationPath);
+      File file = File(configurationPath);
       if (await file.exists()) {
         // If [configurationPath] exists as a file, use the absolute URI. This
         // handles absolute paths on Windows.
@@ -84,8 +84,8 @@
       }
     } else {
       configurationPath = "testing.json";
-      if (!await new File(configurationPath).exists()) {
-        Directory test = new Directory("test");
+      if (!await File(configurationPath).exists()) {
+        Directory test = Directory("test");
         if (await test.exists()) {
           List<FileSystemEntity> candidates = await test
               .list(recursive: true, followLinks: false)
@@ -113,8 +113,7 @@
         .logMessage("Reading configuration file '$configurationPath'.");
     Uri? configuration =
         await Isolate.resolvePackageUri(Uri.base.resolve(configurationPath));
-    if (configuration == null ||
-        !await new File.fromUri(configuration).exists()) {
+    if (configuration == null || !await File.fromUri(configuration).exists()) {
       return fail("Couldn't locate: '$configurationPath'.");
     }
     return configuration;
@@ -124,14 +123,14 @@
     int index = arguments.indexOf("--");
     Set<String> options;
     if (index != -1) {
-      options = new Set<String>.from(arguments.getRange(0, index));
+      options = Set<String>.from(arguments.getRange(0, index));
       arguments = arguments.sublist(index + 1);
     } else {
       options = arguments.where((argument) => argument.startsWith("-")).toSet();
       arguments =
           arguments.where((argument) => !argument.startsWith("-")).toList();
     }
-    return new CommandLine(options, arguments);
+    return CommandLine(options, arguments);
   }
 }
 
@@ -153,11 +152,11 @@
         print("Use --verbose to display more details.");
       }
       TestRoot root = await TestRoot.fromUri(configuration);
-      SuiteRunner runner = new SuiteRunner(
+      SuiteRunner runner = SuiteRunner(
           root.suites, environment, cl.selectors, cl.selectedSuites, cl.skip);
       String? program = await runner.generateDartProgram();
       bool hasAnalyzerSuites = await runner.analyze(root.packages);
-      Stopwatch sw = new Stopwatch()..start();
+      Stopwatch sw = Stopwatch()..start();
       if (program == null) {
         if (!hasAnalyzerSuites) {
           fail("No tests configured.");
@@ -174,7 +173,7 @@
       for (String name in tests.keys) {
         const StdoutLogger()
             .logTestStart(completed, 0, tests.length, null, null);
-        StringBuffer sb = new StringBuffer();
+        StringBuffer sb = StringBuffer();
         try {
           await runGuarded(() {
             print("Running test $name");
diff --git a/pkg/testing/lib/src/stdio_process.dart b/pkg/testing/lib/src/stdio_process.dart
index 587a07f..ca5d6ab 100644
--- a/pkg/testing/lib/src/stdio_process.dart
+++ b/pkg/testing/lib/src/stdio_process.dart
@@ -23,17 +23,17 @@
 
   StdioProcess(this.exitCode, this.output);
 
-  Result<int> toResult({int expected: 0}) {
+  Result<int> toResult({int expected = 0}) {
     if (exitCode == expected) {
-      return new Result<int>.pass(exitCode);
+      return Result<int>.pass(exitCode);
     } else {
-      return new Result<int>(
+      return Result<int>(
           exitCode, ExpectationSet.Default["RuntimeError"], output);
     }
   }
 
   static StreamTransformer<String, String> transformToStdio(Stdout stdio) {
-    return new StreamTransformer<String, String>.fromHandlers(
+    return StreamTransformer<String, String>.fromHandlers(
         handleData: (String data, EventSink<String> sink) {
       sink.add(data);
       stdio.write(data);
@@ -42,15 +42,15 @@
 
   static Future<StdioProcess> run(String executable, List<String> arguments,
       {String? input,
-      Duration? timeout: const Duration(seconds: 60),
-      bool suppressOutput: true,
-      bool runInShell: false}) async {
+      Duration? timeout = const Duration(seconds: 60),
+      bool suppressOutput = true,
+      bool runInShell = false}) async {
     Process process =
         await Process.start(executable, arguments, runInShell: runInShell);
     Timer? timer;
-    StringBuffer sb = new StringBuffer();
+    StringBuffer sb = StringBuffer();
     if (timeout != null) {
-      timer = new Timer(timeout, () {
+      timer = Timer(timeout, () {
         sb.write("Process timed out: ");
         sb.write(executable);
         sb.write(" ");
@@ -58,7 +58,7 @@
         sb.writeln();
         sb.writeln("Sending SIGTERM to process");
         process.kill();
-        timer = new Timer(const Duration(seconds: 10), () {
+        timer = Timer(const Duration(seconds: 10), () {
           sb.writeln("Sending SIGKILL to process");
           process.kill(ProcessSignal.sigkill);
         });
@@ -75,13 +75,15 @@
       stdoutStream = stdoutStream.transform(transformToStdio(io.stdout));
       stderrStream = stderrStream.transform(transformToStdio(io.stderr));
     }
-    Future<List<String>> stdoutFuture = stdoutStream.toList() as Future<List<String>>;
-    Future<List<String>> stderrFuture = stderrStream.toList() as Future<List<String>>;
+    Future<List<String>> stdoutFuture =
+        stdoutStream.toList() as Future<List<String>>;
+    Future<List<String>> stderrFuture =
+        stderrStream.toList() as Future<List<String>>;
     int exitCode = await process.exitCode;
     timer?.cancel();
     sb.writeAll(await stdoutFuture);
     sb.writeAll(await stderrFuture);
     await closeFuture;
-    return new StdioProcess(exitCode, "$sb");
+    return StdioProcess(exitCode, "$sb");
   }
 }
diff --git a/pkg/testing/lib/src/suite.dart b/pkg/testing/lib/src/suite.dart
index b159797..5779064 100644
--- a/pkg/testing/lib/src/suite.dart
+++ b/pkg/testing/lib/src/suite.dart
@@ -23,13 +23,13 @@
     String name = json["name"];
     switch (kind) {
       case "dart":
-        return new Dart.fromJsonMap(base, json, name);
+        return Dart.fromJsonMap(base, json, name);
 
       case "chain":
-        return new Chain.fromJsonMap(base, json, name, kind);
+        return Chain.fromJsonMap(base, json, name, kind);
 
       case "test_dart":
-        return new TestDart.fromJsonMap(base, json, name, kind);
+        return TestDart.fromJsonMap(base, json, name, kind);
 
       default:
         throw "Suite '$name' has unknown kind '$kind'.";
@@ -78,10 +78,10 @@
   factory Dart.fromJsonMap(Uri base, Map json, String name) {
     Uri uri = base.resolve(json["path"]);
     List<RegExp> pattern =
-        new List<RegExp>.from(json["pattern"].map((String p) => new RegExp(p)));
+        List<RegExp>.from(json["pattern"].map((String p) => RegExp(p)));
     List<RegExp> exclude =
-        new List<RegExp>.from(json["exclude"].map((String p) => new RegExp(p)));
-    return new Dart(name, uri, pattern, exclude);
+        List<RegExp>.from(json["exclude"].map((String p) => RegExp(p)));
+    return Dart(name, uri, pattern, exclude);
   }
 
   String toString() => "Dart($name, $uri, $pattern, $exclude)";
diff --git a/pkg/testing/lib/src/test_dart.dart b/pkg/testing/lib/src/test_dart.dart
index 7cf1f89..9425bc1 100644
--- a/pkg/testing/lib/src/test_dart.dart
+++ b/pkg/testing/lib/src/test_dart.dart
@@ -30,9 +30,9 @@
     String common = json["common"] ?? "";
     String processes = json["processes"] ?? "-j${Platform.numberOfProcessors}";
     List<String> commandLines = json["command-lines"] == null
-        ? new List<String>.from(json["command-lines"])
+        ? List<String>.from(json["command-lines"])
         : <String>[];
-    return new TestDart(name, common, processes, commandLines);
+    return TestDart(name, common, processes, commandLines);
   }
 
   void writeFirstImportOn(StringSink sink) {
diff --git a/pkg/testing/lib/src/test_dart/path.dart b/pkg/testing/lib/src/test_dart/path.dart
index f0b5b51..b4566c9 100644
--- a/pkg/testing/lib/src/test_dart/path.dart
+++ b/pkg/testing/lib/src/test_dart/path.dart
@@ -49,6 +49,12 @@
   }
 
   int get hashCode => _path.hashCode;
+
+  @override
+  bool operator ==(Object other) {
+    return other is Path && _path == other._path;
+  }
+
   bool get isEmpty => _path.isEmpty;
   bool get isAbsolute => _path.startsWith('/');
   bool get hasTrailingSeparator => _path.endsWith('/');
@@ -61,7 +67,7 @@
     // Throws exception if an impossible case is reached.
     if (base.isAbsolute != isAbsolute ||
         base.isWindowsShare != isWindowsShare) {
-      throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
+      throw ArgumentError("Invalid case of Path.relativeTo(base):\n"
           "  Path and base must both be relative, or both absolute.\n"
           "  Arguments: $_path.relativeTo($base)");
     }
@@ -81,22 +87,22 @@
           if (basePath[1] != _path[1]) {
             // Replace the drive letter in basePath with that from _path.
             basePath = '/${_path[1]}:/${basePath.substring(4)}';
-            base = new Path(basePath);
+            base = Path(basePath);
           }
         } else {
-          throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
+          throw ArgumentError("Invalid case of Path.relativeTo(base):\n"
               "  Base path and target path are on different Windows drives.\n"
               "  Arguments: $_path.relativeTo($base)");
         }
       } else if (baseHasDrive != pathHasDrive) {
-        throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
+        throw ArgumentError("Invalid case of Path.relativeTo(base):\n"
             "  Base path must start with a drive letter if and "
             "only if target path does.\n"
             "  Arguments: $_path.relativeTo($base)");
       }
     }
     if (_path.startsWith(basePath)) {
-      if (_path == basePath) return new Path('.');
+      if (_path == basePath) return Path('.');
       // There must be a '/' at the end of the match, or immediately after.
       int matchEnd = basePath.length;
       if (_path[matchEnd - 1] == '/' || _path[matchEnd] == '/') {
@@ -104,7 +110,7 @@
         while (matchEnd < _path.length && _path[matchEnd] == '/') {
           matchEnd++;
         }
-        return new Path(_path.substring(matchEnd)).canonicalize();
+        return Path(_path.substring(matchEnd)).canonicalize();
       }
     }
 
@@ -124,7 +130,7 @@
     final segments = <String>[];
 
     if (common < baseSegments.length && baseSegments[common] == '..') {
-      throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
+      throw ArgumentError("Invalid case of Path.relativeTo(base):\n"
           "  Base path has more '..'s than path does.\n"
           "  Arguments: $_path.relativeTo($base)");
     }
@@ -140,22 +146,21 @@
     if (hasTrailingSeparator) {
       segments.add('');
     }
-    return new Path(segments.join('/'));
+    return Path(segments.join('/'));
   }
 
   Path join(Path further) {
     if (further.isAbsolute) {
-      throw new ArgumentError(
-          "Path.join called with absolute Path as argument.");
+      throw ArgumentError("Path.join called with absolute Path as argument.");
     }
     if (isEmpty) {
       return further.canonicalize();
     }
     if (hasTrailingSeparator) {
-      var joined = new Path._internal('$_path${further}', isWindowsShare);
+      var joined = Path._internal('$_path${further}', isWindowsShare);
       return joined.canonicalize();
     }
-    var joined = new Path._internal('$_path/${further}', isWindowsShare);
+    var joined = Path._internal('$_path/${further}', isWindowsShare);
     return joined.canonicalize();
   }
 
@@ -193,7 +198,7 @@
     bool isAbs = isAbsolute;
     List segs = segments();
     String? drive;
-    if (isAbs && !segs.isEmpty && segs[0].length == 2 && segs[0][1] == ':') {
+    if (isAbs && segs.isNotEmpty && segs[0].length == 2 && segs[0][1] == ':') {
       drive = segs[0];
       segs.removeRange(0, 1);
     }
@@ -244,7 +249,7 @@
         segmentsToJoin.add('');
       }
     }
-    return new Path._internal(segmentsToJoin.join('/'), isWindowsShare);
+    return Path._internal(segmentsToJoin.join('/'), isWindowsShare);
   }
 
   String toNativePath() {
@@ -275,11 +280,11 @@
 
   Path append(String finalSegment) {
     if (isEmpty) {
-      return new Path._internal(finalSegment, isWindowsShare);
+      return Path._internal(finalSegment, isWindowsShare);
     } else if (hasTrailingSeparator) {
-      return new Path._internal('$_path$finalSegment', isWindowsShare);
+      return Path._internal('$_path$finalSegment', isWindowsShare);
     } else {
-      return new Path._internal('$_path/$finalSegment', isWindowsShare);
+      return Path._internal('$_path/$finalSegment', isWindowsShare);
     }
   }
 
@@ -298,10 +303,12 @@
 
   Path get directoryPath {
     int pos = _path.lastIndexOf('/');
-    if (pos < 0) return new Path('');
-    while (pos > 0 && _path[pos - 1] == '/') --pos;
+    if (pos < 0) return Path('');
+    while (pos > 0 && _path[pos - 1] == '/') {
+      --pos;
+    }
     var dirPath = (pos > 0) ? _path.substring(0, pos) : '/';
-    return new Path._internal(dirPath, isWindowsShare);
+    return Path._internal(dirPath, isWindowsShare);
   }
 
   String get filename {
diff --git a/pkg/testing/lib/src/test_dart/status_expression.dart b/pkg/testing/lib/src/test_dart/status_expression.dart
index 395483a..2fd922b 100644
--- a/pkg/testing/lib/src/test_dart/status_expression.dart
+++ b/pkg/testing/lib/src/test_dart/status_expression.dart
@@ -4,31 +4,29 @@
 
 library test_dart_copy.status_expression;
 
-/**
- * Parse and evaluate expressions in a .status file for Dart and V8.
- * There are set expressions and Boolean expressions in a .status file.
- * The grammar is:
- *   BooleanExpression := $variableName == value | $variableName != value |
- *                        $variableName | (BooleanExpression) |
- *                        BooleanExpression && BooleanExpression |
- *                        BooleanExpression || BooleanExpression
- *
- *   SetExpression := value | (SetExpression) |
- *                    SetExpression || SetExpression |
- *                    SetExpression if BooleanExpression |
- *                    SetExpression , SetExpression
- *
- *  Productions are listed in order of precedence, and the || and , operators
- *  both evaluate to set union, but with different precedence.
- *
- *  Values and variableNames are non-empty strings of word characters, matching
- *  the RegExp \w+.
- *
- *  Expressions evaluate as expected, with values of variables found in
- *  an environment passed to the evaluator.  The SetExpression "value"
- *  evaluates to a singleton set containing that value. "A if B" evaluates
- *  to A if B is true, and to the empty set if B is false.
- */
+/// Parse and evaluate expressions in a .status file for Dart and V8.
+/// There are set expressions and Boolean expressions in a .status file.
+/// The grammar is:
+///   BooleanExpression := $variableName == value | $variableName != value |
+///                        $variableName | (BooleanExpression) |
+///                        BooleanExpression && BooleanExpression |
+///                        BooleanExpression || BooleanExpression
+///
+///   SetExpression := value | (SetExpression) |
+///                    SetExpression || SetExpression |
+///                    SetExpression if BooleanExpression |
+///                    SetExpression , SetExpression
+///
+///  Productions are listed in order of precedence, and the || and , operators
+///  both evaluate to set union, but with different precedence.
+///
+///  Values and variableNames are non-empty strings of word characters, matching
+///  the RegExp \w+.
+///
+///  Expressions evaluate as expected, with values of variables found in
+///  an environment passed to the evaluator.  The SetExpression "value"
+///  evaluates to a singleton set containing that value. "A if B" evaluates
+///  to A if B is true, and to the empty set if B is false.
 
 class ExprEvaluationException {
   String error;
@@ -57,12 +55,12 @@
 
   // Tokens are : "(", ")", "$", ",", "&&", "||", "==", "!=", and (maximal) \w+.
   static final testRegexp =
-      new RegExp(r"^([()$\w\s,]|(\&\&)|(\|\|)|(\=\=)|(\!\=))+$");
-  static final regexp = new RegExp(r"[()$,]|(\&\&)|(\|\|)|(\=\=)|(\!\=)|\w+");
+      RegExp(r"^([()$\w\s,]|(\&\&)|(\|\|)|(\=\=)|(\!\=))+$");
+  static final regexp = RegExp(r"[()$,]|(\&\&)|(\|\|)|(\=\=)|(\!\=)|\w+");
 
   List<String> tokenize() {
     if (!testRegexp.hasMatch(expression)) {
-      throw new FormatException("Syntax error in '$expression'");
+      throw FormatException("Syntax error in '$expression'");
     }
     for (Match match in regexp.allMatches(expression)) {
       tokens.add(match[0]!);
@@ -103,7 +101,7 @@
   String termValue(environment) {
     var value = environment[name];
     if (value == null) {
-      throw new ExprEvaluationException("Could not find '$name' in environment "
+      throw ExprEvaluationException("Could not find '$name' in environment "
           "while evaluating status file expression.");
     }
     return value.toString();
@@ -163,9 +161,8 @@
 
   SetIf(this.left, this.right);
 
-  Set<String> evaluate(environment) => right.evaluate(environment)
-      ? left.evaluate(environment)
-      : new Set<String>();
+  Set<String> evaluate(environment) =>
+      right.evaluate(environment) ? left.evaluate(environment) : Set<String>();
   String toString() => "($left if $right)";
 }
 
@@ -174,7 +171,7 @@
 
   SetConstant(String v) : value = v.toLowerCase();
 
-  Set<String> evaluate(environment) => new Set<String>.from([value]);
+  Set<String> evaluate(environment) => Set<String>.from([value]);
   String toString() => value;
 }
 
@@ -208,7 +205,7 @@
     while (scanner.hasMore() && scanner.current == Token.UNION) {
       scanner.advance();
       SetExpression right = parseSetIf();
-      left = new SetUnion(left, right);
+      left = SetUnion(left, right);
     }
     return left;
   }
@@ -218,7 +215,7 @@
     while (scanner.hasMore() && scanner.current == "if") {
       scanner.advance();
       BooleanExpression right = parseBooleanExpression();
-      left = new SetIf(left, right);
+      left = SetIf(left, right);
     }
     return left;
   }
@@ -228,7 +225,7 @@
     while (scanner.hasMore() && scanner.current == Token.OR) {
       scanner.advance();
       SetExpression right = parseSetAtomic();
-      left = new SetUnion(left, right);
+      left = SetUnion(left, right);
     }
     return left;
   }
@@ -238,16 +235,16 @@
       scanner.advance();
       SetExpression value = parseSetExpression();
       if (scanner.current != Token.RIGHT_PAREN) {
-        throw new FormatException("Missing right parenthesis in expression");
+        throw FormatException("Missing right parenthesis in expression");
       }
       scanner.advance();
       return value;
     }
-    if (!new RegExp(r"^\w+$").hasMatch(scanner.current!)) {
-      throw new FormatException(
+    if (!RegExp(r"^\w+$").hasMatch(scanner.current!)) {
+      throw FormatException(
           "Expected identifier in expression, got ${scanner.current}");
     }
-    SetExpression value = new SetConstant(scanner.current!);
+    SetExpression value = SetConstant(scanner.current!);
     scanner.advance();
     return value;
   }
@@ -259,7 +256,7 @@
     while (scanner.hasMore() && scanner.current == Token.OR) {
       scanner.advance();
       BooleanExpression right = parseBooleanAnd();
-      left = new BooleanOperation(Token.OR, left, right);
+      left = BooleanOperation(Token.OR, left, right);
     }
     return left;
   }
@@ -269,7 +266,7 @@
     while (scanner.hasMore() && scanner.current == Token.AND) {
       scanner.advance();
       BooleanExpression right = parseBooleanAtomic();
-      left = new BooleanOperation(Token.AND, left, right);
+      left = BooleanOperation(Token.AND, left, right);
     }
     return left;
   }
@@ -279,7 +276,7 @@
       scanner.advance();
       BooleanExpression value = parseBooleanExpression();
       if (scanner.current != Token.RIGHT_PAREN) {
-        throw new FormatException("Missing right parenthesis in expression");
+        throw FormatException("Missing right parenthesis in expression");
       }
       scanner.advance();
       return value;
@@ -288,29 +285,29 @@
     // The only atomic booleans are of the form $variable == value or
     // of the form $variable.
     if (scanner.current != Token.DOLLAR_SYMBOL) {
-      throw new FormatException(
+      throw FormatException(
           "Expected \$ in expression, got ${scanner.current}");
     }
     scanner.advance();
-    if (!new RegExp(r"^\w+$").hasMatch(scanner.current!)) {
-      throw new FormatException(
+    if (!RegExp(r"^\w+$").hasMatch(scanner.current!)) {
+      throw FormatException(
           "Expected identifier in expression, got ${scanner.current}");
     }
-    TermVariable left = new TermVariable(scanner.current!);
+    TermVariable left = TermVariable(scanner.current!);
     scanner.advance();
     if (scanner.current == Token.EQUALS ||
         scanner.current == Token.NOT_EQUALS) {
       bool negate = scanner.current == Token.NOT_EQUALS;
       scanner.advance();
-      if (!new RegExp(r"^\w+$").hasMatch(scanner.current!)) {
-        throw new FormatException(
+      if (!RegExp(r"^\w+$").hasMatch(scanner.current!)) {
+        throw FormatException(
             "Expected value in expression, got ${scanner.current}");
       }
-      TermConstant right = new TermConstant(scanner.current!);
+      TermConstant right = TermConstant(scanner.current!);
       scanner.advance();
-      return new Comparison(left, right, negate);
+      return Comparison(left, right, negate);
     } else {
-      return new BooleanVariable(left);
+      return BooleanVariable(left);
     }
   }
 }
diff --git a/pkg/testing/lib/src/test_dart/status_file_parser.dart b/pkg/testing/lib/src/test_dart/status_file_parser.dart
index a3d2f58..0ce5d90 100644
--- a/pkg/testing/lib/src/test_dart/status_file_parser.dart
+++ b/pkg/testing/lib/src/test_dart/status_file_parser.dart
@@ -13,10 +13,10 @@
 
 import '../expectation.dart' show Expectation, ExpectationSet;
 
-final RegExp SplitComment = new RegExp("^([^#]*)(#.*)?\$");
-final RegExp HeaderPattern = new RegExp(r"^\[([^\]]+)\]");
-final RegExp RulePattern = new RegExp(r"\s*([^: ]*)\s*:(.*)");
-final RegExp IssueNumberPattern = new RegExp("[Ii]ssue ([0-9]+)");
+final RegExp splitComment = RegExp("^([^#]*)(#.*)?\$");
+final RegExp headerPattern = RegExp(r"^\[([^\]]+)\]");
+final RegExp rulePattern = RegExp(r"\s*([^: ]*)\s*:(.*)");
+final RegExp issueNumberPattern = RegExp("[Ii]ssue ([0-9]+)");
 
 class StatusFile {
   final Path location;
@@ -47,17 +47,17 @@
   }
 }
 
-Future<TestExpectations> ReadTestExpectations(List<String> statusFilePaths,
+Future<TestExpectations> readTestExpectations(List<String> statusFilePaths,
     Map<String, String> environment, ExpectationSet expectationSet) {
-  var testExpectations = new TestExpectations(expectationSet);
+  var testExpectations = TestExpectations(expectationSet);
   return Future.wait(statusFilePaths.map((String statusFile) {
-    return ReadTestExpectationsInto(testExpectations, statusFile, environment);
+    return readTestExpectationsInto(testExpectations, statusFile, environment);
   })).then((_) => testExpectations);
 }
 
-Future<void> ReadTestExpectationsInto(TestExpectations expectations,
+Future<void> readTestExpectationsInto(TestExpectations expectations,
     String statusFilePath, Map<String, String> environment) {
-  var completer = new Completer();
+  var completer = Completer();
   List<Section> sections = <Section>[];
 
   void sectionsRead() {
@@ -71,29 +71,29 @@
     completer.complete();
   }
 
-  ReadConfigurationInto(new Path(statusFilePath), sections, sectionsRead);
+  readConfigurationInto(Path(statusFilePath), sections, sectionsRead);
   return completer.future;
 }
 
-void ReadConfigurationInto(Path path, List<Section> sections, void onDone()) {
-  StatusFile statusFile = new StatusFile(path);
-  File file = new File(path.toNativePath());
+void readConfigurationInto(Path path, List<Section> sections, void onDone()) {
+  StatusFile statusFile = StatusFile(path);
+  File file = File(path.toNativePath());
   if (!file.existsSync()) {
-    throw new Exception('Cannot find test status file $path');
+    throw Exception('Cannot find test status file $path');
   }
   int lineNumber = 0;
   Stream<String> lines = file
       .openRead()
       .cast<List<int>>()
       .transform(utf8.decoder)
-      .transform(new LineSplitter());
+      .transform(LineSplitter());
 
-  Section currentSection = new Section.always(statusFile, -1);
+  Section currentSection = Section.always(statusFile, -1);
   sections.add(currentSection);
 
   lines.listen((String line) {
     lineNumber++;
-    Match? match = SplitComment.firstMatch(line);
+    Match? match = splitComment.firstMatch(line);
     line = (match == null) ? "" : match[1]!;
     line = line.trim();
     if (line.isEmpty) return;
@@ -101,36 +101,36 @@
     // Extract the comment to get the issue number if needed.
     String comment = (match == null || match[2] == null) ? "" : match[2]!;
 
-    match = HeaderPattern.firstMatch(line);
+    match = headerPattern.firstMatch(line);
     if (match != null) {
-      String condition_string = match[1]!.trim();
-      List<String> tokens = new Tokenizer(condition_string).tokenize();
-      ExpressionParser parser = new ExpressionParser(new Scanner(tokens));
+      String conditionString = match[1]!.trim();
+      List<String> tokens = Tokenizer(conditionString).tokenize();
+      ExpressionParser parser = ExpressionParser(Scanner(tokens));
       currentSection =
-          new Section(statusFile, parser.parseBooleanExpression(), lineNumber);
+          Section(statusFile, parser.parseBooleanExpression(), lineNumber);
       sections.add(currentSection);
       return;
     }
 
-    match = RulePattern.firstMatch(line);
+    match = rulePattern.firstMatch(line);
     if (match != null) {
       String name = match[1]!.trim();
       // TODO(whesse): Handle test names ending in a wildcard (*).
-      String expression_string = match[2]!.trim();
-      List<String> tokens = new Tokenizer(expression_string).tokenize();
+      String expressionString = match[2]!.trim();
+      List<String> tokens = Tokenizer(expressionString).tokenize();
       SetExpression expression =
-          new ExpressionParser(new Scanner(tokens)).parseSetExpression();
+          ExpressionParser(Scanner(tokens)).parseSetExpression();
 
       // Look for issue number in comment.
       String? issueString = null;
-      match = IssueNumberPattern.firstMatch(comment);
+      match = issueNumberPattern.firstMatch(comment);
       if (match != null) {
         issueString = match[1];
         if (issueString == null) issueString = match[2];
       }
       int? issue = issueString != null ? int.parse(issueString) : null;
       currentSection.testRules
-          .add(new TestRule(name, expression, issue, lineNumber));
+          .add(TestRule(name, expression, issue, lineNumber));
       return;
     }
 
@@ -164,15 +164,11 @@
   Map<String, RegExp>? _regExpCache;
   Map<String, List<RegExp>>? _keyToRegExps;
 
-  /**
-   * Create a TestExpectations object. See the [expectations] method
-   * for an explanation of matching.
-   */
+  /// Create a TestExpectations object. See the [expectations] method
+  /// for an explanation of matching.
   TestExpectations(this.expectationSet) : _map = {};
 
-  /**
-   * Add a rule to the expectations.
-   */
+  /// Add a rule to the expectations.
   void addRule(TestRule testRule, Map<String, String> environment) {
     // Once we have started using the expectations we cannot add more
     // rules.
@@ -181,22 +177,20 @@
     }
     var names = testRule.expression.evaluate(environment);
     var expectations = names.map((name) => expectationSet[name]);
-    _map.putIfAbsent(testRule.name, () => new Set()).addAll(expectations);
+    _map.putIfAbsent(testRule.name, () => Set()).addAll(expectations);
   }
 
-  /**
-   * Compute the expectations for a test based on the filename.
-   *
-   * For every (key, expectation) pair. Match the key with the file
-   * name. Return the union of the expectations for all the keys
-   * that match.
-   *
-   * Normal matching splits the key and the filename into path
-   * components and checks that the anchored regular expression
-   * "^$keyComponent\$" matches the corresponding filename component.
-   */
+  /// Compute the expectations for a test based on the filename.
+  ///
+  /// For every (key, expectation) pair. Match the key with the file
+  /// name. Return the union of the expectations for all the keys
+  /// that match.
+  ///
+  /// Normal matching splits the key and the filename into path
+  /// components and checks that the anchored regular expression
+  /// "^$keyComponent\$" matches the corresponding filename component.
   Set<Expectation> expectations(String filename) {
-    var result = new Set<Expectation>();
+    var result = Set<Expectation>();
     var splitFilename = filename.split('/');
 
     // Create mapping from keys to list of RegExps once and for all.
@@ -233,12 +227,12 @@
     _map.forEach((key, expectations) {
       if (_keyToRegExps![key] != null) return;
       var splitKey = key.split('/');
-      var regExps = new List<RegExp>.generate(splitKey.length, (int i) {
+      var regExps = List<RegExp>.generate(splitKey.length, (int i) {
         var component = splitKey[i];
         var regExp = _regExpCache![component];
         if (regExp == null) {
           var pattern = "^${splitKey[i]}\$".replaceAll('*', '.*');
-          regExp = new RegExp(pattern);
+          regExp = RegExp(pattern);
           _regExpCache![component] = regExp;
         }
         return regExp;
diff --git a/pkg/testing/lib/src/test_description.dart b/pkg/testing/lib/src/test_description.dart
index 1fe0ac1..9ab7d67 100644
--- a/pkg/testing/lib/src/test_description.dart
+++ b/pkg/testing/lib/src/test_description.dart
@@ -63,7 +63,7 @@
     } else if (path.contains(pattern)) {
       hasMatch = true;
     }
-    return hasMatch ? new FileBasedTestDescription(root, entity) : null;
+    return hasMatch ? FileBasedTestDescription(root, entity) : null;
   }
 
   String formatError(String message) {
diff --git a/pkg/testing/lib/src/test_root.dart b/pkg/testing/lib/src/test_root.dart
index 554abee..0df45cd 100644
--- a/pkg/testing/lib/src/test_root.dart
+++ b/pkg/testing/lib/src/test_root.dart
@@ -56,11 +56,11 @@
   List<RegExp> get excludedFromAnalysis => analyze.exclude;
 
   Iterable<Dart> get dartSuites {
-    return new List<Dart>.from(suites.where((Suite suite) => suite is Dart));
+    return List<Dart>.from(suites.whereType<Dart>());
   }
 
   Iterable<Chain> get toolChains {
-    return new List<Chain>.from(suites.where((Suite suite) => suite is Chain));
+    return List<Chain>.from(suites.whereType<Chain>());
   }
 
   String toString() {
@@ -68,7 +68,7 @@
   }
 
   static Future<TestRoot> fromUri(Uri uri) async {
-    String jsonText = await new File.fromUri(uri).readAsString();
+    String jsonText = await File.fromUri(uri).readAsString();
     Map data = json.decode(jsonText);
 
     addDefaults(data);
@@ -76,14 +76,14 @@
     Uri packages = uri.resolve(data["packages"]);
 
     List<Suite> suites = data["suites"]
-        .map<Suite>((json) => new Suite.fromJsonMap(uri, json))
+        .map<Suite>((json) => Suite.fromJsonMap(uri, json))
         .toList();
 
     Analyze analyze = await Analyze.fromJsonMap(uri, data["analyze"], suites);
 
     suites.add(analyze);
 
-    return new TestRoot(packages, suites);
+    return TestRoot(packages, suites);
   }
 
   static void addDefaults(Map data) {
diff --git a/pkg/testing/lib/src/zone_helper.dart b/pkg/testing/lib/src/zone_helper.dart
index a378d7a..a4d0b69 100644
--- a/pkg/testing/lib/src/zone_helper.dart
+++ b/pkg/testing/lib/src/zone_helper.dart
@@ -16,14 +16,16 @@
 Future runGuarded(Future f(),
     {void Function(String)? printLineOnStdout,
     void Function(dynamic, StackTrace)? handleLateError}) {
+  // ignore: prefer_typing_uninitialized_variables
   var printWrapper;
   if (printLineOnStdout != null) {
+    // ignore: non_constant_identifier_names
     printWrapper = (_1, _2, _3, String line) {
       printLineOnStdout(line);
     };
   }
 
-  Completer completer = new Completer();
+  Completer completer = Completer();
 
   handleUncaughtError(error, StackTrace stackTrace) {
     StdoutLogger().logUncaughtError(error, stackTrace);
@@ -46,9 +48,9 @@
     }
   }
 
-  ZoneSpecification specification = new ZoneSpecification(print: printWrapper);
+  ZoneSpecification specification = ZoneSpecification(print: printWrapper);
 
-  ReceivePort errorPort = new ReceivePort();
+  ReceivePort errorPort = ReceivePort();
   Future errorFuture = errorPort.listen((_errors) {
     List errors = _errors;
     Isolate.current.removeErrorListener(errorPort.sendPort);
@@ -56,7 +58,7 @@
     var error = errors[0];
     var stackTrace = errors[1];
     if (stackTrace != null) {
-      stackTrace = new StackTrace.fromString(stackTrace);
+      stackTrace = StackTrace.fromString(stackTrace);
     }
     handleUncaughtError(error, stackTrace);
   }).asFuture();
@@ -65,7 +67,7 @@
   Isolate.current.addErrorListener(errorPort.sendPort);
   return acknowledgeControlMessages(Isolate.current).then((_) {
     runZonedGuarded(
-      () => new Future(f).then(completer.complete),
+      () => Future(f).then(completer.complete),
       handleUncaughtError,
       zoneSpecification: specification,
     );
@@ -83,7 +85,7 @@
 /// messages are things like [Isolate.addErrorListener] and
 /// [Isolate.addOnExitListener].
 Future acknowledgeControlMessages(Isolate isolate, {Capability? resume}) {
-  ReceivePort ping = new ReceivePort();
+  ReceivePort ping = ReceivePort();
   Isolate.current.ping(ping.sendPort);
   if (resume == null) {
     return ping.first;
diff --git a/pkg/testing/pubspec.yaml b/pkg/testing/pubspec.yaml
index d85f43f..f91ce28 100644
--- a/pkg/testing/pubspec.yaml
+++ b/pkg/testing/pubspec.yaml
@@ -3,5 +3,10 @@
 name: testing
 # This package is not intended for consumption on pub.dev. DO NOT publish.
 publish_to: none
+
 environment:
   sdk: '>=2.12.0 <3.0.0'
+
+# Use 'any' constraints here; we get our versions from the DEPS file.
+dev_dependency:
+  lints: any
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index d20cf54..af9539d 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -615,7 +615,7 @@
     thread->isolate_group_ = this;
     thread->field_table_values_ = nullptr;
 #if defined(DART_PRECOMPILED_RUNTIME)
-    if (object_store() != nullptr) {
+    if (object_store() != nullptr && is_mutator) {
 #define INIT_ENTRY_POINT(name)                                                 \
   thread->name##_entry_point_ = Function::EntryPointOf(object_store()->name());
       CACHED_FUNCTION_ENTRY_POINTS_LIST(INIT_ENTRY_POINT)
diff --git a/sdk/lib/_internal/vm/bin/socket_patch.dart b/sdk/lib/_internal/vm/bin/socket_patch.dart
index a70896e..ed5a892 100644
--- a/sdk/lib/_internal/vm/bin/socket_patch.dart
+++ b/sdk/lib/_internal/vm/bin/socket_patch.dart
@@ -1405,10 +1405,14 @@
         if (i == errorEvent) {
           if (!isClosing) {
             final osError = nativeGetError();
-            if (osError == null) {
-              _nativeFatal("Reporting error with OSError code of 0");
-            } else {
+            if (osError != null) {
               reportError(osError, null, osError.message);
+            } else {
+              reportError(
+                  Error(),
+                  StackTrace.current,
+                  "Error event raised in event handler : "
+                  "error condition has been reset");
             }
           }
         } else if (!isClosed) {
diff --git a/tools/VERSION b/tools/VERSION
index 8bbdaaf..5ca3105 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 260
+PRERELEASE 261
 PRERELEASE_PATCH 0
\ No newline at end of file