Version 2.14.0-172.0.dev

Merge commit 'e453b4c64f8b683297e7f0c18e372033cb580ddc' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4a3942c..13329a7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -59,13 +59,32 @@
 https://github.com/dart-lang/sdk/issues/46100
 
 * The `dart create` command has been updated to create projects that use the new
-  'core' set of lints from `package:lints`. See https://dart.dev/go/core-lints
+  'recommended' set of lints from `package:lints`. See https://dart.dev/go/core-lints
   for more information about these lints.
 
 #### Linter
 
-Updated the Linter to `1.4.0`, which includes:
+Updated the Linter to `1.5.0`, which includes:
 
+- (internal) migrated to `SecurityLintCode` instead of deprecated 
+  `SecurityLintCodeWithUniqueName`.
+- (internal) fixed `avoid_types_as_parameter_names` to skip field formal
+  parameters.
+- fixed false positives in `prefer_interpolation_to_compose_strings` where
+  the left operand is not a String.
+- fixed false positives in `only_throw_errors` for misidentified type
+  variables.
+- new lint: `depend_on_referenced_packages`.
+- update `avoid_returning_null_for_future` to skip checks for null-safe
+  libraries.
+- new lint: `use_test_throws_matchers`.
+- relaxed `sort_child_properties_last` to accept closures after child.
+- performance improvements for `prefer_contains` and `prefer_is_empty`.
+- new lint: `noop_primitive_operations`.
+- marked `avoid_web_libraries_in_flutter` as stable.
+- new lint: `prefer_final_parameters`.
+- updated `prefer_initializing_formals` to allow assignments where identifier
+  names don't match.
 - `directives_ordering` now checks ordering of `package:` imports in code
   outside pub packages.
 - simple reachability analysis added to `use_build_context_synchronously` to
diff --git a/DEPS b/DEPS
index f0269ec..cf9edd4 100644
--- a/DEPS
+++ b/DEPS
@@ -118,14 +118,14 @@
   "http_multi_server_rev": "de1b312164c24a1690b46c6e97bd47eff40c4649",
   "http_parser_rev": "7720bfd42a0c096734c5213478fdce92c62f0293",
   "http_retry_rev": "845771af7bb5ab38ab740ce4a31f3b0c7680302b",
-  "http_rev": "abb2bb182fbd7f03aafd1f889b902d7b3bdb8769",
+  "http_rev": "e89b190936d53d0e36148436283e28ba1091b35a",
   "http_throttle_tag" : "1.0.2",
   "icu_rev" : "81d656878ec611cb0b42d52c82e9dae93920d9ba",
   "idl_parser_rev": "5fb1ebf49d235b5a70c9f49047e83b0654031eb7",
   "intl_tag": "0.17.0-nullsafety",
   "jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_rev": "7e00f893440a72de0637970325e4ea44bd1e8c8e",
-  "linter_tag": "1.4.0",
+  "linter_tag": "1.5.0",
   "lints_tag": "f9670df2a66e0ec12eb51554e70c1cbf56c8f5d0",
   "logging_rev": "e2f633b543ef89c54688554b15ca3d7e425b86a2",
   "markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
diff --git a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
index 4792bed..3550b96 100644
--- a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
+import 'package:analysis_server/src/services/completion/dart/extension_cache.dart';
 import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/instrumentation/service.dart';
@@ -12,6 +13,9 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class DartFixContext implements FixContext {
+  /// Return the extension cache used to find available extensions.
+  ExtensionCache get extensionCache;
+
   /// Return the instrumentation service used to report errors that prevent a
   /// fix from being composed.
   InstrumentationService get instrumentationService;
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 344f997..db83350 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -686,6 +686,7 @@
             path, server.doAnalysisError_listFromEngine(result));
       }
       analysisServer.getDocumentationCacheFor(result)?.cacheFromResult(result);
+      analysisServer.getExtensionCacheFor(result)?.cacheFromResult(result);
       var unit = result.unit;
       if (unit != null) {
         if (analysisServer._hasAnalysisServiceSubscription(
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index b890a41..616bf9d 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -16,6 +16,7 @@
 import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
 import 'package:analysis_server/src/server/diagnostic_server.dart';
 import 'package:analysis_server/src/services/completion/dart/documentation_cache.dart';
+import 'package:analysis_server/src/services/completion/dart/extension_cache.dart';
 import 'package:analysis_server/src/services/correction/namespace.dart';
 import 'package:analysis_server/src/services/pub/pub_api.dart';
 import 'package:analysis_server/src/services/pub/pub_package_service.dart';
@@ -91,6 +92,10 @@
   /// each context.
   Map<AnalysisContext, DocumentationCache> documentationForContext = {};
 
+  /// A map from analysis contexts to the extension cache associated with
+  /// each context.
+  Map<AnalysisContext, ExtensionCache> extensionForContext = {};
+
   /// The DiagnosticServer for this AnalysisServer. If available, it can be used
   /// to start an http diagnostics server or return the port for an existing
   /// server.
@@ -229,6 +234,7 @@
   void addContextsToDeclarationsTracker() {
     declarationsTracker?.discardContexts();
     documentationForContext.clear();
+    extensionForContext.clear();
     for (var driver in driverMap.values) {
       declarationsTracker?.addContext(driver.analysisContext!);
       driver.resetUriResolution();
@@ -347,6 +353,14 @@
     return element;
   }
 
+  /// Return the object used to cache information about extensions in the
+  /// context that produced the [result], or `null` if there is no cache for the
+  /// context.
+  ExtensionCache? getExtensionCacheFor(ResolvedUnitResult result) {
+    var context = result.session.analysisContext;
+    return extensionForContext.putIfAbsent(context, () => ExtensionCache());
+  }
+
   /// Return a [Future] that completes with the resolved [AstNode] at the
   /// given [offset] of the given [file], or with `null` if there is no node as
   /// the [offset].
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index 57d87fe..4e08659 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -636,7 +636,7 @@
               result.path!,
               name,
             );
-          });
+          }, extensionCache: server.getExtensionCacheFor(result));
 
           List<Fix> fixes;
           try {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 322e9d8d..b428985 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -312,7 +312,7 @@
             unit.path!,
             name,
           );
-        });
+        }, extensionCache: server.getExtensionCacheFor(unit));
         final fixes = await fixContributor.computeFixes(context);
         if (fixes.isNotEmpty) {
           fixes.sort(Fix.SORT_BY_RELEVANCE);
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index 17d912b..af14c73 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -836,6 +836,8 @@
         final serverErrors = protocol.doAnalysisError_listFromEngine(result);
         recordAnalysisErrors(path, serverErrors);
       }
+      analysisServer.getDocumentationCacheFor(result)?.cacheFromResult(result);
+      analysisServer.getExtensionCacheFor(result)?.cacheFromResult(result);
       final unit = result.unit;
       if (unit != null) {
         if (analysisServer.shouldSendClosingLabelsFor(path)) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/extension_cache.dart b/pkg/analysis_server/lib/src/services/completion/dart/extension_cache.dart
new file mode 100644
index 0000000..96decc0
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/extension_cache.dart
@@ -0,0 +1,105 @@
+// 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/results.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+
+/// Cached data about the extensions defined in a single analysis context.
+class ExtensionCache {
+  /// A set containing the paths of the compilation units that have been cached.
+  /// The set is used to prevent caching the same data multiple times.
+  final Set<String> processedUnits = {};
+
+  /// A map from the name of a non-static public extension member to the set of
+  /// paths to libraries defining an extension member with that name.
+  final Map<String, Set<UnitInLibrary>> membersByName = {};
+
+  /// Initialize a newly created cache.
+  ExtensionCache();
+
+  /// Fill the cache with data from the [result].
+  void cacheFromResult(ResolvedUnitResult result) {
+    var element = result.unit?.declaredElement;
+    if (element != null) {
+      _cacheFromElement(element);
+      for (var library in result.libraryElement.importedLibraries) {
+        _cacheLibrary(library);
+      }
+    }
+  }
+
+  /// Fill the cache with data from the [compilationUnit].
+  void _cacheFromElement(CompilationUnitElement compilationUnit) {
+    // Record that we've cached data for the compilation unit.
+    var unitPath = _keyForUnit(compilationUnit);
+    processedUnits.add(unitPath);
+
+    // Flush any data that was previously cached for the compilation unit.
+    for (var set in membersByName.values) {
+      set.removeWhere((element) => element.unitPath == unitPath);
+    }
+
+    // Cache the data for the compilation unit.
+    var libraryPath = compilationUnit.librarySource.fullName;
+    for (var extension in compilationUnit.extensions) {
+      var extensionName = extension.name;
+      if (extensionName != null && !Identifier.isPrivateName(extensionName)) {
+        for (var member in extension.accessors) {
+          if (!member.isSynthetic) {
+            _recordMember(unitPath, libraryPath, member.displayName);
+          }
+        }
+        for (var member in extension.fields) {
+          if (!member.isSynthetic) {
+            _recordMember(unitPath, libraryPath, member.name);
+          }
+        }
+        for (var member in extension.methods) {
+          _recordMember(unitPath, libraryPath, member.name);
+        }
+      }
+    }
+  }
+
+  /// Cache the data for the given [library] and every library exported from it
+  /// if it hasn't already been cached.
+  void _cacheLibrary(LibraryElement library) {
+    if (_hasDataFor(library.definingCompilationUnit)) {
+      return;
+    }
+    for (var unit in library.units) {
+      _cacheFromElement(unit);
+    }
+    for (var exported in library.exportedLibraries) {
+      _cacheLibrary(exported);
+    }
+  }
+
+  /// Return `true` if the cache contains data for the [compilationUnit].
+  bool _hasDataFor(CompilationUnitElement compilationUnit) {
+    return processedUnits.contains(_keyForUnit(compilationUnit));
+  }
+
+  /// Return the key used in the [extensionCache] for the [compilationUnit].
+  String _keyForUnit(CompilationUnitElement compilationUnit) =>
+      compilationUnit.source.fullName;
+
+  /// Record that an extension member with the given [name] is defined in the
+  /// compilation unit with the [unitPath] in the library with the
+  /// [libraryPath].
+  void _recordMember(String unitPath, String libraryPath, String name) {
+    membersByName
+        .putIfAbsent(name, () => {})
+        .add(UnitInLibrary(unitPath, libraryPath));
+  }
+}
+
+/// A representation of a compilation unit in a library.
+class UnitInLibrary {
+  final String unitPath;
+  final String libraryPath;
+
+  UnitInLibrary(this.unitPath, this.libraryPath);
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
index 8f452a1..036786e 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
@@ -4,13 +4,10 @@
 
 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
 import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
+import 'package:analysis_server/src/utilities/extensions/element.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/generic_inferrer.dart'
-    show GenericInferrer;
-import 'package:analyzer/src/dart/element/type_algebra.dart';
-import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
 
 /// A contributor that produces suggestions based on the members of an
@@ -87,7 +84,7 @@
       if (type == null) {
         // Without a type we can't find the extensions that apply. We shouldn't
         // get to this point, but there's an NPE if we invoke
-        // `_resolveExtendedType` when `type` is `null`, so we guard against it
+        // `resolvedExtendedType` when `type` is `null`, so we guard against it
         // to ensure that we can return the suggestions from other providers.
         return;
       }
@@ -101,7 +98,7 @@
     var nameScope = containingLibrary.scope;
     for (var extension in nameScope.extensions) {
       var extendedType =
-          _resolveExtendedType(containingLibrary, extension, type);
+          extension.resolvedExtendedType(containingLibrary, type);
       if (extendedType != null && typeSystem.isSubtypeOf(type, extendedType)) {
         var inheritanceDistance = 0.0;
         if (type is InterfaceType && extendedType is InterfaceType) {
@@ -141,34 +138,4 @@
           accessor: accessor, inheritanceDistance: inheritanceDistance);
     }
   }
-
-  /// Use the [type] of the object being extended in the [library] to compute
-  /// the actual type extended by the [extension]. Return the computed type,
-  /// or `null` if the type cannot be computed.
-  DartType? _resolveExtendedType(
-    LibraryElement library,
-    ExtensionElement extension,
-    DartType type,
-  ) {
-    var typeParameters = extension.typeParameters;
-    var inferrer =
-        GenericInferrer(library.typeSystem as TypeSystemImpl, typeParameters);
-    inferrer.constrainArgument(
-      type,
-      extension.extendedType,
-      'extendedType',
-    );
-    var typeArguments = inferrer.infer(typeParameters,
-        failAtError: true, genericMetadataIsEnabled: true);
-    if (typeArguments == null) {
-      return null;
-    }
-    var substitution = Substitution.fromPairs(
-      typeParameters,
-      typeArguments,
-    );
-    return substitution.substituteType(
-      extension.extendedType,
-    );
-  }
 }
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
index 0c52fb4..73ca312 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
@@ -6,6 +6,7 @@
 
 import 'package:_fe_analyzer_shared/src/scanner/token.dart';
 import 'package:analysis_server/plugin/edit/fix/fix_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/extension_cache.dart';
 import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/transform_override_set.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
@@ -393,6 +394,9 @@
   /// Returns the EOL to use for this [CompilationUnit].
   String get eol => utils.endOfLine;
 
+  /// Return the extension cache used to find available extensions.
+  ExtensionCache get extensionCache => _context.dartFixContext!.extensionCache;
+
   String get file => _context.file;
 
   Flutter get flutter => Flutter.instance;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
index 6c90568..69137bf 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
@@ -9,8 +9,11 @@
 import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
 import 'package:analysis_server/src/services/correction/namespace.dart';
 import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analysis_server/src/utilities/extensions/element.dart';
+import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/source/source_range.dart';
 import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
@@ -24,26 +27,58 @@
 
   @override
   Iterable<CorrectionProducer> get producers sync* {
+    final node = this.node;
     if (_importKind == _ImportKind.dartAsync) {
       yield* _importLibrary(DartFixKind.IMPORT_ASYNC, Uri.parse('dart:async'));
     } else if (_importKind == _ImportKind.forExtension) {
       if (node is SimpleIdentifier) {
-        var extensionName = (node as SimpleIdentifier).name;
+        var extensionName = node.name;
         yield* _importLibraryForElement(
             extensionName,
             const [ElementKind.EXTENSION],
             const [TopLevelDeclarationKind.extension]);
       }
+    } else if (_importKind == _ImportKind.forExtensionMember) {
+      /// Return producers that will import extensions that apply to the
+      /// [targetType] and that define a member with the given [memberName].
+      Iterable<CorrectionProducer> importMatchingExtensions(
+          String memberName, DartType? targetType) sync* {
+        if (targetType == null) {
+          return;
+        }
+        var definingLibraries = extensionCache.membersByName[memberName];
+        if (definingLibraries != null) {
+          for (var definingLibrary in definingLibraries) {
+            var libraryPath = definingLibrary.libraryPath;
+            var uri = sessionHelper.session.uriConverter.pathToUri(libraryPath);
+            if (uri != null) {
+              yield* _importExtensionInLibrary(uri, targetType, memberName);
+            }
+          }
+        }
+      }
+
+      if (node is SimpleIdentifier) {
+        var memberName = node.name;
+        if (memberName.startsWith('_')) {
+          return;
+        }
+        yield* importMatchingExtensions(memberName, _targetType(node));
+      } else if (node is BinaryExpression) {
+        var memberName = node.operator.lexeme;
+        yield* importMatchingExtensions(
+            memberName, node.leftOperand.staticType);
+      }
     } else if (_importKind == _ImportKind.forFunction) {
       if (node is SimpleIdentifier) {
-        if (node.parent is MethodInvocation) {
-          var invocation = node.parent as MethodInvocation;
-          if (invocation.realTarget != null || invocation.methodName != node) {
+        var parent = node.parent;
+        if (parent is MethodInvocation) {
+          if (parent.realTarget != null || parent.methodName != node) {
             return;
           }
         }
 
-        var name = (node as SimpleIdentifier).name;
+        var name = node.name;
         yield* _importLibraryForElement(name, const [
           ElementKind.FUNCTION,
           ElementKind.TOP_LEVEL_VARIABLE
@@ -127,6 +162,45 @@
     return null;
   }
 
+  Iterable<CorrectionProducer> _importExtensionInLibrary(
+      Uri uri, DartType targetType, String memberName) sync* {
+    // Look to see whether the library at the [uri] is already imported. If it
+    // is, then we can check the extension elements without needing to perform
+    // additional analysis.
+    var foundImport = false;
+    for (var imp in libraryElement.imports) {
+      // prepare element
+      var importedLibrary = imp.importedLibrary;
+      if (importedLibrary == null || importedLibrary.source.uri != uri) {
+        continue;
+      }
+      foundImport = true;
+      for (var extension in importedLibrary.matchingExtensionsWithMember(
+          libraryElement, targetType, memberName)) {
+        // If the import has a combinator that needs to be updated, then offer
+        // to update it.
+        var combinators = imp.combinators;
+        if (combinators.length == 1) {
+          var combinator = combinators[0];
+          if (combinator is HideElementCombinator) {
+            // TODO(brianwilkerson) Support removing the extension name from a
+            //  hide combinator.
+          } else if (combinator is ShowElementCombinator) {
+            yield _ImportLibraryShow(
+                uri.toString(), combinator, extension.name!);
+          }
+        }
+      }
+    }
+
+    // If the library at the [uri] is not already imported, we return a
+    // correction producer that will either add an import or not based on the
+    // result of analyzing the library.
+    if (!foundImport) {
+      yield _ImportLibraryContainingExtension(uri, targetType, memberName);
+    }
+  }
+
   /// Returns a list of one or two import corrections.
   ///
   /// If [relativeUri] is `null`, only one correction, with an absolute import
@@ -187,21 +261,22 @@
       }
       // may be update "show" directive
       var combinators = imp.combinators;
-      if (combinators.length == 1 && combinators[0] is ShowElementCombinator) {
-        var showCombinator = combinators[0] as ShowElementCombinator;
-        // prepare new set of names to show
-        Set<String> showNames = SplayTreeSet<String>();
-        showNames.addAll(showCombinator.shownNames);
-        showNames.add(name);
-        // prepare library name - unit name or 'dart:name' for SDK library
-        var libraryName =
-            libraryElement.definingCompilationUnit.source.uri.toString();
-        if (libraryElement.isInSdk) {
-          libraryName = libraryElement.source.shortName;
+      if (combinators.length == 1) {
+        var combinator = combinators[0];
+        if (combinator is HideElementCombinator) {
+          // TODO(brianwilkerson) Support removing the element name from a
+          //  hide combinator.
+        } else if (combinator is ShowElementCombinator) {
+          // prepare library name - unit name or 'dart:name' for SDK library
+          var libraryName =
+              libraryElement.definingCompilationUnit.source.uri.toString();
+          if (libraryElement.isInSdk) {
+            libraryName = libraryElement.source.shortName;
+          }
+          // don't add this library again
+          alreadyImportedWithPrefix.add(libraryElement.source.fullName);
+          yield _ImportLibraryShow(libraryName, combinator, name);
         }
-        // don't add this library again
-        alreadyImportedWithPrefix.add(libraryElement.source.fullName);
-        yield _ImportLibraryShow(libraryName, showCombinator, showNames);
       }
     }
     // Find new top-level declarations.
@@ -250,6 +325,47 @@
     return false;
   }
 
+  /// If the [node] might represent an access to a member of a type, return the
+  /// type of the object being accessed, otherwise return `null`.
+  DartType? _targetType(SimpleIdentifier node) {
+    var parent = node.parent;
+    if (parent is MethodInvocation && parent.methodName == node) {
+      var target = parent.realTarget;
+      if (target != null) {
+        return target.staticType;
+      }
+    } else if (parent is PropertyAccess && parent.propertyName == node) {
+      return parent.realTarget.staticType;
+    } else if (parent is PrefixedIdentifier && parent.identifier == node) {
+      return parent.prefix.staticType;
+    }
+    // If there is no explicit target, then return the type of an implicit
+    // `this`.
+    DartType? enclosingThisType(AstNode node) {
+      var parent = node.parent;
+      if (parent is ClassOrMixinDeclaration) {
+        return parent.declaredElement?.thisType;
+      } else if (parent is ExtensionDeclaration) {
+        return parent.extendedType.type;
+      }
+    }
+
+    while (parent != null) {
+      if (parent is MethodDeclaration) {
+        if (!parent.isStatic) {
+          return enclosingThisType(parent);
+        }
+        return null;
+      } else if (parent is FieldDeclaration) {
+        if (!parent.isStatic) {
+          return enclosingThisType(parent);
+        }
+        return null;
+      }
+      parent = parent.parent;
+    }
+  }
+
   /// Return an instance of this class that will add an import of `dart:async`.
   /// Used as a tear-off in `FixProcessor`.
   static ImportLibrary dartAsync() => ImportLibrary(_ImportKind.dartAsync);
@@ -259,6 +375,9 @@
   static ImportLibrary forExtension() =>
       ImportLibrary(_ImportKind.forExtension);
 
+  static ImportLibrary forExtensionMember() =>
+      ImportLibrary(_ImportKind.forExtensionMember);
+
   /// Return an instance of this class that will add an import for a top-level
   /// function. Used as a tear-off in `FixProcessor`.
   static ImportLibrary forFunction() => ImportLibrary(_ImportKind.forFunction);
@@ -273,8 +392,7 @@
   static ImportLibrary forType() => ImportLibrary(_ImportKind.forType);
 }
 
-/// A correction processor that can make one of the possible change computed by
-/// the [ImportLibrary] producer.
+/// A correction processor that can add an import using an absolute URI.
 class _ImportAbsoluteLibrary extends CorrectionProducer {
   final FixKind _fixKind;
 
@@ -301,13 +419,53 @@
 enum _ImportKind {
   dartAsync,
   forExtension,
+  forExtensionMember,
   forFunction,
   forTopLevelVariable,
   forType
 }
 
-/// A correction processor that can make one of the possible change computed by
-/// the [ImportLibrary] producer.
+/// A correction processor that can add an import of a library containing an
+/// extension, but which does so only if the extension applies to a given type.
+class _ImportLibraryContainingExtension extends CorrectionProducer {
+  /// The URI of the library defining the extension.
+  Uri uri;
+
+  /// The type of the target that the extension must apply to.
+  DartType targetType;
+
+  /// The name of the member that the extension must declare.
+  String memberName;
+
+  /// The URI that is being proposed for the import directive.
+  String _uriText = '';
+
+  _ImportLibraryContainingExtension(this.uri, this.targetType, this.memberName);
+
+  @override
+  List<Object> get fixArguments => [_uriText];
+
+  @override
+  FixKind get fixKind => DartFixKind.IMPORT_LIBRARY_PROJECT1;
+
+  @override
+  Future<void> compute(ChangeBuilder builder) async {
+    var result = await sessionHelper.session.getLibraryByUri2(uri.toString());
+    if (result is LibraryElementResult) {
+      var library = result.element;
+      if (library
+          .matchingExtensionsWithMember(libraryElement, targetType, memberName)
+          .isNotEmpty) {
+        await builder.addDartFileEdit(file, (builder) {
+          _uriText = builder.importLibrary(uri);
+        });
+      }
+    }
+  }
+}
+
+/// A correction processor that can add a prefix to an identifier defined in a
+/// library that is already imported but that is imported with a prefix.
 class _ImportLibraryPrefix extends CorrectionProducer {
   final LibraryElement _importedLibrary;
   final PrefixElement _importPrefix;
@@ -334,16 +492,16 @@
   }
 }
 
-/// A correction processor that can make one of the possible change computed by
-/// the [ImportLibrary] producer.
+/// A correction processor that can add a name to the show combinator of an
+/// existing import.
 class _ImportLibraryShow extends CorrectionProducer {
   final String _libraryName;
 
   final ShowElementCombinator _showCombinator;
 
-  final Set<String> _showNames;
+  final String _addedName;
 
-  _ImportLibraryShow(this._libraryName, this._showCombinator, this._showNames);
+  _ImportLibraryShow(this._libraryName, this._showCombinator, this._addedName);
 
   @override
   List<Object> get fixArguments => [_libraryName];
@@ -353,7 +511,10 @@
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
-    var newShowCode = 'show ${_showNames.join(', ')}';
+    Set<String> showNames = SplayTreeSet<String>();
+    showNames.addAll(_showCombinator.shownNames);
+    showNames.add(_addedName);
+    var newShowCode = 'show ${showNames.join(', ')}';
     var offset = _showCombinator.offset;
     var length = _showCombinator.end - offset;
     var libraryFile = resolvedResult.libraryElement.source.fullName;
@@ -363,8 +524,7 @@
   }
 }
 
-/// A correction processor that can make one of the possible change computed by
-/// the [ImportLibrary] producer.
+/// A correction processor that can add an import using a relative URI.
 class _ImportRelativeLibrary extends CorrectionProducer {
   final FixKind _fixKind;
 
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index f76a542..97e39a21 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/plugin/edit/fix/fix_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/extension_cache.dart';
 import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
 import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer/dart/analysis/results.dart';
@@ -129,11 +130,16 @@
   @override
   final AnalysisError error;
 
+  @override
+  final ExtensionCache extensionCache;
+
   final List<TopLevelDeclaration> Function(String name)
       getTopLevelDeclarationsFunction;
 
   DartFixContextImpl(this.instrumentationService, this.workspace,
-      this.resolveResult, this.error, this.getTopLevelDeclarationsFunction);
+      this.resolveResult, this.error, this.getTopLevelDeclarationsFunction,
+      {ExtensionCache? extensionCache})
+      : extensionCache = extensionCache ?? ExtensionCache();
 
   @override
   List<TopLevelDeclaration> getTopLevelDeclarations(String name) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 4ebbaad..0ecd309 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -234,6 +234,7 @@
           resolveResult,
           error,
           (name) => [],
+          extensionCache: context.extensionCache,
         );
         fixState = await _fixError(fixContext, fixState, generator(), error);
       }
@@ -1131,6 +1132,7 @@
     ],
     CompileTimeErrorCode.UNDEFINED_GETTER: [
       DataDriven.newInstance,
+      ImportLibrary.forExtensionMember,
       ImportLibrary.forTopLevelVariable,
       ImportLibrary.forType,
     ],
@@ -1143,6 +1145,7 @@
     ],
     CompileTimeErrorCode.UNDEFINED_METHOD: [
       DataDriven.newInstance,
+      ImportLibrary.forExtensionMember,
       ImportLibrary.forFunction,
       ImportLibrary.forType,
     ],
@@ -1150,9 +1153,13 @@
       ChangeArgumentName.newInstance,
       DataDriven.newInstance,
     ],
+    CompileTimeErrorCode.UNDEFINED_OPERATOR: [
+      ImportLibrary.forExtensionMember,
+    ],
     CompileTimeErrorCode.UNDEFINED_SETTER: [
       DataDriven.newInstance,
-      // TODO(brianwilkerson) Support ImportLibrary
+      // TODO(brianwilkerson) Support ImportLibrary for non-extension members.
+      ImportLibrary.forExtensionMember,
     ],
     CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS: [
       DataDriven.newInstance,
diff --git a/pkg/analysis_server/lib/src/utilities/extensions/element.dart b/pkg/analysis_server/lib/src/utilities/extensions/element.dart
index 73e8eb8..764d8ab 100644
--- a/pkg/analysis_server/lib/src/utilities/extensions/element.dart
+++ b/pkg/analysis_server/lib/src/utilities/extensions/element.dart
@@ -2,7 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/generic_inferrer.dart';
+import 'package:analyzer/src/dart/element/type_algebra.dart';
+import 'package:analyzer/src/dart/element/type_system.dart';
 
 extension ClassElementExtensions on ClassElement {
   /// Return `true` if this element represents the class `Iterable` from
@@ -55,6 +60,58 @@
   }
 }
 
+extension ExtensionElementExtensions on ExtensionElement {
+  /// Use the [type] of the object being extended in the [library] to compute
+  /// the actual type extended by this [extension]. Return the computed type,
+  /// or `null` if the type can't be computed.
+  DartType? resolvedExtendedType(LibraryElement library, DartType type) {
+    final typeParameters = this.typeParameters;
+    var inferrer =
+        GenericInferrer(library.typeSystem as TypeSystemImpl, typeParameters);
+    inferrer.constrainArgument(
+      type,
+      extendedType,
+      'extendedType',
+    );
+    var typeArguments = inferrer.infer(typeParameters,
+        failAtError: true, genericMetadataIsEnabled: true);
+    if (typeArguments == null) {
+      return null;
+    }
+    var substitution = Substitution.fromPairs(
+      typeParameters,
+      typeArguments,
+    );
+    return substitution.substituteType(
+      extendedType,
+    );
+  }
+}
+
+extension LibraryElementExtensions on LibraryElement {
+  /// Return the extensions in this library that can be applied, within the
+  /// [containingLibrary], to the [targetType] and that define a member with the
+  /// given [memberName].
+  Iterable<ExtensionElement> matchingExtensionsWithMember(
+      LibraryElement containingLibrary,
+      DartType targetType,
+      String memberName) sync* {
+    for (var unit in units) {
+      for (var extension in unit.extensions) {
+        var extensionName = extension.name;
+        if (extensionName != null && !Identifier.isPrivateName(extensionName)) {
+          var extendedType =
+              extension.resolvedExtendedType(containingLibrary, targetType);
+          if (extendedType != null &&
+              typeSystem.isSubtypeOf(targetType, extendedType)) {
+            yield extension;
+          }
+        }
+      }
+    }
+  }
+}
+
 extension MethodElementExtensions on MethodElement {
   /// Return `true` if this element represents the method `cast` from either
   /// `Iterable`, `List`, `Map`, or `Set`.
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart
index 2c1d827..4e3c01b9 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart
@@ -79,6 +79,17 @@
 ''');
   }
 
+  @failingTest
+  Future<void> test_propertyAccess() async {
+    // We should not offer to define a local variable named 'g'.
+    await resolveTestCode('''
+void f(String s) {
+  s.g;
+}
+''');
+    await assertNoFix();
+  }
+
   Future<void> test_read_typeAssignment() async {
     await resolveTestCode('''
 main() {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
index 7ac6c2b..fd320f2 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
@@ -3,10 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
+import 'package:analysis_server/src/services/completion/dart/extension_cache.dart';
 import 'package:analysis_server/src/services/correction/change_workspace.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
 import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/error/lint_codes.dart';
@@ -172,9 +174,18 @@
 
 /// A base class defining support for writing fix processor tests.
 abstract class FixProcessorTest extends BaseFixProcessorTest {
+  /// The extension cache used for test purposes.
+  ExtensionCache extensionCache = ExtensionCache();
+
   /// Return the kind of fixes being tested by this test class.
   FixKind get kind;
 
+  Future<void> addUnimportedFile(String filePath, String content) async {
+    addSource(filePath, content);
+    var result = await session.getResolvedUnit2(filePath);
+    extensionCache.cacheFromResult(result as ResolvedUnitResult);
+  }
+
   Future<void> assertHasFix(String expected,
       {bool Function(AnalysisError)? errorFilter,
       int? length,
@@ -429,6 +440,7 @@
 
     var tracker = DeclarationsTracker(MemoryByteStore(), resourceProvider);
     tracker.addContext(analysisContext);
+    extensionCache.cacheFromResult(testAnalysisResult);
 
     var context = DartFixContextImpl(
       TestInstrumentationService(),
@@ -440,6 +452,7 @@
         provider.doTrackerWork();
         return provider.get(analysisContext, testFile, name);
       },
+      extensionCache: extensionCache,
     );
     return await DartFixContributor().computeFixes(context);
   }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart b/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
index 98c939b..ccd65da 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
@@ -39,6 +39,201 @@
     await assertNoFix();
   }
 
+  Future<void> test_extension_notImported_field_onThisType_fromClass() async {
+    addUnimportedFile('/home/test/lib/lib2.dart', '''
+import 'package:test/lib1.dart';
+
+extension E on C {
+  int m() => 0;
+}
+''');
+    addSource('/home/test/lib/lib1.dart', '''
+class C {}
+''');
+    await resolveTestCode('''
+import 'package:test/lib1.dart';
+
+class D extends C {
+  int f = m();
+}
+''');
+    await assertHasFix('''
+import 'package:test/lib1.dart';
+import 'package:test/lib2.dart';
+
+class D extends C {
+  int f = m();
+}
+''');
+  }
+
+  Future<void> test_extension_notImported_getter() async {
+    addUnimportedFile('/home/test/lib/lib.dart', '''
+extension E on String {
+  int get m => 0;
+}
+''');
+    await resolveTestCode('''
+void f(String s) {
+  s.m;
+}
+''');
+    await assertHasFix('''
+import 'package:test/lib.dart';
+
+void f(String s) {
+  s.m;
+}
+''');
+  }
+
+  Future<void> test_extension_notImported_method() async {
+    addUnimportedFile('/home/test/lib/lib.dart', '''
+extension E on String {
+  void m() {}
+}
+''');
+    await resolveTestCode('''
+void f(String s) {
+  s.m();
+}
+''');
+    await assertHasFix('''
+import 'package:test/lib.dart';
+
+void f(String s) {
+  s.m();
+}
+''');
+  }
+
+  Future<void> test_extension_notImported_method_extendsGeneric() async {
+    addUnimportedFile('/home/test/lib/lib.dart', '''
+import 'package:test/lib1.dart';
+
+extension E<T extends num> on List<T> {
+  void m() {}
+}
+''');
+    await resolveTestCode('''
+void f(List<int> l) {
+  l.m();
+}
+''');
+    await assertHasFix('''
+import 'package:test/lib.dart';
+
+void f(List<int> l) {
+  l.m();
+}
+''');
+  }
+
+  Future<void> test_extension_notImported_method_onThisType_fromClass() async {
+    addUnimportedFile('/home/test/lib/lib2.dart', '''
+import 'package:test/lib1.dart';
+
+extension E on C {
+  void m() {}
+}
+''');
+    addSource('/home/test/lib/lib1.dart', '''
+class C {}
+''');
+    await resolveTestCode('''
+import 'package:test/lib1.dart';
+
+class D extends C {
+  void m2() {
+    m();
+  }
+}
+''');
+    await assertHasFix('''
+import 'package:test/lib1.dart';
+import 'package:test/lib2.dart';
+
+class D extends C {
+  void m2() {
+    m();
+  }
+}
+''');
+  }
+
+  Future<void>
+      test_extension_notImported_method_onThisType_fromExtension() async {
+    addUnimportedFile('/home/test/lib/lib2.dart', '''
+import 'package:test/lib1.dart';
+
+extension E on C {
+  void m() {}
+}
+''');
+    addSource('/home/test/lib/lib1.dart', '''
+class C {}
+''');
+    await resolveTestCode('''
+import 'package:test/lib1.dart';
+
+extension F on C {
+  void m2() {
+    m();
+  }
+}
+''');
+    await assertHasFix('''
+import 'package:test/lib1.dart';
+import 'package:test/lib2.dart';
+
+extension F on C {
+  void m2() {
+    m();
+  }
+}
+''');
+  }
+
+  Future<void> test_extension_notImported_operator() async {
+    addUnimportedFile('/home/test/lib/lib.dart', '''
+extension E on String {
+  String operator -(String other) => this;
+}
+''');
+    await resolveTestCode('''
+void f(String s) {
+  s - '2';
+}
+''');
+    await assertHasFix('''
+import 'package:test/lib.dart';
+
+void f(String s) {
+  s - '2';
+}
+''');
+  }
+
+  Future<void> test_extension_notImported_setter() async {
+    addUnimportedFile('/home/test/lib/lib.dart', '''
+extension E on String {
+  set m(int v) {}
+}
+''');
+    await resolveTestCode('''
+void f(String s) {
+  s.m = 2;
+}
+''');
+    await assertHasFix('''
+import 'package:test/lib.dart';
+
+void f(String s) {
+  s.m = 2;
+}
+''');
+  }
+
   Future<void> test_invalidUri_interpolation() async {
     addSource('/home/test/lib/lib.dart', r'''
 class Test {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart b/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart
index e54adba..118b44f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart
@@ -19,6 +19,98 @@
   @override
   FixKind get kind => DartFixKind.IMPORT_LIBRARY_SHOW;
 
+  Future<void> test_extension_notShown_getter() async {
+    addSource('/home/test/lib/lib.dart', '''
+class C {}
+extension E on String {
+  int get m => 0;
+}
+''');
+    await resolveTestCode('''
+import 'package:test/lib.dart' show C;
+
+void f(String s, C c) {
+  s.m;
+}
+''');
+    await assertHasFix('''
+import 'package:test/lib.dart' show C, E;
+
+void f(String s, C c) {
+  s.m;
+}
+''');
+  }
+
+  Future<void> test_extension_notShown_method() async {
+    addSource('/home/test/lib/lib.dart', '''
+class C {}
+extension E on String {
+  void m() {}
+}
+''');
+    await resolveTestCode('''
+import 'package:test/lib.dart' show C;
+
+void f(String s, C c) {
+  s.m();
+}
+''');
+    await assertHasFix('''
+import 'package:test/lib.dart' show C, E;
+
+void f(String s, C c) {
+  s.m();
+}
+''');
+  }
+
+  Future<void> test_extension_notShown_operator() async {
+    addSource('/home/test/lib/lib.dart', '''
+class C {}
+extension E on String {
+  String operator -(String other) => this;
+}
+''');
+    await resolveTestCode('''
+import 'package:test/lib.dart' show C;
+
+void f(String s, C c) {
+  s - '2';
+}
+''');
+    await assertHasFix('''
+import 'package:test/lib.dart' show C, E;
+
+void f(String s, C c) {
+  s - '2';
+}
+''');
+  }
+
+  Future<void> test_extension_notShown_setter() async {
+    addSource('/home/test/lib/lib.dart', '''
+class C {}
+extension E on String {
+  set m(int v) {}
+}
+''');
+    await resolveTestCode('''
+import 'package:test/lib.dart' show C;
+
+void f(String s, C c) {
+  s.m = 2;
+}
+''');
+    await assertHasFix('''
+import 'package:test/lib.dart' show C, E;
+
+void f(String s, C c) {
+  s.m = 2;
+}
+''');
+  }
+
   Future<void> test_override_samePackage() async {
     addSource('/home/test/lib/lib.dart', '''
 class A {}
diff --git a/pkg/analyzer/lib/src/dart/error/todo_codes.dart b/pkg/analyzer/lib/src/dart/error/todo_codes.dart
index 3fbccd3..ef128be 100644
--- a/pkg/analyzer/lib/src/dart/error/todo_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/todo_codes.dart
@@ -30,9 +30,9 @@
    * But not
    * * todo
    * * TODOS
-   * 
+   *
    * It also supports wrapped TODOs where the next line is indented by a space:
-   * 
+   *
    *   /**
    *    * TODO(username): This line is
    *    *  wrapped onto the next line
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 8696184..8a00fa9 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -55,6 +55,11 @@
       object is CiderSearchMatch &&
       path == object.path &&
       const ListEquality<int>().equals(offsets, object.offsets);
+
+  @override
+  String toString() {
+    return '($path, $offsets)';
+  }
 }
 
 class FileContext {
diff --git a/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart b/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
index 2b66120..a09335c 100644
--- a/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
@@ -305,6 +305,13 @@
   }
 
   @override
+  bool visitFunctionReference(FunctionReference node) {
+    // Note: `node.function` could be a reference to a method
+    // (`Target.methodName`) so we need to visit it in case the target exits.
+    return node.function.accept(this)!;
+  }
+
+  @override
   bool visitGenericFunctionType(GenericFunctionType node) => false;
 
   @override
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index a4f9b42..29d755d 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -3532,14 +3532,6 @@
         typeArguments.leftBracket,
         typeArguments.rightBracket,
       );
-      // Since analyzer visitors don't yet support constructor tear-offs, create
-      // a FunctionExpressionInvocation with a synthetic argument list instead.
-      // TODO(paulberry): once we have visitor support for constructor
-      // tear-offs, fall through and return a FunctionReference instead since
-      // that should lead to better quality error recovery.
-      push(ast.functionExpressionInvocation(receiver, typeArguments,
-          _syntheticArgumentList(typeArguments.rightBracket)));
-      return;
     }
     push(ast.functionReference(
         function: receiver, typeArguments: typeArguments));
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 54b29b2..43750b2 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -163,6 +163,12 @@
   @override
   void visitFunctionExpression(FunctionExpression node) {}
 
+  @override
+  void visitFunctionReference(covariant FunctionReferenceImpl node) {
+    // TODO(paulberry): implement
+    node.staticType = _dynamicType;
+  }
+
   /// The Dart Language Specification, 12.11.1: <blockquote>The static type of a new expression of
   /// either the form <i>new T.id(a<sub>1</sub>, &hellip;, a<sub>n</sub>)</i> or the form <i>new
   /// T(a<sub>1</sub>, &hellip;, a<sub>n</sub>)</i> is <i>T</i>.</blockquote>
diff --git a/pkg/analyzer/test/generated/function_reference_parser_test.dart b/pkg/analyzer/test/generated/function_reference_parser_test.dart
index fe9091f..13d0d82 100644
--- a/pkg/analyzer/test/generated/function_reference_parser_test.dart
+++ b/pkg/analyzer/test/generated/function_reference_parser_test.dart
@@ -36,23 +36,9 @@
   }
 
   void test_feature_disabled() {
-    var expression =
-        (parseStatement('f<a, b>;', featureSet: preConstructorTearoffs)
-                as ExpressionStatement)
-            .expression;
-    // TODO(paulberry): once we have visitor support for FunctionReference, this
-    // should be parsed as a FunctionReference, so we should be able to validate
-    // it using `expect_f_a_b`.  But for now it's parsed as a
-    // FunctionExpressionInvocation with synthetic arguments.
-    var functionExpressionInvocation =
-        expression as FunctionExpressionInvocation;
-    expect(
-        (functionExpressionInvocation.function as SimpleIdentifier).name, 'f');
-    expect(functionExpressionInvocation.argumentList.arguments, isEmpty);
-    var typeArgs = functionExpressionInvocation.typeArguments!.arguments;
-    expect(typeArgs, hasLength(2));
-    expect(((typeArgs[0] as TypeName).name as SimpleIdentifier).name, 'a');
-    expect(((typeArgs[1] as TypeName).name as SimpleIdentifier).name, 'b');
+    expect_f_a_b((parseStatement('f<a, b>;', featureSet: preConstructorTearoffs)
+            as ExpressionStatement)
+        .expression);
     listener.assertErrors([
       expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 1, 6),
     ]);
diff --git a/pkg/analyzer/test/generated/simple_parser_test.dart b/pkg/analyzer/test/generated/simple_parser_test.dart
index 0198aa1..3a52b79 100644
--- a/pkg/analyzer/test/generated/simple_parser_test.dart
+++ b/pkg/analyzer/test/generated/simple_parser_test.dart
@@ -1449,8 +1449,8 @@
     expect(body.expression, isMethodInvocation);
     var methodInvocation = body.expression as MethodInvocationImpl;
     var target = methodInvocation.target!;
-    expect(target, isFunctionExpressionInvocation);
-    expect(target.toSource(), 'C<E>()');
+    expect(target, isFunctionReference);
+    expect(target.toSource(), 'C<E>');
     expect(methodInvocation.methodName.name, 'n');
     expect(methodInvocation.argumentList, isNotNull);
     expect(methodInvocation.typeArguments!.arguments, hasLength(1));
diff --git a/pkg/analyzer/test/generated/static_type_warning_code_test.dart b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
index 7a161cd..447f887 100644
--- a/pkg/analyzer/test/generated/static_type_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
@@ -475,7 +475,7 @@
     await assertErrorsInCode('''
 Future<Future<int>> ffi() => null;
 f() async {
-  Future<int> b = await ffi(); 
+  Future<int> b = await ffi();
 }
 ''', [
       error(HintCode.UNUSED_LOCAL_VARIABLE, 61, 1),
diff --git a/pkg/analyzer/test/src/dart/analysis/dependency/reference_collector_test.dart b/pkg/analyzer/test/src/dart/analysis/dependency/reference_collector_test.dart
index 01ca1e1..5e1206c 100644
--- a/pkg/analyzer/test/src/dart/analysis/dependency/reference_collector_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/dependency/reference_collector_test.dart
@@ -1507,7 +1507,7 @@
     var library = await buildTestLibrary(a, r'''
 class C {
   var f;
-  
+
   C.test() : f = x;
 }
 ''');
@@ -1567,7 +1567,7 @@
     var library = await buildTestLibrary(a, r'''
 class C extends A {
   C.test() : this.named(x);
-  
+
   C.named(a);
 }
 ''');
@@ -1579,7 +1579,7 @@
     var library = await buildTestLibrary(a, r'''
 class C extends A {
   C.test() : this(x);
-  
+
   C(a);
 }
 ''');
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
index 8251b43..63c5831 100644
--- a/pkg/analyzer/test/src/dart/analysis/index_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -1327,7 +1327,7 @@
   int get getter1 => null;
   void set setter1(_) {}
   void method1() {}
-  
+
   static int staticField;
   static void staticMethod() {}
 }
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index e1646c9..6f2cd6e 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -463,7 +463,7 @@
   void func() {
    print('hello');
  }
- 
+
  void func2() {
    func();
  }
@@ -483,7 +483,7 @@
     await resolveFile(bPath);
     var result = fileResolver.findReferences(17, aPath);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(aPath, [17, 69]),
+      CiderSearchMatch(aPath, [17, 68]),
       CiderSearchMatch(bPath, [46])
     ];
     expect(result, unorderedEquals(expected));
@@ -593,14 +593,14 @@
     newFile(aPath, content: r'''
 class Foo<T> {
   List<T> l;
-  
+
   void bar(T t) {}
 }
 ''');
     await resolveFile(aPath);
     var result = fileResolver.findReferences(10, aPath);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(aPath, [10, 22, 42])
+      CiderSearchMatch(aPath, [10, 22, 40])
     ];
     expect(result.map((e) => e.path),
         unorderedEquals(expected.map((e) => e.path)));
diff --git a/pkg/analyzer/test/src/dart/resolution/comment_test.dart b/pkg/analyzer/test/src/dart/resolution/comment_test.dart
index 0f894bf..173fa0a 100644
--- a/pkg/analyzer/test/src/dart/resolution/comment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/comment_test.dart
@@ -148,13 +148,13 @@
 abstract class A {
   /// [p1]
   ma(int p1);
-  
+
   /// [p2]
   mb(int p2);
-  
+
   /// [p3] and [p4]
   mc(int p3, p4());
-  
+
   /// [p5]
   md(int p5, {int p6});
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
index 28b1f8c..a76e41a 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -652,7 +652,7 @@
 class C<T extends MyFunction> {
   T foo;
   C(this.foo);
-  
+
   main() {
     foo(0);
   }
@@ -733,13 +733,13 @@
     await assertErrorsInCode(r'''
 class C {
   static int foo = 0;
-  
+
   main() {
     foo();
   }
 }
 ''', [
-      error(CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, 50, 3),
+      error(CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, 48, 3),
     ]);
 
     var invocation = findNode.functionExpressionInvocation('foo();');
@@ -1654,7 +1654,7 @@
 class C<T extends A> {
   T a;
   C(this.a);
-  
+
   main() {
     a.foo(0);
   }
diff --git a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
index e86d332..094323e 100644
--- a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
@@ -99,7 +99,7 @@
 class A {
   int operator[](int index) => 0;
   operator[]=(int index, num _) {}
-  
+
   void f() {
     this[0]++;
   }
diff --git a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
index c49b4a6..06fd33d 100644
--- a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
@@ -146,7 +146,7 @@
 class A {
   int operator[](int index) => 0;
   operator[]=(int index, num _) {}
-  
+
   void f() {
     ++this[0];
   }
diff --git a/pkg/analyzer/test/src/dart/resolution/simple_identifier_test.dart b/pkg/analyzer/test/src/dart/resolution/simple_identifier_test.dart
index 83c2471..4a33901 100644
--- a/pkg/analyzer/test/src/dart/resolution/simple_identifier_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/simple_identifier_test.dart
@@ -100,7 +100,7 @@
     await assertNoErrorsInCode(r'''
 main() {
   Never;
-}    
+}
 ''');
     assertSimpleIdentifier(
       findNode.simple('Never;'),
diff --git a/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart b/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
index bb0999a..a24235f 100644
--- a/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
+++ b/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
@@ -2,8 +2,10 @@
 // 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/ast/ast.dart';
 import 'package:analyzer/src/dart/resolver/exit_detector.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/test_utilities/find_node.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -143,6 +145,11 @@
 /// See [ExitDetectorResolvedStatementTest] for tests that require the AST to be resolved.
 @reflectiveTest
 class ExitDetectorParsedStatementTest extends ParseBase {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = FeatureSet.forTesting(
+        sdkVersion: '2.13', additionalFeatures: [Feature.constructor_tearoffs]);
+
   test_asExpression() async {
     _assertFalse('a as Object;');
   }
@@ -514,6 +521,18 @@
     _assertTrue("(throw 42)(g);");
   }
 
+  test_functionReference() async {
+    _assertFalse('a<int>;');
+  }
+
+  test_functionReference_method() async {
+    _assertFalse('(a).m<int>;');
+  }
+
+  test_functionReference_method_throw() async {
+    _assertTrue('(throw 42).m<int>;');
+  }
+
   test_identifier_prefixedIdentifier() async {
     _assertFalse('a.b;');
   }
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_of_do_not_store_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_of_do_not_store_test.dart
index 56b086d..40ba01a 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_of_do_not_store_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_of_do_not_store_test.dart
@@ -216,7 +216,7 @@
     await assertErrorsInCode('''
 import 'package:meta/meta.dart';
 
-String top = A().f; 
+String top = A().f;
 
 class A{
   @doNotStore
@@ -246,7 +246,7 @@
     await assertErrorsInCode('''
 import 'package:meta/meta.dart';
 
-String top = v; 
+String top = v;
 
 @doNotStore
 String get v => '';
@@ -259,7 +259,7 @@
     await assertErrorsInCode('''
 import 'package:meta/meta.dart';
 
-String top = A().v(); 
+String top = A().v();
 
 class A{
   @doNotStore
diff --git a/pkg/analyzer/test/src/diagnostics/experiment_not_enabled_test.dart b/pkg/analyzer/test/src/diagnostics/experiment_not_enabled_test.dart
index e1037ea..c0ecd09 100644
--- a/pkg/analyzer/test/src/diagnostics/experiment_not_enabled_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/experiment_not_enabled_test.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
-import 'package:analyzer/src/error/codes.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../dart/resolution/context_collection_resolution.dart';
@@ -26,10 +25,6 @@
   Foo<int>.bar.baz();
 }
 ''', [
-      // TODO(paulberry): the INVOCATION_OF_NON_FUNCTION_EXPRESSION error is
-      // bogus, and should go away once we implement visitor and resolution
-      // support for constructor tearoffs.
-      error(CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, 67, 3),
       error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 70, 5),
     ]);
   }
@@ -45,10 +40,6 @@
   Foo<int>.bar.baz();
 }
 ''', [
-      // TODO(paulberry): the INVOCATION_OF_NON_FUNCTION_EXPRESSION error is
-      // bogus, and should go away once we implement visitor and resolution
-      // support for constructor tearoffs.
-      error(CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, 80, 3),
       error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 83, 5),
     ]);
   }
diff --git a/pkg/analyzer/test/src/diagnostics/missing_return_test.dart b/pkg/analyzer/test/src/diagnostics/missing_return_test.dart
index 3972ae7..7fbed0b 100644
--- a/pkg/analyzer/test/src/diagnostics/missing_return_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/missing_return_test.dart
@@ -97,7 +97,7 @@
 
   test_functionExpression_async_block_futureInt() async {
     await assertErrorsInCode(r'''
-Future<int> Function() f = () async {}; 
+Future<int> Function() f = () async {};
 ''', [
       error(HintCode.MISSING_RETURN, 27, 11),
     ]);
diff --git a/pkg/analyzer/test/src/diagnostics/private_setter_test.dart b/pkg/analyzer/test/src/diagnostics/private_setter_test.dart
index a173db7..be8cabb 100644
--- a/pkg/analyzer/test/src/diagnostics/private_setter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/private_setter_test.dart
@@ -68,7 +68,7 @@
     newFile('$testPackageLibPath/a.dart', content: r'''
 class A {
   static set _foo(int _) {}
-  
+
   static int get _foo => 0;
 }
 ''');
diff --git a/pkg/analyzer/test/src/diagnostics/referenced_before_declaration_test.dart b/pkg/analyzer/test/src/diagnostics/referenced_before_declaration_test.dart
index cdcd43d..1e8a99a 100644
--- a/pkg/analyzer/test/src/diagnostics/referenced_before_declaration_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/referenced_before_declaration_test.dart
@@ -200,7 +200,7 @@
 void f() {
   // ignore:unused_label
   label: var v = 0;
-  v; 
+  v;
 }
 ''');
 
diff --git a/pkg/analyzer/test/src/diagnostics/return_of_do_not_store_test.dart b/pkg/analyzer/test/src/diagnostics/return_of_do_not_store_test.dart
index 9722e80..cfbbbe3 100644
--- a/pkg/analyzer/test/src/diagnostics/return_of_do_not_store_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/return_of_do_not_store_test.dart
@@ -165,7 +165,7 @@
   }
 
   String getV2() => _v;
-  
+
   @doNotStore
   String getV3() => _v;
 }
diff --git a/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart b/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart
index c5c9ddf..ab0bbca 100644
--- a/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart
@@ -451,7 +451,7 @@
 
   test_function_async_expression_dynamic__to_Future_int() async {
     await assertNoErrorsInCode(r'''
-Future<int> f(dynamic a) async => a; 
+Future<int> f(dynamic a) async => a;
 ''');
   }
 
diff --git a/pkg/analyzer/test/src/diagnostics/todo_test.dart b/pkg/analyzer/test/src/diagnostics/todo_test.dart
index c2cb064..f61b675 100644
--- a/pkg/analyzer/test/src/diagnostics/todo_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/todo_test.dart
@@ -40,12 +40,12 @@
    */
   /* TODO(a): Implement something
    *  that is too long for one line
-   * 
+   *
    *  This line is not part of the todo
    */
   /* TODO: Implement something
    *  that is too long for one line
-   * 
+   *
    *  This line is not part of the todo
    */
 }
@@ -56,7 +56,7 @@
           text: 'TODO: Implement something that is too long for one line'),
       error(TodoCode.TODO, 241, 64,
           text: 'TODO(a): Implement something that is too long for one line'),
-      error(TodoCode.TODO, 363, 61,
+      error(TodoCode.TODO, 362, 61,
           text: 'TODO: Implement something that is too long for one line'),
     ]);
   }
@@ -145,12 +145,12 @@
 
   // TODO: Implement something
   //  that is too long for one line
-  
+
   //  this is not part of the todo
 
   // TODO: Implement something
   //  that is too long for one line
-  // 
+  //
   //  this is not part of the todo
 }
 ''', [
@@ -158,7 +158,7 @@
           text: 'TODO: Implement something that is too long for one line'),
       error(TodoCode.TODO, 116, 61,
           text: 'TODO: Implement something that is too long for one line'),
-      error(TodoCode.TODO, 222, 61,
+      error(TodoCode.TODO, 220, 61,
           text: 'TODO: Implement something that is too long for one line'),
     ]);
   }
diff --git a/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart b/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart
index 1b663a6..cee7219 100644
--- a/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart
@@ -137,7 +137,7 @@
     testRecovery('''
 f() {
   var x;
-  x = 
+  x =
 }
 ''', [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN], '''
 f() {
@@ -195,7 +195,7 @@
 
   void test_conditionalExpression_else() {
     testRecovery('''
-f() => x ? y : 
+f() => x ? y :
 ''', [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN], '''
 f() => x ? y : _s_;
 ''');
diff --git a/pkg/analyzer/test/src/pubspec/pubspec_validator_test.dart b/pkg/analyzer/test/src/pubspec/pubspec_validator_test.dart
index 7ad97b0..005d55f 100644
--- a/pkg/analyzer/test/src/pubspec/pubspec_validator_test.dart
+++ b/pkg/analyzer/test/src/pubspec/pubspec_validator_test.dart
@@ -232,7 +232,7 @@
 name: sample
 dependencies:
   foo:
-    git:      
+    git:
       url: git@github.com:foo/foo.git
       path: path/to/foo
 ''');
@@ -244,7 +244,7 @@
 version: 0.1.0
 dependencies:
   foo:
-    git:      
+    git:
       url: git@github.com:foo/foo.git
       path: path/to/foo
 ''', [PubspecWarningCode.INVALID_DEPENDENCY]);
@@ -257,7 +257,7 @@
 publish_to: none
 dependencies:
   foo:
-    git:      
+    git:
       url: git@github.com:foo/foo.git
       path: path/to/foo
 ''');
@@ -291,7 +291,7 @@
 name: sample
 dependencies:
   foo:
-    path: 
+    path:
      - baz
 ''');
   }
@@ -425,7 +425,7 @@
 version: 0.1.0
 dev_dependencies:
   foo:
-    git:      
+    git:
       url: git@github.com:foo/foo.git
       path: path/to/foo
 ''');
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index bd6e007..7074657 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -1175,7 +1175,7 @@
     var library = await checkLibrary('''
 class C {
   int get x => 0;
-  void set x(int value) {} 
+  void set x(int value) {}
 }
 ''');
     checkElementText(
@@ -2194,7 +2194,7 @@
 class A {}
 
 class B {}
-    
+
 class Raw = Object with A, B;
 
 /// Comment 1.
@@ -2226,33 +2226,33 @@
 }
 class B/*codeOffset=12, codeLength=10*/ {
 }
-class alias Raw/*codeOffset=28, codeLength=29*/ extends Object with A, B {
+class alias Raw/*codeOffset=24, codeLength=29*/ extends Object with A, B {
   synthetic const Raw() : super();
 }
 /// Comment 1.
 /// Comment 2.
-class alias HasDocComment/*codeOffset=59, codeLength=69*/ extends Object with A, B {
+class alias HasDocComment/*codeOffset=55, codeLength=69*/ extends Object with A, B {
   synthetic const HasDocComment() : super();
 }
 @Object()
-class alias HasAnnotation/*codeOffset=130, codeLength=49*/ extends Object with A, B {
+class alias HasAnnotation/*codeOffset=126, codeLength=49*/ extends Object with A, B {
   synthetic const HasAnnotation() : super();
 }
 /// Comment 1.
 /// Comment 2.
 @Object()
-class alias AnnotationThenComment/*codeOffset=181, codeLength=87*/ extends Object with A, B {
+class alias AnnotationThenComment/*codeOffset=177, codeLength=87*/ extends Object with A, B {
   synthetic const AnnotationThenComment() : super();
 }
 /// Comment 1.
 /// Comment 2.
 @Object()
-class alias CommentThenAnnotation/*codeOffset=270, codeLength=87*/ extends Object with A, B {
+class alias CommentThenAnnotation/*codeOffset=266, codeLength=87*/ extends Object with A, B {
   synthetic const CommentThenAnnotation() : super();
 }
 /// Comment 2.
 @Object()
-class alias CommentAroundAnnotation/*codeOffset=374, codeLength=74*/ extends Object with A, B {
+class alias CommentAroundAnnotation/*codeOffset=370, codeLength=74*/ extends Object with A, B {
   synthetic const CommentAroundAnnotation() : super();
 }
 ''',
@@ -2466,13 +2466,13 @@
 
   int withoutInit;
 
-  int multiWithInit = 2, multiWithoutInit, multiWithInit2 = 3; 
+  int multiWithInit = 2, multiWithoutInit, multiWithInit2 = 3;
 }
 ''');
     checkElementText(
         library,
         r'''
-class C/*codeOffset=0, codeLength=116*/ {
+class C/*codeOffset=0, codeLength=115*/ {
   int withInit/*codeOffset=12, codeLength=16*/;
   int withoutInit/*codeOffset=33, codeLength=15*/;
   int multiWithInit/*codeOffset=53, codeLength=21*/;
@@ -2794,7 +2794,7 @@
 
 int withoutInit;
 
-int multiWithInit = 2, multiWithoutInit, multiWithInit2 = 3; 
+int multiWithInit = 2, multiWithoutInit, multiWithInit2 = 3;
 ''');
     checkElementText(
         library,
@@ -14788,7 +14788,7 @@
   test_unit_implicitVariable_getterFirst() async {
     var library = await checkLibrary('''
 int get x => 0;
-void set x(int value) {} 
+void set x(int value) {}
 ''');
     checkElementText(
         library,
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index d70bd51..e59913a9 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -2065,21 +2065,21 @@
 }
 
 abstract class D extends Object with M<num> {}
-  
+
 class E extends D with M<int> {
   int x;
 }
-  
+
 class F extends D with M<int> {
   num x;
 }
 ''', [
       error(CompileTimeErrorCode.INVALID_OVERRIDE, 124, 1),
-      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 186, 1),
-      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 186, 1),
-      error(CompileTimeErrorCode.INVALID_OVERRIDE, 218, 1),
-      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 232, 1),
-      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 232, 1),
+      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 184, 1),
+      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 184, 1),
+      error(CompileTimeErrorCode.INVALID_OVERRIDE, 216, 1),
+      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 228, 1),
+      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 228, 1),
     ]);
   }
 
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index d20ec18..0acae0a 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -1148,7 +1148,7 @@
   new F4(a: [[3]]);
   new F4(a: [["hello"]]);
   new F4(a: [["hello"], [3]]);
-  
+
   new F5([[[3]]]);
 }
 ''', [
diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart
index f6015bd..c4bd9f1 100644
--- a/pkg/dartdev/lib/src/commands/run.dart
+++ b/pkg/dartdev/lib/src/commands/run.dart
@@ -69,6 +69,12 @@
         valueHelp: '[<port>[/<bind-address>]]',
       )
       ..addFlag(
+        'serve-devtools',
+        help: 'Serves an instance of the Dart DevTools debugger and profiler '
+            'via the VM service at <vm-service-uri>/devtools.',
+        defaultsTo: true,
+      )
+      ..addFlag(
         'pause-isolates-on-exit',
         help: 'Pause isolates on exit when '
             'running with --enable-vm-service.',
@@ -186,9 +192,7 @@
     String ddsHost = '';
     String ddsPort = '';
 
-    // TODO(bkonyi): allow for users to choose not to launch DevTools
-    // See https://github.com/dart-lang/sdk/issues/45867.
-    const bool launchDevTools = true;
+    bool launchDevTools = argResults['serve-devtools'];
     bool launchDds = false;
     if (launchDdsArg != null) {
       launchDds = true;
diff --git a/pkg/dartdev/test/commands/run_test.dart b/pkg/dartdev/test/commands/run_test.dart
index cfccec8..4cd3517 100644
--- a/pkg/dartdev/test/commands/run_test.dart
+++ b/pkg/dartdev/test/commands/run_test.dart
@@ -329,7 +329,7 @@
     const devToolsMessagePrefix =
         'The Dart DevTools debugger and profiler is available at: http://127.0.0.1:';
 
-    test('spawn simple', () async {
+    test('dart run simple', () async {
       p = project(mainSrc: "void main() { print('Hello World'); }");
       ProcessResult result = p.runSync([
         'run',
@@ -339,7 +339,7 @@
       expect(result.stdout, contains(devToolsMessagePrefix));
     });
 
-    test('implicit spawn', () async {
+    test('dart simple', () async {
       p = project(mainSrc: "void main() { print('Hello World'); }");
       ProcessResult result = p.runSync([
         '--enable-vm-service',
@@ -348,6 +348,67 @@
       expect(result.stdout, contains(devToolsMessagePrefix));
     });
 
+    test('dart run explicit', () async {
+      p = project(mainSrc: "void main() { print('Hello World'); }");
+      ProcessResult result = p.runSync([
+        'run',
+        '--serve-devtools',
+        '--enable-vm-service',
+        p.relativeFilePath,
+      ]);
+      expect(result.stdout, contains(devToolsMessagePrefix));
+    });
+
+    test('dart explicit', () async {
+      p = project(mainSrc: "void main() { print('Hello World'); }");
+      ProcessResult result = p.runSync([
+        '--serve-devtools',
+        '--enable-vm-service',
+        p.relativeFilePath,
+      ]);
+      expect(result.stdout, contains(devToolsMessagePrefix));
+    });
+
+    test('dart run disabled', () async {
+      p = project(mainSrc: "void main() { print('Hello World'); }");
+      ProcessResult result = p.runSync([
+        'run',
+        '--enable-vm-service',
+        '--no-serve-devtools',
+        p.relativeFilePath,
+      ]);
+      expect(result.stdout, isNot(contains(devToolsMessagePrefix)));
+    });
+
+    test('dart disabled', () async {
+      p = project(mainSrc: "void main() { print('Hello World'); }");
+      ProcessResult result = p.runSync([
+        '--enable-vm-service',
+        '--no-serve-devtools',
+        p.relativeFilePath,
+      ]);
+      expect(result.stdout, isNot(contains(devToolsMessagePrefix)));
+    });
+
+    test('dart run VM service not enabled', () async {
+      p = project(mainSrc: "void main() { print('Hello World'); }");
+      ProcessResult result = p.runSync([
+        'run',
+        '--serve-devtools',
+        p.relativeFilePath,
+      ]);
+      expect(result.stdout, isNot(contains(devToolsMessagePrefix)));
+    });
+
+    test('dart VM service not enabled', () async {
+      p = project(mainSrc: "void main() { print('Hello World'); }");
+      ProcessResult result = p.runSync([
+        '--serve-devtools',
+        p.relativeFilePath,
+      ]);
+      expect(result.stdout, isNot(contains(devToolsMessagePrefix)));
+    });
+
     test(
       'spawn via SIGQUIT',
       () async {
diff --git a/pkg/wasm/README.md b/pkg/wasm/README.md
index 1fcab7e..ecf418d 100644
--- a/pkg/wasm/README.md
+++ b/pkg/wasm/README.md
@@ -1,7 +1,6 @@
-# wasm
+Provides utilities for loading and running WASM modules
 
-This package provides utilities for loading and running WASM modules. It is
-built on top of the [Wasmer](https://github.com/wasmerio/wasmer) runtime.
+Built on top of the [Wasmer](https://github.com/wasmerio/wasmer) runtime.
 
 ## Setup
 
diff --git a/pkg/wasm/bin/setup.dart b/pkg/wasm/bin/setup.dart
index ad36423..868c189 100644
--- a/pkg/wasm/bin/setup.dart
+++ b/pkg/wasm/bin/setup.dart
@@ -27,6 +27,12 @@
     return checkedOutSdkDir;
   }
 
+  final homebrewOutSdkDir = exe.resolve('..');
+  final homebrewIncludeDir = homebrewOutSdkDir.resolve('include');
+  if (Directory(homebrewIncludeDir.path).existsSync()) {
+    return homebrewOutSdkDir;
+  }
+
   // If neither returned above, we return the common case:
   return commonSdkDir;
 }
@@ -52,7 +58,7 @@
   return 'libwasmer.so';
 }
 
-getTargetTriple() async {
+Future<String> getTargetTriple() async {
   final process = await Process.start('rustc', ['--print', 'cfg']);
   process.stderr
       .transform(utf8.decoder)
@@ -69,11 +75,14 @@
   String arch = cfg['target_arch'] ?? 'unknown';
   String vendor = cfg['target_vendor'] ?? 'unknown';
   String os = cfg['target_os'] ?? 'unknown';
-  String env = cfg['target_env'] ?? 'unknown';
-  return '$arch-$vendor-$os-$env';
+  if (os == 'macos') os = 'darwin';
+  String? env = cfg['target_env'];
+  return [arch, vendor, os, env]
+      .where((element) => element != null && element.isNotEmpty)
+      .join('-');
 }
 
-run(String exe, List<String> args) async {
+Future<void> run(String exe, List<String> args) async {
   print('\n$exe ${args.join(' ')}\n');
   final process = await Process.start(exe, args);
   process.stdout
@@ -91,13 +100,13 @@
   }
 }
 
-main(List<String> args) async {
+Future<void> main(List<String> args) async {
   if (args.length > 1) {
     print('Usage: dart setup.dart [target-triple]');
     exit(1);
   }
 
-  final target = args.length >= 1 ? args[0] : await getTargetTriple();
+  final target = args.isNotEmpty ? args[0] : await getTargetTriple();
   final sdkDir = getSdkDir();
   final binDir = Platform.script;
   final outDir = getOutDir(binDir);
@@ -121,12 +130,13 @@
     '--release'
   ]);
 
+  final dartApiDlImplFile =
+      File.fromUri(sdkDir.resolve('include/internal/dart_api_dl_impl.h'));
   // Hack around a bug with dart_api_dl_impl.h include path in dart_api_dl.c.
-  if (!File.fromUri(sdkDir.resolve('include/internal/dart_api_dl_impl.h'))
-      .existsSync()) {
+  if (!dartApiDlImplFile.existsSync()) {
     Directory(outDir.resolve('include/internal/').path)
         .createSync(recursive: true);
-    File.fromUri(sdkDir.resolve('include/runtime/dart_api_dl_impl.h'))
+    await dartApiDlImplFile
         .copy(outDir.resolve('include/internal/dart_api_dl_impl.h').path);
   }
 
diff --git a/pkg/wasm/example/brotli.dart b/pkg/wasm/example/brotli.dart
index e9520e3..d8cea14 100644
--- a/pkg/wasm/example/brotli.dart
+++ b/pkg/wasm/example/brotli.dart
@@ -6,9 +6,9 @@
 // library. Usage:
 // dart brotli.dart input.txt
 
-import 'dart:convert';
 import "dart:io";
 import "dart:typed_data";
+
 import "package:wasm/wasm.dart";
 
 // Brotli compression parameters.
diff --git a/pkg/wasm/lib/src/function.dart b/pkg/wasm/lib/src/function.dart
index 8cff328..bc5e44c 100644
--- a/pkg/wasm/lib/src/function.dart
+++ b/pkg/wasm/lib/src/function.dart
@@ -2,10 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:ffi';
+
+import 'package:ffi/ffi.dart';
+
 import 'runtime.dart';
 import 'wasmer_api.dart';
-import 'dart:ffi';
-import 'package:ffi/ffi.dart';
 
 /// WasmFunction is a callable function from a WasmInstance.
 class WasmFunction {
@@ -19,7 +21,7 @@
   WasmFunction(this._name, this._func, this._argTypes, this._returnType) {
     _args.ref.length = _argTypes.length;
     _args.ref.data =
-        _argTypes.length == 0 ? nullptr : calloc<WasmerVal>(_argTypes.length);
+        _argTypes.isEmpty ? nullptr : calloc<WasmerVal>(_argTypes.length);
     _results.ref.length = _returnType == WasmerValKindVoid ? 0 : 1;
     _results.ref.data =
         _returnType == WasmerValKindVoid ? nullptr : calloc<WasmerVal>();
diff --git a/pkg/wasm/lib/src/module.dart b/pkg/wasm/lib/src/module.dart
index 305d239..5687b2e 100644
--- a/pkg/wasm/lib/src/module.dart
+++ b/pkg/wasm/lib/src/module.dart
@@ -2,13 +2,15 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'runtime.dart';
-import 'function.dart';
-import 'wasmer_api.dart';
-import 'dart:typed_data';
 import 'dart:ffi';
+import 'dart:typed_data';
+
 import 'package:ffi/ffi.dart';
 
+import 'function.dart';
+import 'runtime.dart';
+import 'wasmer_api.dart';
+
 /// WasmModule is a compiled module that can be instantiated.
 class WasmModule {
   late Pointer<WasmerStore> _store;
@@ -165,7 +167,6 @@
       throw Exception("Import is not a function: $imp");
     }
 
-    var argTypes = runtime.getArgTypes(imp.funcType);
     var returnType = runtime.getReturnType(imp.funcType);
     var wasmFnImport = calloc<_WasmFnImport>();
     wasmFnImport.ref.returnType = returnType;
@@ -241,7 +242,7 @@
         var mem = runtime.externToMemory(e);
         _exportedMemory = mem;
         if (_wasiEnv != nullptr) {
-          runtime.wasiEnvSetMemory(_wasiEnv as Pointer<WasmerWasiEnv>, mem);
+          runtime.wasiEnvSetMemory(_wasiEnv, mem);
         }
       }
     }
diff --git a/pkg/wasm/lib/src/runtime.dart b/pkg/wasm/lib/src/runtime.dart
index b8defab..1db3ef4 100644
--- a/pkg/wasm/lib/src/runtime.dart
+++ b/pkg/wasm/lib/src/runtime.dart
@@ -699,7 +699,7 @@
   Function _reader;
   Pointer<Uint8> _buf = calloc<Uint8>(_bufferLength);
   int _length = 0;
-  _WasiStreamIterator(this._env, this._reader) {}
+  _WasiStreamIterator(this._env, this._reader);
 
   bool moveNext() {
     _length = _reader(_env, _buf, _bufferLength);
@@ -712,7 +712,7 @@
 class _WasiStreamIterable extends Iterable<List<int>> {
   Pointer<WasmerWasiEnv> _env;
   Function _reader;
-  _WasiStreamIterable(this._env, this._reader) {}
+  _WasiStreamIterable(this._env, this._reader);
   @override
   Iterator<List<int>> get iterator => _WasiStreamIterator(_env, _reader);
 }
diff --git a/pkg/wasm/lib/src/tools/runtime_template.dart b/pkg/wasm/lib/src/tools/runtime_template.dart
index 0394c10..2798b90 100644
--- a/pkg/wasm/lib/src/tools/runtime_template.dart
+++ b/pkg/wasm/lib/src/tools/runtime_template.dart
@@ -390,7 +390,7 @@
   Function _reader;
   Pointer<Uint8> _buf = calloc<Uint8>(_bufferLength);
   int _length = 0;
-  _WasiStreamIterator(this._env, this._reader) {}
+  _WasiStreamIterator(this._env, this._reader);
 
   bool moveNext() {
     _length = _reader(_env, _buf, _bufferLength);
@@ -403,7 +403,7 @@
 class _WasiStreamIterable extends Iterable<List<int>> {
   Pointer<WasmerWasiEnv> _env;
   Function _reader;
-  _WasiStreamIterable(this._env, this._reader) {}
+  _WasiStreamIterable(this._env, this._reader);
   @override
   Iterator<List<int>> get iterator => _WasiStreamIterator(_env, _reader);
 }
diff --git a/pkg/wasm/pubspec.yaml b/pkg/wasm/pubspec.yaml
index ef31927..9cd60c7 100644
--- a/pkg/wasm/pubspec.yaml
+++ b/pkg/wasm/pubspec.yaml
@@ -1,7 +1,6 @@
 name: wasm
 version: 0.1.0
-description: Load and run wasm bytecode.
-author: Dart Team <misc@dartlang.org>
+description: Utilities for loading and running WASM modules from Dart code
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/wasm
 
 environment:
diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
index 55fef46..157b70f 100644
--- a/runtime/bin/main_options.cc
+++ b/runtime/bin/main_options.cc
@@ -155,6 +155,7 @@
 "  set of options which are often useful for debugging under Observatory.\n"
 "  These options are currently:\n"
 "      --enable-vm-service[=<port>[/<bind-address>]]\n"
+"      --serve-devtools\n"
 "      --pause-isolates-on-exit\n"
 "      --pause-isolates-on-unhandled-exceptions\n"
 "      --warn-on-pause-with-no-debugger\n"
@@ -191,6 +192,7 @@
 "  set of options which are often useful for debugging under Observatory.\n"
 "  These options are currently:\n"
 "      --enable-vm-service[=<port>[/<bind-address>]]\n"
+"      --serve-devtools\n"
 "      --pause-isolates-on-exit\n"
 "      --pause-isolates-on-unhandled-exceptions\n"
 "      --warn-on-pause-with-no-debugger\n"
@@ -416,6 +418,7 @@
 
   bool enable_dartdev_analytics = false;
   bool disable_dartdev_analytics = false;
+  bool serve_devtools = true;
 
   // Parse out the vm options.
   while (i < argc) {
@@ -444,6 +447,12 @@
         // It is irelevant for the vm.
         dart_options->AddArgument("--no-analytics");
         skipVmOption = true;
+      } else if (IsOption(argv[i], "serve-devtools")) {
+        serve_devtools = true;
+        skipVmOption = true;
+      } else if (IsOption(argv[i], "no-serve-devtools")) {
+        serve_devtools = false;
+        skipVmOption = true;
       }
       if (!skipVmOption) {
         temp_vm_options.AddArgument(argv[i]);
@@ -571,6 +580,16 @@
       // run command. If 'run' is provided, it will be the first argument
       // processed in this loop.
       dart_options->AddArgument("run");
+
+      // Ensure we can enable / disable DevTools when invoking 'dart run'
+      // implicitly.
+      if (enable_vm_service_) {
+        if (serve_devtools) {
+          dart_options->AddArgument("--serve-devtools");
+        } else {
+          dart_options->AddArgument("--no-serve-devtools");
+        }
+      }
     } else {
       dart_options->AddArgument(argv[i]);
       i++;
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index 94e834f..cf13c43 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -985,9 +985,12 @@
 
   // Flip the two semi-spaces so that to_ is always the space for allocating
   // objects.
-  SemiSpace* from = to_;
-
-  to_ = new SemiSpace(NewSizeInWords(from->max_capacity_in_words()));
+  SemiSpace* from;
+  {
+    MutexLocker ml(&space_lock_);
+    from = to_;
+    to_ = new SemiSpace(NewSizeInWords(from->max_capacity_in_words()));
+  }
   UpdateMaxHeapCapacity();
 
   return from;
@@ -1740,9 +1743,12 @@
 
   // Swap from-space and to-space. The abandoned to-space will be deleted in
   // the epilogue.
-  SemiSpace* temp = to_;
-  to_ = *from;
-  *from = temp;
+  {
+    MutexLocker ml(&space_lock_);
+    SemiSpace* temp = to_;
+    to_ = *from;
+    *from = temp;
+  }
 
   // Release any remaining part of the promotion worklist that wasn't completed.
   promotion_stack_.Reset();
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 47d868c..422d7b4 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -18151,7 +18151,7 @@
   } else {
     ASSERT(instance_class_id_or_signature.IsFunctionType());
     buffer->Printf(
-        "%sfunction: %s", separator,
+        "%ssignature: %s", separator,
         FunctionType::Cast(instance_class_id_or_signature).ToCString());
   }
   if (!destination_type.IsNull()) {
@@ -19237,6 +19237,7 @@
         instantiated_other = TypeRef::Cast(instantiated_other).type();
       }
       if (instantiated_other.IsTopTypeForSubtyping() ||
+          instantiated_other.IsObjectType() ||
           instantiated_other.IsDartFunctionType()) {
         return true;
       }
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index e1c900d..41d3e40 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -139,6 +139,10 @@
     "../utils/dds:dds",
   ],
   [
+    "frontend_server",
+    "../utils/kernel-service:frontend_server",
+  ],
+  [
     "pub",
     "../utils/pub",
   ],
@@ -169,10 +173,6 @@
                           "kernel_worker",
                           "../utils/bazel:kernel_worker",
                         ],
-                        [
-                          "frontend_server",
-                          "../utils/kernel-service:frontend_server",
-                        ],
                       ]
 
 # Libraries that go under lib/
diff --git a/tests/language/constructor/reference_test.dart b/tests/language/constructor/reference_test.dart
index f57a26f..d781ab1 100644
--- a/tests/language/constructor/reference_test.dart
+++ b/tests/language/constructor/reference_test.dart
@@ -92,8 +92,6 @@
   Foo<int>();
   Foo<int>.bar();
   Foo<int>.bar.baz();
-//^^^
-// [analyzer] COMPILE_TIME_ERROR.INVOCATION_OF_NON_FUNCTION_EXPRESSION
   // ^^^^^
   // [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
   // [cfe] This requires the 'constructor-tearoffs' language feature to be enabled.
diff --git a/tests/language/regress/regress46165_test.dart b/tests/language/regress/regress46165_test.dart
new file mode 100644
index 0000000..2aed9e0
--- /dev/null
+++ b/tests/language/regress/regress46165_test.dart
@@ -0,0 +1,10 @@
+// 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.
+
+void main() {
+  final l = <Object>[];
+  l.add((String x, StringBuffer y) {
+    print(x);
+  });
+}
diff --git a/tests/language_2/constructor/reference_test.dart b/tests/language_2/constructor/reference_test.dart
index 73abdb9..ee1aa67 100644
--- a/tests/language_2/constructor/reference_test.dart
+++ b/tests/language_2/constructor/reference_test.dart
@@ -94,8 +94,6 @@
   Foo<int>();
   Foo<int>.bar();
   Foo<int>.bar.baz();
-//^^^
-// [analyzer] COMPILE_TIME_ERROR.INVOCATION_OF_NON_FUNCTION_EXPRESSION
   // ^^^^^
   // [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
   // [cfe] This requires the 'constructor-tearoffs' language feature to be enabled.
diff --git a/tests/language_2/regress/regress46165_test.dart b/tests/language_2/regress/regress46165_test.dart
new file mode 100644
index 0000000..2aed9e0
--- /dev/null
+++ b/tests/language_2/regress/regress46165_test.dart
@@ -0,0 +1,10 @@
+// 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.
+
+void main() {
+  final l = <Object>[];
+  l.add((String x, StringBuffer y) {
+    print(x);
+  });
+}
diff --git a/tools/VERSION b/tools/VERSION
index dcce38e..432be1f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 171
+PRERELEASE 172
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/flutter/analyze_flutter_plugins.sh b/tools/bots/flutter/analyze_flutter_plugins.sh
new file mode 100755
index 0000000..9696c74
--- /dev/null
+++ b/tools/bots/flutter/analyze_flutter_plugins.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+
+# 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.
+
+# Analyze Dart code in the flutter/plugins repo.
+
+set -e
+
+checkout=$(pwd)
+export PATH=$checkout/out/ReleaseX64/dart-sdk/bin:$PATH
+dart=$checkout/out/ReleaseX64/dart-sdk/bin/dart
+pub=$checkout/out/ReleaseX64/dart-sdk/bin/pub
+sdk=$checkout/out/ReleaseX64/dart-sdk
+tmpdir=$(mktemp -d)
+
+cleanup() {
+  rm -rf "$tmpdir"
+}
+
+trap cleanup EXIT HUP INT QUIT TERM PIPE
+cd "$tmpdir"
+
+# install flutter
+git clone --single-branch -vv https://github.com/flutter/flutter
+export PATH="$PATH":"$tmpdir/flutter/bin"
+flutter --version
+
+# get the flutter/plugins repo
+git clone --single-branch -vv https://github.com/flutter/plugins
+cd plugins
+
+# validate the tool's source
+(cd script/tool; dart pub get)
+(cd script/tool; dart analyze --fatal-infos)
+
+# Invoke the repo's analysis script.
+./script/tool_runner.sh analyze --analysis-sdk $sdk
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 67fb0a0..1d078c0 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -3624,7 +3624,11 @@
         {
           "name": "analyze flutter/flutter",
           "script": "tools/bots/flutter/analyze_flutter_flutter.sh"
-        }
+        },
+        {
+          "name": "analyze flutter/plugins",
+          "script": "tools/bots/flutter/analyze_flutter_plugins.sh"
+        }        
       ]
     },
     {