Version 2.16.0-123.0.dev

Merge commit '38cbbaa63d94b2ef56aaddef258fe3b2b374017c' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/documentation_cache.dart b/pkg/analysis_server/lib/src/services/completion/dart/documentation_cache.dart
index 0ca62d6..8411094 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/documentation_cache.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/documentation_cache.dart
@@ -162,17 +162,16 @@
 }
 
 extension on Map<String, DocumentationWithSummary> {
-  /// Cache the data associated with the top-level [element], and return the
-  /// [key] used for the element. This does not cache any data associated with
-  /// any other elements, including children of the [element].
-  String? cacheTopLevelElement(
-      DartdocDirectiveInfo dartdocDirectiveInfo, Element element) {
-    var key = element.name;
-    if (key == null) {
-      return null;
+  /// Cache the data associated with the [element], using the given [key].
+  DocumentationWithSummary? cacheElement(
+      DartdocDirectiveInfo dartdocDirectiveInfo, String key, Element element) {
+    var documentation = DartUnitHoverComputer.computeDocumentation(
+        dartdocDirectiveInfo, element,
+        includeSummary: true);
+    if (documentation is DocumentationWithSummary) {
+      return this[key] = documentation;
     }
-    cacheElement(dartdocDirectiveInfo, key, element);
-    return key;
+    return this[key] = DocumentationCache._emptyDocs;
   }
 
   /// Cache the data associated with the [member] element given that the key
@@ -186,15 +185,16 @@
     cacheElement(dartdocDirectiveInfo, '$parentKey.$name', member);
   }
 
-  /// Cache the data associated with the [element], using the given [key].
-  DocumentationWithSummary? cacheElement(
-      DartdocDirectiveInfo dartdocDirectiveInfo, String key, Element element) {
-    var documentation = DartUnitHoverComputer.computeDocumentation(
-        dartdocDirectiveInfo, element,
-        includeSummary: true);
-    if (documentation is DocumentationWithSummary) {
-      return this[key] = documentation;
+  /// Cache the data associated with the top-level [element], and return the
+  /// [key] used for the element. This does not cache any data associated with
+  /// any other elements, including children of the [element].
+  String? cacheTopLevelElement(
+      DartdocDirectiveInfo dartdocDirectiveInfo, Element element) {
+    var key = element.name;
+    if (key == null) {
+      return null;
     }
-    return this[key] = DocumentationCache._emptyDocs;
+    cacheElement(dartdocDirectiveInfo, key, element);
+    return key;
   }
 }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index 8ffc7d4..0e7d181 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -547,8 +547,7 @@
       var suggestion = CompletionSuggestion(CompletionSuggestionKind.IDENTIFIER,
           Relevance.label, completion, completion.length, 0, false, false);
       suggestion.element = createLocalElement(
-          request.source, protocol.ElementKind.LABEL, label.label,
-          returnType: NO_RETURN_TYPE);
+          request.source, protocol.ElementKind.LABEL, label.label);
       _add(suggestion);
     }
   }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
index 33d20fe..eef975c 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
@@ -7,11 +7,8 @@
     show CompletionSuggestion, Location;
 import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_ast_factory.dart';
-import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol
     show Element, ElementKind;
@@ -28,13 +25,6 @@
   return b.relevance.compareTo(a.relevance);
 };
 
-/// A marker used in place of `null` when a function has no return type.
-final NamedType NO_RETURN_TYPE = astFactory.namedType(
-  name: astFactory.simpleIdentifier(
-    StringToken(TokenType.IDENTIFIER, '', 0),
-  ),
-);
-
 /// Add default argument list text and ranges based on the given
 /// [requiredParams] and [namedParams].
 void addDefaultArgDetails(
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/rename_parameter.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/rename_parameter.dart
index 1072578..19ca94a 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/rename_parameter.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/rename_parameter.dart
@@ -111,20 +111,6 @@
 }
 
 extension on MethodDeclaration {
-  /// Return the parameter of this method whose name matches the given [name],
-  /// or `null` if there is no such parameter.
-  FormalParameter? parameterNamed(String name) {
-    final parameters = this.parameters;
-    if (parameters != null) {
-      for (var parameter in parameters.parameters) {
-        if (parameter.declaredElement?.name == name) {
-          return parameter;
-        }
-      }
-    }
-    return null;
-  }
-
   /// Return the element that this method overrides, or `null` if this method
   /// doesn't override any inherited member.
   ExecutableElement? overriddenElement() {
@@ -138,6 +124,20 @@
     }
     return null;
   }
+
+  /// Return the parameter of this method whose name matches the given [name],
+  /// or `null` if there is no such parameter.
+  FormalParameter? parameterNamed(String name) {
+    final parameters = this.parameters;
+    if (parameters != null) {
+      for (var parameter in parameters.parameters) {
+        if (parameter.declaredElement?.name == name) {
+          return parameter;
+        }
+      }
+    }
+    return null;
+  }
 }
 
 extension on ExecutableElement {
diff --git a/pkg/analysis_server/lib/src/utilities/extensions/ast.dart b/pkg/analysis_server/lib/src/utilities/extensions/ast.dart
index efde1c5..b92d957 100644
--- a/pkg/analysis_server/lib/src/utilities/extensions/ast.dart
+++ b/pkg/analysis_server/lib/src/utilities/extensions/ast.dart
@@ -8,6 +8,18 @@
 import 'package:analyzer/dart/element/element.dart';
 
 extension AstNodeExtensions on AstNode {
+  /// Return the [IfStatement] associated with `this`.
+  IfStatement? get enclosingIfStatement {
+    for (var node in withParents) {
+      if (node is IfStatement) {
+        return node;
+      } else if (node is! Expression) {
+        return null;
+      }
+    }
+    return null;
+  }
+
   /// Return `true` if this node has an `override` annotation.
   bool get hasOverride {
     var node = this;
@@ -62,18 +74,6 @@
 
   bool get inWhileLoop => thisOrAncestorOfType<WhileStatement>() != null;
 
-  /// Return the [IfStatement] associated with `this`.
-  IfStatement? get enclosingIfStatement {
-    for (var node in withParents) {
-      if (node is IfStatement) {
-        return node;
-      } else if (node is! Expression) {
-        return null;
-      }
-    }
-    return null;
-  }
-
   /// Return this node and all its parents.
   Iterable<AstNode> get withParents sync* {
     var current = this;
diff --git a/pkg/analysis_server/lib/src/utilities/extensions/range_factory.dart b/pkg/analysis_server/lib/src/utilities/extensions/range_factory.dart
index b143cd4..95c5384 100644
--- a/pkg/analysis_server/lib/src/utilities/extensions/range_factory.dart
+++ b/pkg/analysis_server/lib/src/utilities/extensions/range_factory.dart
@@ -89,6 +89,26 @@
     return startEnd(thisLeadingComment, thisTrailingComment);
   }
 
+  /// Return the left-most comment immediately before the [token] that is not on
+  /// the same line as the first non-comment token before the [token]. Return
+  /// the [token] if there is no such comment.
+  Token _leadingComment(LineInfo lineInfo, Token token) {
+    var previous = token.previous;
+    if (previous == null || previous.type == TokenType.EOF) {
+      return token.precedingComments ?? token;
+    }
+    var previousLine = lineInfo.getLocation(previous.offset).lineNumber;
+    Token? comment = token.precedingComments;
+    while (comment != null) {
+      var commentLine = lineInfo.getLocation(comment.offset).lineNumber;
+      if (commentLine != previousLine) {
+        break;
+      }
+      comment = comment.next;
+    }
+    return comment ?? token;
+  }
+
   /// Return the comment token immediately following the [token] if it is on the
   /// same line as the [token], or the [token] if there is no comment after the
   /// [token] or if the comment is on a different line than the [token]. If
@@ -111,24 +131,4 @@
     }
     return returnComma ? lastToken : token;
   }
-
-  /// Return the left-most comment immediately before the [token] that is not on
-  /// the same line as the first non-comment token before the [token]. Return
-  /// the [token] if there is no such comment.
-  Token _leadingComment(LineInfo lineInfo, Token token) {
-    var previous = token.previous;
-    if (previous == null || previous.type == TokenType.EOF) {
-      return token.precedingComments ?? token;
-    }
-    var previousLine = lineInfo.getLocation(previous.offset).lineNumber;
-    Token? comment = token.precedingComments;
-    while (comment != null) {
-      var commentLine = lineInfo.getLocation(comment.offset).lineNumber;
-      if (commentLine != previousLine) {
-        break;
-      }
-      comment = comment.next;
-    }
-    return comment ?? token;
-  }
 }
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index c3ec9c3..e3a94a0 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -2783,18 +2783,18 @@
 
 extension on CheckTarget<CompletionGetSuggestionDetails2Result> {
   @useResult
-  CheckTarget<String> get completion {
-    return nest(
-      value.completion,
-      (selected) => 'has completion ${valueStr(selected)}',
-    );
-  }
-
-  @useResult
   CheckTarget<SourceChange> get change {
     return nest(
       value.change,
       (selected) => 'has change ${valueStr(selected)}',
     );
   }
+
+  @useResult
+  CheckTarget<String> get completion {
+    return nest(
+      value.completion,
+      (selected) => 'has completion ${valueStr(selected)}',
+    );
+  }
 }
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index f5e2631..105ec72 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 3.1.0-dev
+* New internal API for `package:dart_style`.
+
 ## 3.0.0
 * Removed deprecated `DartType.aliasElement/aliasArguments`.
 * Removed deprecated constructors from `FeatureSet`.
diff --git a/pkg/analyzer/lib/src/clients/dart_style/rewrite_cascade.dart b/pkg/analyzer/lib/src/clients/dart_style/rewrite_cascade.dart
new file mode 100644
index 0000000..dc054a8
--- /dev/null
+++ b/pkg/analyzer/lib/src/clients/dart_style/rewrite_cascade.dart
@@ -0,0 +1,114 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/standard_ast_factory.dart';
+import 'package:analyzer/dart/ast/token.dart';
+
+/// Parenthesize the target of the [expressionStatement]'s expression (assumed
+/// to [cascadeExpression]) before removing the cascade.
+ExpressionStatement fixCascadeByParenthesizingTarget({
+  required ExpressionStatement expressionStatement,
+  required CascadeExpression cascadeExpression,
+}) {
+  assert(cascadeExpression.cascadeSections.length == 1);
+
+  var newTarget = astFactory.parenthesizedExpression(
+    Token(TokenType.OPEN_PAREN, 0)
+      ..previous = expressionStatement.beginToken.previous
+      ..next = cascadeExpression.target.beginToken,
+    cascadeExpression.target,
+    Token(TokenType.CLOSE_PAREN, 0)
+      ..previous = cascadeExpression.target.endToken
+      ..next = expressionStatement.semicolon,
+  );
+
+  return astFactory.expressionStatement(
+    astFactory.cascadeExpression(
+      newTarget,
+      cascadeExpression.cascadeSections,
+    ),
+    expressionStatement.semicolon,
+  );
+}
+
+/// Recursively insert [cascadeTarget] (the LHS of the cascade) into the
+/// LHS of the assignment expression that used to be the cascade's RHS.
+Expression insertCascadeTargetIntoExpression({
+  required Expression expression,
+  required Expression cascadeTarget,
+}) {
+  // Base case: We've recursed as deep as possible.
+  if (expression == cascadeTarget) return cascadeTarget;
+
+  // Otherwise, copy `expression` and recurse into its LHS.
+  if (expression is AssignmentExpression) {
+    return astFactory.assignmentExpression(
+      insertCascadeTargetIntoExpression(
+        expression: expression.leftHandSide,
+        cascadeTarget: cascadeTarget,
+      ),
+      expression.operator,
+      expression.rightHandSide,
+    );
+  } else if (expression is IndexExpression) {
+    var expressionTarget = expression.realTarget;
+    var question = expression.question;
+
+    // A null-aware cascade treats the `?` in `?..` as part of the token, but
+    // for a non-cascade index, it is a separate `?` token.
+    if (expression.period?.type == TokenType.QUESTION_PERIOD_PERIOD) {
+      question = _synthesizeToken(TokenType.QUESTION, expression.period!);
+    }
+
+    return astFactory.indexExpressionForTarget2(
+      target: insertCascadeTargetIntoExpression(
+        expression: expressionTarget,
+        cascadeTarget: cascadeTarget,
+      ),
+      question: question,
+      leftBracket: expression.leftBracket,
+      index: expression.index,
+      rightBracket: expression.rightBracket,
+    );
+  } else if (expression is MethodInvocation) {
+    var expressionTarget = expression.realTarget!;
+    return astFactory.methodInvocation(
+      insertCascadeTargetIntoExpression(
+        expression: expressionTarget,
+        cascadeTarget: cascadeTarget,
+      ),
+      // If we've reached the end, replace the `..` operator with `.`
+      expressionTarget == cascadeTarget
+          ? _synthesizeToken(TokenType.PERIOD, expression.operator!)
+          : expression.operator,
+      expression.methodName,
+      expression.typeArguments,
+      expression.argumentList,
+    );
+  } else if (expression is PropertyAccess) {
+    var expressionTarget = expression.realTarget;
+    return astFactory.propertyAccess(
+      insertCascadeTargetIntoExpression(
+        expression: expressionTarget,
+        cascadeTarget: cascadeTarget,
+      ),
+      // If we've reached the end, replace the `..` operator with `.`
+      expressionTarget == cascadeTarget
+          ? _synthesizeToken(TokenType.PERIOD, expression.operator)
+          : expression.operator,
+      expression.propertyName,
+    );
+  }
+  throw UnimplementedError('Unhandled ${expression.runtimeType}'
+      '($expression)');
+}
+
+/// Synthesize a token with [type] to replace the given [operator].
+///
+/// Offset, comments, and previous/next links are all preserved.
+Token _synthesizeToken(TokenType type, Token operator) =>
+    Token(type, operator.offset, operator.precedingComments)
+      ..previous = operator.previous
+      ..next = operator.next;
diff --git a/pkg/analyzer/lib/src/dart/ast/extensions.dart b/pkg/analyzer/lib/src/dart/ast/extensions.dart
index 3df0bb6..f30fcca 100644
--- a/pkg/analyzer/lib/src/dart/ast/extensions.dart
+++ b/pkg/analyzer/lib/src/dart/ast/extensions.dart
@@ -118,14 +118,14 @@
 
 /// TODO(scheglov) https://github.com/dart-lang/sdk/issues/43608
 extension IdentifierExtension on Identifier {
-  Element? get writeElement {
-    return _writeElement(this);
-  }
-
   Element? get readElement {
     return _readElement(this);
   }
 
+  Element? get writeElement {
+    return _writeElement(this);
+  }
+
   Element? get writeOrReadElement {
     return _writeElement(this) ?? staticElement;
   }
diff --git a/pkg/analyzer/lib/src/dart/element/extensions.dart b/pkg/analyzer/lib/src/dart/element/extensions.dart
index 7037407..ad00f5e 100644
--- a/pkg/analyzer/lib/src/dart/element/extensions.dart
+++ b/pkg/analyzer/lib/src/dart/element/extensions.dart
@@ -60,23 +60,6 @@
 }
 
 extension ElementExtension on Element {
-  /// Return `true` if this element is an instance member of a class or mixin.
-  ///
-  /// Only [MethodElement]s and [PropertyAccessorElement]s are supported.
-  /// We intentionally exclude [ConstructorElement]s - they can only be
-  /// invoked in instance creation expressions, and [FieldElement]s - they
-  /// cannot be invoked directly and are always accessed using corresponding
-  /// [PropertyAccessorElement]s.
-  bool get isInstanceMember {
-    var this_ = this;
-    var enclosing = this_.enclosingElement;
-    if (enclosing is ClassElement) {
-      return this_ is MethodElement && !this_.isStatic ||
-          this_ is PropertyAccessorElement && !this_.isStatic;
-    }
-    return false;
-  }
-
   /// Return `true` if this element, the enclosing class (if there is one), or
   /// the enclosing library, has been annotated with the `@doNotStore`
   /// annotation.
@@ -101,6 +84,23 @@
     return ancestor is CompilationUnitElement &&
         ancestor.enclosingElement.hasDoNotStore;
   }
+
+  /// Return `true` if this element is an instance member of a class or mixin.
+  ///
+  /// Only [MethodElement]s and [PropertyAccessorElement]s are supported.
+  /// We intentionally exclude [ConstructorElement]s - they can only be
+  /// invoked in instance creation expressions, and [FieldElement]s - they
+  /// cannot be invoked directly and are always accessed using corresponding
+  /// [PropertyAccessorElement]s.
+  bool get isInstanceMember {
+    var this_ = this;
+    var enclosing = this_.enclosingElement;
+    if (enclosing is ClassElement) {
+      return this_ is MethodElement && !this_.isStatic ||
+          this_ is PropertyAccessorElement && !this_.isStatic;
+    }
+    return false;
+  }
 }
 
 extension ParameterElementExtensions on ParameterElement {
diff --git a/pkg/analyzer/lib/src/dart/resolver/applicable_extensions.dart b/pkg/analyzer/lib/src/dart/resolver/applicable_extensions.dart
index 478c884..5d26817 100644
--- a/pkg/analyzer/lib/src/dart/resolver/applicable_extensions.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/applicable_extensions.dart
@@ -105,6 +105,17 @@
 }
 
 extension ExtensionsExtensions on Iterable<ExtensionElement> {
+  /// Extensions that can be applied, within [targetLibrary], to [targetType].
+  List<InstantiatedExtensionWithoutMember> applicableTo({
+    required LibraryElement targetLibrary,
+    required DartType targetType,
+  }) {
+    return map((e) => _NotInstantiatedExtensionWithoutMember(e)).applicableTo(
+      targetLibrary: targetLibrary,
+      targetType: targetType,
+    );
+  }
+
   List<_NotInstantiatedExtensionWithMember> hasMemberWithBaseName(
     String baseName,
   ) {
@@ -157,17 +168,6 @@
     }
     return result;
   }
-
-  /// Extensions that can be applied, within [targetLibrary], to [targetType].
-  List<InstantiatedExtensionWithoutMember> applicableTo({
-    required LibraryElement targetLibrary,
-    required DartType targetType,
-  }) {
-    return map((e) => _NotInstantiatedExtensionWithoutMember(e)).applicableTo(
-      targetLibrary: targetLibrary,
-      targetType: targetType,
-    );
-  }
 }
 
 extension NotInstantiatedExtensionsExtensions<R>
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
index aadcb78..53ec6ae 100644
--- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -1259,20 +1259,6 @@
 }
 
 extension on Annotation {
-  bool get isArray {
-    final element = this.element;
-    return element is ConstructorElement &&
-        element.ffiClass != null &&
-        element.enclosingElement.name == 'Array';
-  }
-
-  bool get isPacked {
-    final element = this.element;
-    return element is ConstructorElement &&
-        element.ffiClass != null &&
-        element.enclosingElement.name == 'Packed';
-  }
-
   bool get isAbiSpecificIntegerMapping {
     final element = this.element;
     return element is ConstructorElement &&
@@ -1280,16 +1266,12 @@
         element.enclosingElement.name ==
             FfiVerifier._abiSpecificIntegerMappingClassName;
   }
-}
 
-extension on ElementAnnotation {
   bool get isArray {
     final element = this.element;
     return element is ConstructorElement &&
         element.ffiClass != null &&
         element.enclosingElement.name == 'Array';
-    // Note: this is 'Array' instead of '_ArraySize' because it finds the
-    // forwarding factory instead of the forwarded constructor.
   }
 
   bool get isPacked {
@@ -1298,7 +1280,9 @@
         element.ffiClass != null &&
         element.enclosingElement.name == 'Packed';
   }
+}
 
+extension on ElementAnnotation {
   List<int> get arraySizeDimensions {
     assert(isArray);
     final value = computeConstantValue();
@@ -1334,6 +1318,22 @@
     return result;
   }
 
+  bool get isArray {
+    final element = this.element;
+    return element is ConstructorElement &&
+        element.ffiClass != null &&
+        element.enclosingElement.name == 'Array';
+    // Note: this is 'Array' instead of '_ArraySize' because it finds the
+    // forwarding factory instead of the forwarded constructor.
+  }
+
+  bool get isPacked {
+    final element = this.element;
+    return element is ConstructorElement &&
+        element.ffiClass != null &&
+        element.enclosingElement.name == 'Packed';
+  }
+
   int? get packedMemberAlignment {
     assert(isPacked);
     final value = computeConstantValue();
@@ -1342,6 +1342,33 @@
 }
 
 extension on Element? {
+  /// If this is a class element from `dart:ffi`, return it.
+  ClassElement? get ffiClass {
+    var element = this;
+    if (element is ConstructorElement) {
+      element = element.enclosingElement;
+    }
+    if (element is ClassElement && element.isFfiClass) {
+      return element;
+    }
+    return null;
+  }
+
+  /// Return `true` if this represents the class `AbiSpecificInteger`.
+  bool get isAbiSpecificInteger {
+    final element = this;
+    return element is ClassElement &&
+        element.name == FfiVerifier._abiSpecificIntegerClassName &&
+        element.isFfiClass;
+  }
+
+  /// Return `true` if this represents a subclass of the class
+  /// `AbiSpecificInteger`.
+  bool get isAbiSpecificIntegerSubclass {
+    final element = this;
+    return element is ClassElement && element.supertype.isAbiSpecificInteger;
+  }
+
   /// Return `true` if this represents the extension `AllocatorAlloc`.
   bool get isAllocatorExtension {
     final element = this;
@@ -1350,6 +1377,14 @@
         element.isFfiExtension;
   }
 
+  /// Return `true` if this represents the extension `DynamicLibraryExtension`.
+  bool get isDynamicLibraryExtension {
+    final element = this;
+    return element is ExtensionElement &&
+        element.name == 'DynamicLibraryExtension' &&
+        element.isFfiExtension;
+  }
+
   bool get isNativeFunctionPointerExtension {
     final element = this;
     return element is ExtensionElement &&
@@ -1371,14 +1406,6 @@
         element.isFfiExtension;
   }
 
-  /// Return `true` if this represents the extension `DynamicLibraryExtension`.
-  bool get isDynamicLibraryExtension {
-    final element = this;
-    return element is ExtensionElement &&
-        element.name == 'DynamicLibraryExtension' &&
-        element.isFfiExtension;
-  }
-
   /// Return `true` if this represents the class `Pointer`.
   bool get isPointer {
     final element = this;
@@ -1414,33 +1441,6 @@
     final element = this;
     return element is ClassElement && element.supertype.isUnion;
   }
-
-  /// Return `true` if this represents the class `AbiSpecificInteger`.
-  bool get isAbiSpecificInteger {
-    final element = this;
-    return element is ClassElement &&
-        element.name == FfiVerifier._abiSpecificIntegerClassName &&
-        element.isFfiClass;
-  }
-
-  /// Return `true` if this represents a subclass of the class
-  /// `AbiSpecificInteger`.
-  bool get isAbiSpecificIntegerSubclass {
-    final element = this;
-    return element is ClassElement && element.supertype.isAbiSpecificInteger;
-  }
-
-  /// If this is a class element from `dart:ffi`, return it.
-  ClassElement? get ffiClass {
-    var element = this;
-    if (element is ConstructorElement) {
-      element = element.enclosingElement;
-    }
-    if (element is ClassElement && element.isFfiClass) {
-      return element;
-    }
-    return null;
-  }
 }
 
 extension on ClassElement {
@@ -1487,6 +1487,11 @@
 }
 
 extension on DartType? {
+  bool get isAbiSpecificInteger {
+    final self = this;
+    return self is InterfaceType && self.element.isAbiSpecificInteger;
+  }
+
   bool get isStruct {
     final self = this;
     return self is InterfaceType && self.element.isStruct;
@@ -1496,24 +1501,9 @@
     final self = this;
     return self is InterfaceType && self.element.isUnion;
   }
-
-  bool get isAbiSpecificInteger {
-    final self = this;
-    return self is InterfaceType && self.element.isAbiSpecificInteger;
-  }
 }
 
 extension on DartType {
-  /// Return `true` if this represents the class `Array`.
-  bool get isArray {
-    final self = this;
-    if (self is InterfaceType) {
-      final element = self.element;
-      return element.name == FfiVerifier._arrayClassName && element.isFfiClass;
-    }
-    return false;
-  }
-
   int get arrayDimensions {
     DartType iterator = this;
     int dimensions = 0;
@@ -1536,9 +1526,65 @@
     return iterator;
   }
 
-  bool get isPointer {
+  bool get isAbiSpecificInteger {
     final self = this;
-    return self is InterfaceType && self.element.isPointer;
+    if (self is InterfaceType) {
+      final element = self.element;
+      final name = element.name;
+      return name == FfiVerifier._abiSpecificIntegerClassName &&
+          element.isFfiClass;
+    }
+    return false;
+  }
+
+  /// Returns `true` iff this is an Abi-specific integer type,
+  /// i.e. a subtype of `AbiSpecificInteger`.
+  bool get isAbiSpecificIntegerSubtype {
+    final self = this;
+    if (self is InterfaceType) {
+      final superType = self.element.supertype;
+      if (superType != null) {
+        final superClassElement = superType.element;
+        return superClassElement.name ==
+                FfiVerifier._abiSpecificIntegerClassName &&
+            superClassElement.isFfiClass;
+      }
+    }
+    return false;
+  }
+
+  /// Return `true` if this represents the class `Array`.
+  bool get isArray {
+    final self = this;
+    if (self is InterfaceType) {
+      final element = self.element;
+      return element.name == FfiVerifier._arrayClassName && element.isFfiClass;
+    }
+    return false;
+  }
+
+  bool get isCompound {
+    final self = this;
+    if (self is InterfaceType) {
+      final element = self.element;
+      final name = element.name;
+      return (name == FfiVerifier._structClassName ||
+              name == FfiVerifier._unionClassName) &&
+          element.isFfiClass;
+    }
+    return false;
+  }
+
+  /// Returns `true` if this is a struct type, i.e. a subtype of `Struct`.
+  bool get isCompoundSubtype {
+    final self = this;
+    if (self is InterfaceType) {
+      final superType = self.element.supertype;
+      if (superType != null) {
+        return superType.isCompound;
+      }
+    }
+    return false;
   }
 
   bool get isHandle {
@@ -1570,33 +1616,6 @@
     return false;
   }
 
-  bool get isAbiSpecificInteger {
-    final self = this;
-    if (self is InterfaceType) {
-      final element = self.element;
-      final name = element.name;
-      return name == FfiVerifier._abiSpecificIntegerClassName &&
-          element.isFfiClass;
-    }
-    return false;
-  }
-
-  /// Returns `true` iff this is an Abi-specific integer type,
-  /// i.e. a subtype of `AbiSpecificInteger`.
-  bool get isAbiSpecificIntegerSubtype {
-    final self = this;
-    if (self is InterfaceType) {
-      final superType = self.element.supertype;
-      if (superType != null) {
-        final superClassElement = superType.element;
-        return superClassElement.name ==
-                FfiVerifier._abiSpecificIntegerClassName &&
-            superClassElement.isFfiClass;
-      }
-    }
-    return false;
-  }
-
   /// Returns `true` iff this is a opaque type, i.e. a subtype of `Opaque`.
   bool get isOpaqueSubtype {
     final self = this;
@@ -1611,28 +1630,9 @@
     return false;
   }
 
-  bool get isCompound {
+  bool get isPointer {
     final self = this;
-    if (self is InterfaceType) {
-      final element = self.element;
-      final name = element.name;
-      return (name == FfiVerifier._structClassName ||
-              name == FfiVerifier._unionClassName) &&
-          element.isFfiClass;
-    }
-    return false;
-  }
-
-  /// Returns `true` if this is a struct type, i.e. a subtype of `Struct`.
-  bool get isCompoundSubtype {
-    final self = this;
-    if (self is InterfaceType) {
-      final superType = self.element.supertype;
-      if (superType != null) {
-        return superType.isCompound;
-      }
-    }
-    return false;
+    return self is InterfaceType && self.element.isPointer;
   }
 }
 
@@ -1643,19 +1643,19 @@
   }
 
   /// Return `true` if this represents a subtype of `Struct` or `Union`.
-  bool get isCompoundSubtype {
+  bool get isAbiSpecificIntegerSubtype {
     var element = name.staticElement;
     if (element is ClassElement) {
-      return element.allSupertypes.any((e) => e.isCompound);
+      return element.allSupertypes.any((e) => e.isAbiSpecificInteger);
     }
     return false;
   }
 
   /// Return `true` if this represents a subtype of `Struct` or `Union`.
-  bool get isAbiSpecificIntegerSubtype {
+  bool get isCompoundSubtype {
     var element = name.staticElement;
     if (element is ClassElement) {
-      return element.allSupertypes.any((e) => e.isAbiSpecificInteger);
+      return element.allSupertypes.any((e) => e.isCompound);
     }
     return false;
   }
diff --git a/pkg/analyzer/lib/src/lint/util.dart b/pkg/analyzer/lib/src/lint/util.dart
index a0c25dc..392df53 100644
--- a/pkg/analyzer/lib/src/lint/util.dart
+++ b/pkg/analyzer/lib/src/lint/util.dart
@@ -12,19 +12,8 @@
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:path/path.dart' as path;
 
-final _identifier = RegExp(r'^([(_|$)a-zA-Z]+([_a-zA-Z0-9])*)$');
-
-final _lowerCamelCase = RegExp(r'^(_)*[?$a-z][a-z0-9?$]*([A-Z][a-z0-9?$]*)*$');
-
-final _lowerCaseUnderScore = RegExp(r'^([a-z]+([_]?[a-z0-9]+)*)+$');
-
-final _lowerCaseUnderScoreWithDots =
-    RegExp(r'^[a-z][_a-z0-9]*(\.[a-z][_a-z0-9]*)*$');
-
 final _pubspec = RegExp(r'^[_]?pubspec\.yaml$');
 
-final _underscores = RegExp(r'^[_]+$');
-
 /// Create a library name prefix based on [libraryPath], [projectRoot] and
 /// current [packageName].
 String createLibraryNamePrefix(
@@ -50,37 +39,9 @@
 /// Returns `true` if this [fileName] is a Dart file.
 bool isDartFileName(String fileName) => fileName.endsWith('.dart');
 
-/// Returns `true` if this [name] is a legal Dart identifier.
-@deprecated // Never intended for public use.
-bool isIdentifier(String name) => _identifier.hasMatch(name);
-
-/// Returns `true` of the given [name] is composed only of `_`s.
-@deprecated // Never intended for public use.
-bool isJustUnderscores(String name) => _underscores.hasMatch(name);
-
-/// Returns `true` if this [id] is `lowerCamelCase`.
-@deprecated // Never intended for public use.
-bool isLowerCamelCase(String id) =>
-    id.length == 1 && isUpperCase(id.codeUnitAt(0)) ||
-    id == '_' ||
-    _lowerCamelCase.hasMatch(id);
-
-/// Returns `true` if this [id] is `lower_camel_case_with_underscores`.
-@deprecated // Never intended for public use.
-bool isLowerCaseUnderScore(String id) => _lowerCaseUnderScore.hasMatch(id);
-
-/// Returns `true` if this [id] is `lower_camel_case_with_underscores_or.dots`.
-@deprecated // Never intended for public use.
-bool isLowerCaseUnderScoreWithDots(String id) =>
-    _lowerCaseUnderScoreWithDots.hasMatch(id);
-
 /// Returns `true` if this [fileName] is a Pubspec file.
 bool isPubspecFileName(String fileName) => _pubspec.hasMatch(fileName);
 
-/// Returns `true` if the given code unit [c] is upper case.
-@deprecated // Never intended for public use.
-bool isUpperCase(int c) => c >= 0x40 && c <= 0x5A;
-
 class Spelunker {
   final String path;
   final IOSink sink;
diff --git a/pkg/analyzer/lib/src/util/yaml.dart b/pkg/analyzer/lib/src/util/yaml.dart
index dfa104e..416828c 100644
--- a/pkg/analyzer/lib/src/util/yaml.dart
+++ b/pkg/analyzer/lib/src/util/yaml.dart
@@ -106,12 +106,15 @@
 }
 
 extension YamlMapExtensions on YamlMap {
-  /// Return the value associated with the key whose value matches the given
-  /// [key], or `null` if there is no matching key.
-  YamlNode? valueAt(String key) {
-    for (var keyNode in nodes.keys) {
-      if (keyNode is YamlScalar && keyNode.value == key) {
-        return nodes[keyNode];
+  /// Return [nodes] as a Map with [YamlNode] keys.
+  Map<YamlNode, YamlNode> get nodeMap => nodes.cast<YamlNode, YamlNode>();
+
+  /// Return the [YamlNode] associated with the given [key], or `null` if there
+  /// is no matching key.
+  YamlNode? getKey(String key) {
+    for (YamlNode k in nodes.keys) {
+      if (k is YamlScalar && k.value == key) {
+        return k;
       }
     }
     return null;
@@ -128,17 +131,14 @@
     return null;
   }
 
-  /// Return the [YamlNode] associated with the given [key], or `null` if there
-  /// is no matching key.
-  YamlNode? getKey(String key) {
-    for (YamlNode k in nodes.keys) {
-      if (k is YamlScalar && k.value == key) {
-        return k;
+  /// Return the value associated with the key whose value matches the given
+  /// [key], or `null` if there is no matching key.
+  YamlNode? valueAt(String key) {
+    for (var keyNode in nodes.keys) {
+      if (keyNode is YamlScalar && keyNode.value == key) {
+        return nodes[keyNode];
       }
     }
     return null;
   }
-
-  /// Return [nodes] as a Map with [YamlNode] keys.
-  Map<YamlNode, YamlNode> get nodeMap => nodes.cast<YamlNode, YamlNode>();
 }
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 9261ded..e706822 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 3.0.0
+version: 3.1.0-dev
 description: This package provides a library that performs static analysis of Dart code.
 homepage: https://github.com/dart-lang/sdk/tree/main/pkg/analyzer
 
diff --git a/pkg/analyzer/test/src/clients/dart_style/rewrite_cascade_test.dart b/pkg/analyzer/test/src/clients/dart_style/rewrite_cascade_test.dart
new file mode 100644
index 0000000..81d2486
--- /dev/null
+++ b/pkg/analyzer/test/src/clients/dart_style/rewrite_cascade_test.dart
@@ -0,0 +1,121 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/dart/analysis/utilities.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/clients/dart_style/rewrite_cascade.dart';
+import 'package:analyzer/src/test_utilities/find_node.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(RewriteCascadeTest);
+  });
+}
+
+@reflectiveTest
+class RewriteCascadeTest {
+  test_fixCascadeByParenthesizingTarget() {
+    const pairs = {
+      'c ? a : b..method();': '(c ? a : b)..method();',
+      'a ?? b..method();': '(a ?? b)..method();',
+      'a && b..method();': '(a && b)..method();',
+      'a || b..method();': '(a || b)..method();',
+      'a == b..method();': '(a == b)..method();',
+      'a != b..method();': '(a != b)..method();',
+      'a < b..method();': '(a < b)..method();',
+      'a > b..method();': '(a > b)..method();',
+      'a <= b..method();': '(a <= b)..method();',
+      'a >= b..method();': '(a >= b)..method();',
+      'a ^ b..method();': '(a ^ b)..method();',
+      'a | b..method();': '(a | b)..method();',
+      'a << b..method();': '(a << b)..method();',
+      'a >> b..method();': '(a >> b)..method();',
+      'a + b..method();': '(a + b)..method();',
+      'a - b..method();': '(a - b)..method();',
+      'a * b..method();': '(a * b)..method();',
+      'a / b..method();': '(a / b)..method();',
+      'a ~/ b..method();': '(a ~/ b)..method();',
+      '-a..method();': '(-a)..method();',
+      '!a..method();': '(!a)..method();',
+      '~a..method();': '(~a)..method();',
+      'a++..method();': '(a++)..method();',
+      'a--..method();': '(a--)..method();',
+    };
+
+    void assertSingle({
+      required String input,
+      required String expected,
+    }) {
+      var statement = _parseStringToFindNode('''
+void f() {
+  $input
+}
+''').expressionStatement(input);
+      var result = fixCascadeByParenthesizingTarget(
+        expressionStatement: statement,
+        cascadeExpression: statement.expression as CascadeExpression,
+      );
+      expect(result.toSource(), expected);
+      expect(result.semicolon, same(statement.semicolon));
+    }
+
+    for (var entry in pairs.entries) {
+      assertSingle(
+        input: entry.key,
+        expected: entry.value,
+      );
+    }
+  }
+
+  test_insertCascadeTargetIntoExpression() {
+    void assertSingle({
+      required String input,
+      required String expected,
+    }) {
+      var statement = _parseStringToFindNode('''
+void f() {
+  $input;
+    }
+    ''').expressionStatement(input);
+      var cascadeExpression = statement.expression as CascadeExpression;
+      var result = insertCascadeTargetIntoExpression(
+        expression: cascadeExpression.cascadeSections.single,
+        cascadeTarget: cascadeExpression.target,
+      );
+      expect(result.toSource(), expected);
+    }
+
+    const pairs = {
+      'obj..method()': 'obj.method()',
+      'obj..getter': 'obj.getter',
+      'obj..setter = 3': 'obj.setter = 3',
+      'obj..[subscript] = 3': 'obj[subscript] = 3',
+      'obj?..[subscript] = 3': 'obj?[subscript] = 3',
+      'obj..index[subscript] = 3': 'obj.index[subscript] = 3',
+      'obj..index?[subscript] = 3': 'obj.index?[subscript] = 3',
+      // Nested
+      'obj..foo().bar().method()': 'obj.foo().bar().method()',
+      'obj..foo.bar.getter': 'obj.foo.bar.getter',
+      'obj..foo.bar.setter = 0': 'obj.foo.bar.setter = 0',
+    };
+
+    for (var entry in pairs.entries) {
+      assertSingle(
+        input: entry.key,
+        expected: entry.value,
+      );
+    }
+  }
+
+  FindNode _parseStringToFindNode(String content) {
+    var parseResult = parseString(
+      content: content,
+      featureSet: FeatureSet.latestLanguageVersion(),
+    );
+    return FindNode(parseResult.content, parseResult.unit);
+  }
+}
diff --git a/pkg/analyzer/test/src/clients/dart_style/test_all.dart b/pkg/analyzer/test/src/clients/dart_style/test_all.dart
new file mode 100644
index 0000000..d5179bd
--- /dev/null
+++ b/pkg/analyzer/test/src/clients/dart_style/test_all.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'rewrite_cascade_test.dart' as rewrite_cascade;
+
+main() {
+  defineReflectiveSuite(() {
+    rewrite_cascade.main();
+  }, name: 'dart_style');
+}
diff --git a/pkg/analyzer/test/src/clients/test_all.dart b/pkg/analyzer/test/src/clients/test_all.dart
new file mode 100644
index 0000000..5118a6b
--- /dev/null
+++ b/pkg/analyzer/test/src/clients/test_all.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'dart_style/test_all.dart' as dart_style;
+
+main() {
+  defineReflectiveSuite(() {
+    dart_style.main();
+  }, name: 'clients');
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 8568ee0..cb4869d 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -71,33 +71,30 @@
 
     // Reference "inner" using a non-canonical URI.
     {
-      var path = convertPath('$outerLibPath/a.dart');
-      newFile(path, content: r'''
+      var a = newFile(convertPath('$outerLibPath/a.dart'), content: r'''
 import 'inner/lib/b.dart';
 ''');
-      var result = await analysisSession.getResolvedUnit(path);
+      var result = await analysisSession.getResolvedUnit(a.path);
       result as ResolvedUnitResult;
       assertInnerUri(result);
     }
 
     // Reference "inner" using the canonical URI, via relative.
     {
-      var path = '$outerLibPath/inner/lib/c.dart';
-      newFile(path, content: r'''
+      var c = newFile('$outerLibPath/inner/lib/c.dart', content: r'''
 import 'b.dart';
 ''');
-      var result = await analysisSession.getResolvedUnit(path);
+      var result = await analysisSession.getResolvedUnit(c.path);
       result as ResolvedUnitResult;
       assertInnerUri(result);
     }
 
     // Reference "inner" using the canonical URI, via absolute.
     {
-      var path = '$outerLibPath/inner/lib/d.dart';
-      newFile(path, content: '''
+      var d = newFile('$outerLibPath/inner/lib/d.dart', content: '''
 import '$innerUri';
 ''');
-      var result = await analysisSession.getResolvedUnit(path);
+      var result = await analysisSession.getResolvedUnit(d.path);
       result as ResolvedUnitResult;
       assertInnerUri(result);
     }
@@ -3428,10 +3425,6 @@
 }
 
 extension on AnalysisDriver {
-  FileResult getFileSyncValid(String path) {
-    return getFileSync(path) as FileResult;
-  }
-
   Set<String> get loadedLibraryUriSet {
     var elementFactory = this.test.libraryContext!.elementFactory;
     var libraryReferences = elementFactory.rootReference.children;
@@ -3453,11 +3446,15 @@
     }
   }
 
-  Future<ResolvedUnitResult> getResultValid(String path) async {
-    return await getResult(path) as ResolvedUnitResult;
+  FileResult getFileSyncValid(String path) {
+    return getFileSync(path) as FileResult;
   }
 
   Future<LibraryElementResult> getLibraryByUriValid(String uriStr) async {
     return await getLibraryByUri(uriStr) as LibraryElementResult;
   }
+
+  Future<ResolvedUnitResult> getResultValid(String path) async {
+    return await getResult(path) as ResolvedUnitResult;
+  }
 }
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index 612ac02..91057d0 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -2400,14 +2400,6 @@
 }
 
 extension on List<Declaration> {
-  void assertNo(String name) {
-    for (var declaration in this) {
-      if (declaration.name == name) {
-        fail('Unexpected declaration $name');
-      }
-    }
-  }
-
   Declaration assertHas(String name, DeclarationKind kind,
       {int? offset,
       int? codeOffset,
@@ -2432,4 +2424,12 @@
     fail('Expected to find (name=$name, kind=$kind, offset=$offset, '
         'codeOffset=$codeOffset, codeLength=$codeLength) in\n$actual');
   }
+
+  void assertNo(String name) {
+    for (var declaration in this) {
+      if (declaration.name == name) {
+        fail('Unexpected declaration $name');
+      }
+    }
+  }
 }
diff --git a/pkg/analyzer/test/src/dart/analysis/session_test.dart b/pkg/analyzer/test/src/dart/analysis/session_test.dart
index 9512475..5a90033 100644
--- a/pkg/analyzer/test/src/dart/analysis/session_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/session_test.dart
@@ -641,40 +641,40 @@
 }
 
 extension on AnalysisSession {
-  Future<UnitElementResult> getUnitElementValid(String path) async {
-    return await getUnitElement(path) as UnitElementResult;
-  }
-
-  ParsedLibraryResult getParsedLibraryValid(String path) {
-    return getParsedLibrary(path) as ParsedLibraryResult;
+  Future<ErrorsResult> getErrorsValid(String path) async {
+    return await getErrors(path) as ErrorsResult;
   }
 
   FileResult getFileValid(String path) {
     return getFile(path) as FileResult;
   }
 
-  ParsedUnitResult getParsedUnitValid(String path) {
-    return getParsedUnit(path) as ParsedUnitResult;
-  }
-
-  Future<ResolvedLibraryResult> getResolvedLibraryValid(String path) async {
-    return await getResolvedLibrary(path) as ResolvedLibraryResult;
-  }
-
   Future<LibraryElementResult> getLibraryByUriValid(String path) async {
     return await getLibraryByUri(path) as LibraryElementResult;
   }
 
+  ParsedLibraryResult getParsedLibraryByElementValid(LibraryElement element) {
+    return getParsedLibraryByElement(element) as ParsedLibraryResult;
+  }
+
+  ParsedLibraryResult getParsedLibraryValid(String path) {
+    return getParsedLibrary(path) as ParsedLibraryResult;
+  }
+
+  ParsedUnitResult getParsedUnitValid(String path) {
+    return getParsedUnit(path) as ParsedUnitResult;
+  }
+
   Future<ResolvedLibraryResult> getResolvedLibraryByElementValid(
       LibraryElement element) async {
     return await getResolvedLibraryByElement(element) as ResolvedLibraryResult;
   }
 
-  ParsedLibraryResult getParsedLibraryByElementValid(LibraryElement element) {
-    return getParsedLibraryByElement(element) as ParsedLibraryResult;
+  Future<ResolvedLibraryResult> getResolvedLibraryValid(String path) async {
+    return await getResolvedLibrary(path) as ResolvedLibraryResult;
   }
 
-  Future<ErrorsResult> getErrorsValid(String path) async {
-    return await getErrors(path) as ErrorsResult;
+  Future<UnitElementResult> getUnitElementValid(String path) async {
+    return await getUnitElement(path) as UnitElementResult;
   }
 }
diff --git a/pkg/analyzer/test/src/dart/element/class_element_test.dart b/pkg/analyzer/test/src/dart/element/class_element_test.dart
index c6ed690..9505982 100644
--- a/pkg/analyzer/test/src/dart/element/class_element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/class_element_test.dart
@@ -1331,10 +1331,6 @@
 }
 
 extension on ClassElement {
-  MethodElement? _lookUpInheritedMethod(String name) {
-    return lookUpInheritedMethod(name, library);
-  }
-
   PropertyAccessorElement? _lookUpInheritedConcreteGetter(String name) {
     return lookUpInheritedConcreteGetter(name, library);
   }
@@ -1346,4 +1342,8 @@
   PropertyAccessorElement? _lookUpInheritedConcreteSetter(String name) {
     return lookUpInheritedConcreteSetter(name, library);
   }
+
+  MethodElement? _lookUpInheritedMethod(String name) {
+    return lookUpInheritedMethod(name, library);
+  }
 }
diff --git a/pkg/analyzer/test/src/test_all.dart b/pkg/analyzer/test/src/test_all.dart
index 9969e39..c6fe9f8 100644
--- a/pkg/analyzer/test/src/test_all.dart
+++ b/pkg/analyzer/test/src/test_all.dart
@@ -4,6 +4,7 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'clients/test_all.dart' as clients;
 import 'context/test_all.dart' as context;
 import 'dart/test_all.dart' as dart;
 import 'dartdoc/test_all.dart' as dartdoc;
@@ -25,6 +26,7 @@
 
 main() {
   defineReflectiveSuite(() {
+    clients.main();
     context.main();
     dart.main();
     dartdoc.main();
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 31590d0..e235487 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_ast_factory.dart';
 import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -413,15 +412,21 @@
         }
       }
       if (token is StringToken) {
-        var uri = astFactory.simpleStringLiteral(token, token.lexeme);
-        var keyword = containingNode.findPrevious(token)?.keyword;
-        if (keyword == Keyword.IMPORT ||
-            keyword == Keyword.EXPORT ||
-            keyword == Keyword.PART) {
+        final containingNode = this.containingNode;
+        StringLiteral? uri;
+        Directive? directive;
+        if (containingNode is NamespaceDirective) {
+          directive = containingNode;
+          uri = containingNode.uri;
+        } else if (containingNode is SimpleStringLiteral) {
+          uri = containingNode;
+          directive = containingNode.parent.ifTypeOrNull();
+        }
+        // Replacement range for a URI.
+        if (directive != null && uri is SimpleStringLiteral) {
           var start = uri.contentsOffset;
           var end = uri.contentsEnd;
           if (start <= requestOffset && requestOffset <= end) {
-            // Replacement range for import URI
             return SourceRange(start, end - start);
           }
         }
@@ -660,3 +665,11 @@
     }
   }
 }
+
+extension on Object? {
+  /// If the target is [T], return it, otherwise `null`.
+  T? ifTypeOrNull<T>() {
+    final self = this;
+    return self is T ? self : null;
+  }
+}
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 c622af3..728782a 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
@@ -3,21 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_ast_factory.dart';
-import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
-import 'package:analyzer/src/dart/ast/token.dart';
 
 /// A visitor that visits an [AstNode] and its parent recursively along with any
 /// declarations in those nodes. Consumers typically call [visit] which catches
 /// the exception thrown by [finished].
 abstract class LocalDeclarationVisitor extends GeneralizingAstVisitor {
-  static final NamedType STACKTRACE_TYPE = astFactory.namedType(
-    name: astFactory.simpleIdentifier(
-      StringToken(TokenType.IDENTIFIER, 'StackTrace', 0),
-    ),
-  );
-
   final int offset;
 
   LocalDeclarationVisitor(this.offset);
@@ -81,14 +72,16 @@
 
   @override
   void visitCatchClause(CatchClause node) {
-    var param = node.exceptionParameter;
-    if (param != null) {
-      declaredParam(param, node.exceptionType);
+    var exceptionParameter = node.exceptionParameter;
+    if (exceptionParameter != null) {
+      declaredParam(exceptionParameter, node.exceptionType);
     }
-    param = node.stackTraceParameter;
-    if (param != null) {
-      declaredParam(param, STACKTRACE_TYPE);
+
+    var stackTraceParameter = node.stackTraceParameter;
+    if (stackTraceParameter != null) {
+      declaredParam(stackTraceParameter, null);
     }
+
     visitNode(node);
   }
 
diff --git a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
index 8d5106f..5ad2871 100644
--- a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
@@ -253,6 +253,52 @@
   }
 
   @override
+  void visitComment(Comment node) {
+    for (var commentReference in node.references) {
+      commentReference.accept(this);
+    }
+
+    var inToolAnnotation = false;
+    for (var token in node.tokens) {
+      if (token.isEof) {
+        break;
+      }
+      var strValue = token.toString();
+      if (strValue.isEmpty) {
+        continue;
+      }
+
+      if (inToolAnnotation) {
+        if (strValue.contains('{@end-tool}')) {
+          inToolAnnotation = false;
+        } else if (strValue.contains('** See code in ')) {
+          var startIndex = strValue.indexOf('** See code in ') + 15;
+          var endIndex = strValue.indexOf('.dart') + 5;
+          var pathSnippet = strValue.substring(startIndex, endIndex);
+          var parentPath =
+              _computeParentWithExamplesAPI(node, resourceProvider);
+          if (parentPath != null) {
+            computer.collector.addRegion(
+                token.offset + startIndex,
+                token.offset + endIndex,
+                protocol.ElementKind.LIBRARY,
+                protocol.Location(
+                    resourceProvider.pathContext.join(parentPath, pathSnippet),
+                    0,
+                    0,
+                    0,
+                    0,
+                    endLine: 0,
+                    endColumn: 0));
+          }
+        }
+      } else if (strValue.contains('{@tool ')) {
+        inToolAnnotation = true;
+      }
+    }
+  }
+
+  @override
   void visitCompilationUnit(CompilationUnit unit) {
     // prepare top-level nodes sorted by their offsets
     var nodes = <AstNode>[];
@@ -476,4 +522,31 @@
       }
     }
   }
+
+  /// Given some [Comment], compute and return the parent directory absolute
+  /// path which contains the directories 'examples/api/'. Null is returned if
+  /// such directories are not found.
+  String? _computeParentWithExamplesAPI(
+      Comment node, ResourceProvider resourceProvider) {
+    var source =
+        node.thisOrAncestorOfType<CompilationUnit>()?.declaredElement?.source;
+    if (source == null) {
+      return null;
+    }
+
+    var file = resourceProvider.getFile(source.fullName);
+    if (!file.exists) {
+      return null;
+    }
+    var parent = file.parent2;
+    while (parent != parent.parent2) {
+      var examplesFolder = parent.getChildAssumingFolder('examples');
+      if (examplesFolder.exists &&
+          examplesFolder.getChildAssumingFolder('api').exists) {
+        return parent.path;
+      }
+      parent = parent.parent2;
+    }
+    return null;
+  }
 }
diff --git a/pkg/analyzer_utilities/lib/check/bool.dart b/pkg/analyzer_utilities/lib/check/bool.dart
index 18d5054..1b13751 100644
--- a/pkg/analyzer_utilities/lib/check/bool.dart
+++ b/pkg/analyzer_utilities/lib/check/bool.dart
@@ -5,15 +5,15 @@
 import 'package:analyzer_utilities/check/check.dart';
 
 extension BoolExtension on CheckTarget<bool> {
-  void get isTrue {
-    if (!value) {
-      fail('is not true');
-    }
-  }
-
   void get isFalse {
     if (value) {
       fail('is not false');
     }
   }
+
+  void get isTrue {
+    if (!value) {
+      fail('is not true');
+    }
+  }
 }
diff --git a/pkg/analyzer_utilities/lib/check/nullability.dart b/pkg/analyzer_utilities/lib/check/nullability.dart
index 3a31513..ef1860e 100644
--- a/pkg/analyzer_utilities/lib/check/nullability.dart
+++ b/pkg/analyzer_utilities/lib/check/nullability.dart
@@ -5,12 +5,6 @@
 import 'package:analyzer_utilities/check/check.dart';
 
 extension NullabilityExtension<T> on CheckTarget<T?> {
-  void get isNull {
-    if (value != null) {
-      fail('is not null');
-    }
-  }
-
   CheckTarget<T> get isNotNull {
     final value = this.value;
     if (value == null) {
@@ -18,4 +12,10 @@
     }
     return nest(value, (value) => 'is not null');
   }
+
+  void get isNull {
+    if (value != null) {
+      fail('is not null');
+    }
+  }
 }
diff --git a/pkg/analyzer_utilities/lib/check/string.dart b/pkg/analyzer_utilities/lib/check/string.dart
index 3d80003..75278b8 100644
--- a/pkg/analyzer_utilities/lib/check/string.dart
+++ b/pkg/analyzer_utilities/lib/check/string.dart
@@ -12,12 +12,6 @@
     }
   }
 
-  void startsWith(Pattern other) {
-    if (!value.startsWith(other)) {
-      fail('does not start with ${valueStr(other)}');
-    }
-  }
-
   @UseResult.unless(parameterDefined: 'expected')
   CheckTarget<int> hasLength([int? expected]) {
     var actual = value.length;
@@ -28,4 +22,10 @@
 
     return nest(actual, (length) => 'has length $length');
   }
+
+  void startsWith(Pattern other) {
+    if (!value.startsWith(other)) {
+      fail('does not start with ${valueStr(other)}');
+    }
+  }
 }
diff --git a/pkg/dart_internal/analysis_options.yaml b/pkg/dart_internal/analysis_options.yaml
index edcd64e..6f7501d 100644
--- a/pkg/dart_internal/analysis_options.yaml
+++ b/pkg/dart_internal/analysis_options.yaml
@@ -1,5 +1,5 @@
 analyzer:
   errors:
     import_internal_library: ignore
-  strong-mode:
-    implicit-casts: false
+  language:
+    strict-casts: true
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index c8cbcec..b2dce5c 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -4545,13 +4545,14 @@
     ElideJSONSubstring("libraries", buffer, buffer);
     ElideJSONSubstring("_List@", buffer, buffer);
     ElideJSONSubstring("_TypeParameter@", buffer, buffer);
+    StripTokenPositions(buffer);
     EXPECT_SUBSTRING(
         "{\"type\":\"@Instance\",\"_vmType\":\"Array\",\"class\":{\"type\":\"@"
         "Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"_List\",\"_vmName\":"
         "\"\",\"location\":{\"type\":\"SourceLocation\",\"script\":{\"type\":"
         "\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:core-patch\\/"
-        "array.dart\",\"_kind\":\"kernel\"},\"tokenPos\":248,\"endTokenPos\":"
-        "7917},\"library\":{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
+        "array.dart\",\"_kind\":\"kernel\"}},"
+        "\"library\":{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
         "\"name\":\"dart.core\",\"uri\":\"dart:core\"},\"typeParameters\":[{"
         "\"type\":\"@"
         "Instance\",\"_vmType\":\"TypeParameter\",\"class\":{\"type\":\"@"
@@ -4559,8 +4560,8 @@
         "vmName\":\"\",\"location\":{\"type\":"
         "\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
         "\"id\":\"\",\"uri\":\"dart:core-patch\\/"
-        "type_patch.dart\",\"_kind\":\"kernel\"},\"tokenPos\":1749,"
-        "\"endTokenPos\":1894},\"library\":{\"type\":\"@Library\",\"fixedId\":"
+        "type_patch.dart\",\"_kind\":\"kernel\"}},"
+        "\"library\":{\"type\":\"@Library\",\"fixedId\":"
         "true,\"id\":\"\",\"name\":\"dart.core\",\"uri\":\"dart:core\"}},"
         "\"identityHashCode\":",
         buffer);
@@ -4572,8 +4573,8 @@
         "\"Null\",\"location\":{\"type\":\"SourceLocation\",\"script\":{"
         "\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:"
         "core\\/"
-        "null.dart\",\"_kind\":\"kernel\"},\"tokenPos\":925,\"endTokenPos\":"
-        "1165},\"library\":{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
+        "null.dart\",\"_kind\":\"kernel\"}},"
+        "\"library\":{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
         "\"name\":\"dart.core\",\"uri\":\"dart:core\"}},\"kind\":\"Null\","
         "\"fixedId\":true,\"id\":\"\",\"valueAsString\":\"null\"}}]},"
         "\"identityHashCode\":0,\"kind\":\"List\",\"id\":\"\",\"length\":0}",
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 3298b08..c6280c1 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -7125,14 +7125,6 @@
     setProperty('grid-column-end', value, '');
   }
 
-  /** Gets the value of "grid-column-gap" */
-  String get gridColumnGap => getPropertyValue('grid-column-gap');
-
-  /** Sets the value of "grid-column-gap" */
-  set gridColumnGap(String value) {
-    setProperty('grid-column-gap', value, '');
-  }
-
   /** Gets the value of "grid-column-start" */
   String get gridColumnStart => getPropertyValue('grid-column-start');
 
@@ -7157,14 +7149,6 @@
     setProperty('grid-row-end', value, '');
   }
 
-  /** Gets the value of "grid-row-gap" */
-  String get gridRowGap => getPropertyValue('grid-row-gap');
-
-  /** Sets the value of "grid-row-gap" */
-  set gridRowGap(String value) {
-    setProperty('grid-row-gap', value, '');
-  }
-
   /** Gets the value of "grid-row-start" */
   String get gridRowStart => getPropertyValue('grid-row-start');
 
diff --git a/tools/VERSION b/tools/VERSION
index 40c1a10..1745e69 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 16
 PATCH 0
-PRERELEASE 122
+PRERELEASE 123
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 388f037..ed2057e 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -547,14 +547,6 @@
         "use-sdk": true
       }
     },
-    "dart2js-canary-(linux|mac|win)-chrome": {
-      "options": {
-        "use-sdk": true,
-        "dart2js-options": [
-          "--canary"
-        ]
-      }
-    },
     "dart2js-(linux|mac|win)-chrome-unsound": {
       "options": {
         "use-sdk": true,
@@ -699,7 +691,17 @@
     "dart2js-canary-(linux|mac|win)-d8": {
       "options": {
         "builder-tag": "dart2js_canary",
-        "use-sdk": true,
+        "host-checked": true,
+        "timeout": 240,
+        "dart2js-options": [
+          "--canary"
+        ]
+      }
+    },
+    "dart2js-canary-(linux|mac|win)-chrome": {
+      "options": {
+        "host-checked": true,
+        "timeout": 240,
         "dart2js-options": [
           "--canary"
         ]
diff --git a/tools/dom/scripts/CSSPropertyNames.in b/tools/dom/scripts/CSSPropertyNames.in
index cf59dca..8947335 100644
--- a/tools/dom/scripts/CSSPropertyNames.in
+++ b/tools/dom/scripts/CSSPropertyNames.in
@@ -329,7 +329,6 @@
 grid-area
 grid-column
 grid-column-end
-grid-column-gap
 grid-column-start
 grid
 grid-template
@@ -337,7 +336,6 @@
 grid-template-rows
 grid-row
 grid-row-end
-grid-row-gap
 grid-row-start
 grid-template-areas
 -webkit-highlight
diff --git a/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate b/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate
index a81ff5a..7aade98 100644
--- a/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate
+++ b/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate
@@ -3211,15 +3211,6 @@
     setProperty('grid-column-end', value, '');
   }
 
-  /** Gets the value of "grid-column-gap" */
-  String get gridColumnGap =>
-    getPropertyValue('grid-column-gap');
-
-  /** Sets the value of "grid-column-gap" */
-  set gridColumnGap(String value) {
-    setProperty('grid-column-gap', value, '');
-  }
-
   /** Gets the value of "grid-column-start" */
   String get gridColumnStart =>
     getPropertyValue('grid-column-start');
@@ -3247,15 +3238,6 @@
     setProperty('grid-row-end', value, '');
   }
 
-  /** Gets the value of "grid-row-gap" */
-  String get gridRowGap =>
-    getPropertyValue('grid-row-gap');
-
-  /** Sets the value of "grid-row-gap" */
-  set gridRowGap(String value) {
-    setProperty('grid-row-gap', value, '');
-  }
-
   /** Gets the value of "grid-row-start" */
   String get gridRowStart =>
     getPropertyValue('grid-row-start');