Version 2.17.0-20.0.dev

Merge commit '650b9627b7a7c05d9d2a489a23b2eae98c9aef95' into 'dev'
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 4c8b529..1350c46 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -410,11 +410,11 @@
   ///
   /// So, we can start working in parallel on adding services and improving
   /// projects/contexts support.
-  void setAnalysisRoots(String requestId, List<String> includedPaths,
-      List<String> excludedPaths) {
+  Future<void> setAnalysisRoots(String requestId, List<String> includedPaths,
+      List<String> excludedPaths) async {
     notificationManager.setAnalysisRoots(includedPaths, excludedPaths);
     try {
-      contextManager.setRoots(includedPaths, excludedPaths);
+      await contextManager.setRoots(includedPaths, excludedPaths);
     } on UnimplementedError catch (e) {
       throw RequestFailure(Response.unsupportedFeature(
           requestId, e.message ?? 'Unsupported feature.'));
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index b94ee3f..b60182d 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -459,8 +459,8 @@
 
   /// Read all files, resolve all URIs, and perform required analysis in
   /// all current analysis drivers.
-  void reanalyze() {
-    contextManager.refresh();
+  Future<void> reanalyze() async {
+    await contextManager.refresh();
   }
 
   ResolvedForCompletionResultImpl? resolveForCompletion({
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index ceb6b14..6dc9295 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -5,6 +5,7 @@
 import 'dart:async';
 import 'dart:collection';
 
+import 'package:analysis_server/src/lsp/handlers/handlers.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_parser.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/file_system/file_system.dart';
@@ -81,11 +82,11 @@
 
   /// Rebuild the set of contexts from scratch based on the data last sent to
   /// [setRoots].
-  void refresh();
+  Future<void> refresh();
 
   /// Change the set of paths which should be used as starting points to
   /// determine the context directories.
-  void setRoots(List<String> includedPaths, List<String> excludedPaths);
+  Future<void> setRoots(List<String> includedPaths, List<String> excludedPaths);
 }
 
 /// Callback interface used by [ContextManager] to (a) request that contexts be
@@ -182,10 +183,6 @@
   final Map<Folder, AnalysisDriver> driverMap =
       HashMap<Folder, AnalysisDriver>();
 
-  /// The timer that is started after creating analysis contexts, to check
-  /// for in-between changes to configuration files.
-  Timer? _collectionConsistencyCheckTimer;
-
   /// Stream subscription we are using to watch each analysis root directory for
   /// changes.
   final Map<Folder, StreamSubscription<WatchEvent>> changeSubscriptions =
@@ -211,6 +208,12 @@
   /// clean up when we destroy a context.
   final bazelWatchedPathsPerFolder = <Folder, _BazelWatchedFiles>{};
 
+  /// Information about the current/last queued context rebuild.
+  ///
+  /// This is used when a new build is requested to cancel any in-progress
+  /// rebuild and wait for it to terminate before starting the next.
+  final _CancellingTaskQueue currentContextRebuild = _CancellingTaskQueue();
+
   ContextManagerImpl(
       this.resourceProvider,
       this.sdkManager,
@@ -255,13 +258,18 @@
     );
   }
 
+  /// Starts (an asynchronous) rebuild of analysis contexts.
   @override
-  void refresh() {
-    _createAnalysisContexts();
+  Future<void> refresh() async {
+    await _createAnalysisContexts();
   }
 
+  /// Updates the analysis roots and waits for the contexts to rebuild.
+  ///
+  /// If the roots have not changed, exits early without performing any work.
   @override
-  void setRoots(List<String> includedPaths, List<String> excludedPaths) {
+  Future<void> setRoots(
+      List<String> includedPaths, List<String> excludedPaths) async {
     if (_rootsAreUnchanged(includedPaths, excludedPaths)) {
       return;
     }
@@ -269,7 +277,7 @@
     this.includedPaths = includedPaths;
     this.excludedPaths = excludedPaths;
 
-    _createAnalysisContexts();
+    await _createAnalysisContexts();
   }
 
   /// Use the given analysis [driver] to analyze the content of the analysis
@@ -412,65 +420,156 @@
     }
   }
 
-  void _createAnalysisContexts() {
-    _destroyAnalysisContexts();
-    _fileContentCache.invalidateAll();
+  /// Recreates all analysis contexts.
+  ///
+  /// If an existing rebuild is in progress, it will be cancelled and this
+  /// rebuild will occur only once it has exited.
+  ///
+  /// Returns a [Future] that completes once the requested rebuild completes.
+  Future<void> _createAnalysisContexts() async {
+    /// A helper that performs a context rebuild while monitoring the included
+    /// paths for changes until the contexts file watchers are ready.
+    ///
+    /// If changes are detected during the rebuild, the rebuild will be
+    /// restarted.
+    Future<void> performContextRebuildGuarded(
+      CancellationToken cancellationToken,
+    ) async {
+      /// A helper that performs the context rebuild and waits for all watchers
+      /// to be fully initialized.
+      Future<void> performContextRebuild() async {
+        _destroyAnalysisContexts();
+        _fileContentCache.invalidateAll();
 
-    var collection = _collection = AnalysisContextCollectionImpl(
-      includedPaths: includedPaths,
-      excludedPaths: excludedPaths,
-      byteStore: _byteStore,
-      drainStreams: false,
-      enableIndex: true,
-      performanceLog: _performanceLog,
-      resourceProvider: resourceProvider,
-      scheduler: _scheduler,
-      sdkPath: sdkManager.defaultSdkDirectory,
-      packagesFile: packagesFile,
-      fileContentCache: _fileContentCache,
-    );
+        var watchers = <ResourceWatcher>[];
+        var collection = _collection = AnalysisContextCollectionImpl(
+          includedPaths: includedPaths,
+          excludedPaths: excludedPaths,
+          byteStore: _byteStore,
+          drainStreams: false,
+          enableIndex: true,
+          performanceLog: _performanceLog,
+          resourceProvider: resourceProvider,
+          scheduler: _scheduler,
+          sdkPath: sdkManager.defaultSdkDirectory,
+          packagesFile: packagesFile,
+          fileContentCache: _fileContentCache,
+        );
 
-    for (var analysisContext in collection.contexts) {
-      var driver = analysisContext.driver;
+        for (var analysisContext in collection.contexts) {
+          var driver = analysisContext.driver;
 
-      callbacks.listenAnalysisDriver(driver);
+          callbacks.listenAnalysisDriver(driver);
 
-      var rootFolder = analysisContext.contextRoot.root;
-      driverMap[rootFolder] = driver;
+          var rootFolder = analysisContext.contextRoot.root;
+          driverMap[rootFolder] = driver;
 
-      changeSubscriptions[rootFolder] = rootFolder.changes
-          .listen(_handleWatchEvent, onError: _handleWatchInterruption);
+          var watcher = rootFolder.watch();
+          watchers.add(watcher);
+          changeSubscriptions[rootFolder] = watcher.changes
+              .listen(_handleWatchEvent, onError: _handleWatchInterruption);
 
-      _watchBazelFilesIfNeeded(rootFolder, driver);
+          _watchBazelFilesIfNeeded(rootFolder, driver);
 
-      for (var file in analysisContext.contextRoot.analyzedFiles()) {
-        if (file_paths.isAndroidManifestXml(pathContext, file)) {
-          _analyzeAndroidManifestXml(driver, file);
-        } else if (file_paths.isDart(pathContext, file)) {
-          driver.addFile(file);
+          for (var file in analysisContext.contextRoot.analyzedFiles()) {
+            if (file_paths.isAndroidManifestXml(pathContext, file)) {
+              _analyzeAndroidManifestXml(driver, file);
+            } else if (file_paths.isDart(pathContext, file)) {
+              driver.addFile(file);
+            }
+          }
+
+          var optionsFile = analysisContext.contextRoot.optionsFile;
+          if (optionsFile != null) {
+            _analyzeAnalysisOptionsYaml(driver, optionsFile.path);
+          }
+
+          var fixDataYamlFile = rootFolder
+              .getChildAssumingFolder('lib')
+              .getChildAssumingFile(file_paths.fixDataYaml);
+          if (fixDataYamlFile.exists) {
+            _analyzeFixDataYaml(driver, fixDataYamlFile.path);
+          }
+
+          var pubspecFile =
+              rootFolder.getChildAssumingFile(file_paths.pubspecYaml);
+          if (pubspecFile.exists) {
+            _analyzePubspecYaml(driver, pubspecFile.path);
+          }
         }
+
+        // Finally, wait for the new contexts watchers to all become ready so we
+        // can ensure they will not lose any future events before we continue.
+        await Future.wait(watchers.map((watcher) => watcher.ready));
       }
 
-      var optionsFile = analysisContext.contextRoot.optionsFile;
-      if (optionsFile != null) {
-        _analyzeAnalysisOptionsYaml(driver, optionsFile.path);
+      /// A helper that returns whether a change to the file at [path] should
+      /// restart any in-progress rebuild.
+      bool shouldRestartBuild(String path) {
+        return file_paths.isDart(pathContext, path) ||
+            file_paths.isAnalysisOptionsYaml(pathContext, path) ||
+            file_paths.isPubspecYaml(pathContext, path) ||
+            file_paths.isDotPackages(pathContext, path) ||
+            file_paths.isPackageConfigJson(pathContext, path);
       }
 
-      var fixDataYamlFile = rootFolder
-          .getChildAssumingFolder('lib')
-          .getChildAssumingFile(file_paths.fixDataYaml);
-      if (fixDataYamlFile.exists) {
-        _analyzeFixDataYaml(driver, fixDataYamlFile.path);
+      if (cancellationToken.isCancellationRequested) {
+        return;
       }
 
-      var pubspecFile = rootFolder.getChildAssumingFile(file_paths.pubspecYaml);
-      if (pubspecFile.exists) {
-        _analyzePubspecYaml(driver, pubspecFile.path);
+      // Create temporary watchers before we start the context build so we can
+      // tell if any files were modified while waiting for the "real" watchers to
+      // become ready and start the process again.
+      final temporaryWatchers = includedPaths
+          .map((path) => resourceProvider.getResource(path))
+          .map((resource) => resource.watch())
+          .toList();
+
+      // If any watcher picks up an important change while we're running the
+      // rest of this method, we will need to start again.
+      var needsBuild = true;
+      final temporaryWatcherSubscriptions = temporaryWatchers
+          .map((watcher) => watcher.changes.listen((event) {
+                if (shouldRestartBuild(event.path)) {
+                  needsBuild = true;
+                }
+              }))
+          .toList();
+
+      try {
+        // Ensure all watchers are ready before we begin any rebuild.
+        await Future.wait(temporaryWatchers.map((watcher) => watcher.ready));
+
+        // Max number of attempts to rebuild if changes.
+        var remainingBuilds = 5;
+        while (needsBuild && remainingBuilds-- > 0) {
+          // Reset the flag, as we'll only need to rebuild if a temporary
+          // watcher fires after this point.
+          needsBuild = false;
+
+          if (cancellationToken.isCancellationRequested) {
+            return;
+          }
+
+          // Attempt a context rebuild. This call will wait for all required
+          // watchers to be ready before returning.
+          await performContextRebuild();
+        }
+      } finally {
+        // Cancel the temporary watcher subscriptions.
+        await Future.wait(
+          temporaryWatcherSubscriptions.map((sub) => sub.cancel()),
+        );
       }
+
+      if (cancellationToken.isCancellationRequested) {
+        return;
+      }
+
+      callbacks.afterContextsCreated();
     }
 
-    callbacks.afterContextsCreated();
-    _scheduleCollectionConsistencyCheck(collection);
+    return currentContextRebuild.queue(performContextRebuildGuarded);
   }
 
   /// Clean up and destroy the context associated with the given folder.
@@ -492,7 +591,6 @@
   void _destroyAnalysisContexts() {
     var collection = _collection;
     if (collection != null) {
-      _collectionConsistencyCheckTimer?.cancel();
       for (var analysisContext in collection.contexts) {
         _destroyAnalysisContext(analysisContext);
       }
@@ -577,15 +675,16 @@
         file_paths.isPackageConfigJson(pathContext, path) ||
         isPubspec ||
         false) {
-      _createAnalysisContexts();
-
-      if (isPubspec) {
-        if (type == ChangeType.REMOVE) {
-          callbacks.pubspecRemoved(path);
-        } else {
-          callbacks.pubspecChanged(path);
+      _createAnalysisContexts().then((_) {
+        if (isPubspec) {
+          if (type == ChangeType.REMOVE) {
+            callbacks.pubspecRemoved(path);
+          } else {
+            callbacks.pubspecChanged(path);
+          }
         }
-      }
+      });
+
       return;
     }
 
@@ -652,28 +751,6 @@
         existingExcludedSet.containsAll(excludedPaths);
   }
 
-  /// We create analysis contexts, and then start watching the file system
-  /// for modifications to Dart files, and to configuration files, e.g.
-  /// `pubspec.yaml` file Pub workspaces.
-  ///
-  /// So, it is possible that one of these files will be changed between the
-  /// moment when we read it, and the moment when we started watching for
-  /// changes. Using `package:watcher` before creating analysis contexts
-  /// was still not reliable enough.
-  ///
-  /// To work around this we check after a short timeout, and hope that
-  /// any subsequent changes will be noticed by `package:watcher`.
-  void _scheduleCollectionConsistencyCheck(
-    AnalysisContextCollectionImpl collection,
-  ) {
-    _collectionConsistencyCheckTimer = Timer(Duration(seconds: 1), () {
-      _collectionConsistencyCheckTimer = null;
-      if (!collection.areWorkspacesConsistent) {
-        _createAnalysisContexts();
-      }
-    });
-  }
-
   /// Starts watching for the `bazel-bin` and `blaze-bin` symlinks.
   ///
   /// This is important since these symlinks might not be present when the
@@ -755,3 +832,50 @@
   final paths = <String>{};
   _BazelWatchedFiles(this.workspace);
 }
+
+/// Handles a task queue of tasks that cannot run concurrently.
+///
+/// Queueing a new task will signal for any in-progress task to cancel and
+/// wait for it to complete before starting the new task.
+class _CancellingTaskQueue {
+  /// A cancellation token for current/last queued task.
+  ///
+  /// This token is replaced atomically with [_complete] and
+  /// together they allow cancelling a task and chaining a new task on
+  /// to the end.
+  CancelableToken? _cancellationToken;
+
+  /// A [Future] that completes when the current/last queued task finishes.
+  ///
+  /// This future is replaced atomically with [_cancellationToken] and together
+  /// they allow cancelling a task and chaining a new task on to the end.
+  Future<void> _complete = Future.value();
+
+  /// Requests that [performTask] is called after first cancelling any
+  /// in-progress task and waiting for it to complete.
+  ///
+  /// Returns a future that completes once the new task has completed.
+  Future<void> queue(
+    Future<void> Function(CancellationToken cancellationToken) performTask,
+  ) {
+    // Signal for any in-progress task to cancel.
+    _cancellationToken?.cancel();
+
+    // Chain the new task onto the end of any existing one, so the new
+    // task never starts until the previous (cancelled) one finishes (which
+    // may be by aborting early because of the cancellation signal).
+    final token = _cancellationToken = CancelableToken();
+    _complete = _complete
+        .then((_) => performTask(token))
+        .then((_) => _clearTokenIfCurrent(token));
+
+    return _complete;
+  }
+
+  /// Clears the current cancellation token if it is [token].
+  void _clearTokenIfCurrent(CancelableToken token) {
+    if (token == _cancellationToken) {
+      _cancellationToken = null;
+    }
+  }
+}
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index d079a6b..af16242 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -279,9 +279,11 @@
         getSignature(request);
         return Response.DELAYED_RESPONSE;
       } else if (requestName == ANALYSIS_REQUEST_REANALYZE) {
-        return reanalyze(request);
+        reanalyze(request);
+        return Response.DELAYED_RESPONSE;
       } else if (requestName == ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS) {
-        return setAnalysisRoots(request);
+        setAnalysisRoots(request);
+        return Response.DELAYED_RESPONSE;
       } else if (requestName == ANALYSIS_REQUEST_SET_GENERAL_SUBSCRIPTIONS) {
         return setGeneralSubscriptions(request);
       } else if (requestName == ANALYSIS_REQUEST_SET_PRIORITY_FILES) {
@@ -300,10 +302,10 @@
   }
 
   /// Implement the 'analysis.reanalyze' request.
-  Response reanalyze(Request request) {
+  void reanalyze(Request request) async {
     server.options.analytics?.sendEvent('analysis', 'reanalyze');
 
-    server.reanalyze();
+    await server.reanalyze();
 
     //
     // Restart all of the plugins. This is an async operation that will happen
@@ -313,11 +315,11 @@
     //
     // Send the response.
     //
-    return AnalysisReanalyzeResult().toResponse(request.id);
+    server.sendResponse(AnalysisReanalyzeResult().toResponse(request.id));
   }
 
   /// Implement the 'analysis.setAnalysisRoots' request.
-  Response setAnalysisRoots(Request request) {
+  void setAnalysisRoots(Request request) async {
     var params = AnalysisSetAnalysisRootsParams.fromRequest(request);
     var includedPathList = params.included;
     var excludedPathList = params.excluded;
@@ -328,12 +330,14 @@
     // validate
     for (var path in includedPathList) {
       if (!server.isValidFilePath(path)) {
-        return Response.invalidFilePathFormat(request, path);
+        server.sendResponse(Response.invalidFilePathFormat(request, path));
+        return;
       }
     }
     for (var path in excludedPathList) {
       if (!server.isValidFilePath(path)) {
-        return Response.invalidFilePathFormat(request, path);
+        server.sendResponse(Response.invalidFilePathFormat(request, path));
+        return;
       }
     }
 
@@ -343,9 +347,11 @@
       detachableFileSystemManager
           .setAnalysisRoots(request.id, includedPathList, excludedPathList, {});
     } else {
-      server.setAnalysisRoots(request.id, includedPathList, excludedPathList);
+      await server.setAnalysisRoots(
+          request.id, includedPathList, excludedPathList);
     }
-    return AnalysisSetAnalysisRootsResult().toResponse(request.id);
+    return server
+        .sendResponse(AnalysisSetAnalysisRootsResult().toResponse(request.id));
   }
 
   /// Implement the 'analysis.setGeneralSubscriptions' request.
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
index 003917f..8e5f7c6 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
@@ -70,8 +70,8 @@
   FutureOr<ErrorOr<Null>> handle(
       DidCloseTextDocumentParams params, CancellationToken token) {
     final path = pathOfDoc(params.textDocument);
-    return path.mapResult((path) {
-      server.removePriorityFile(path);
+    return path.mapResult((path) async {
+      await server.removePriorityFile(path);
       server.documentVersions.remove(path);
       server.onOverlayDestroyed(path);
 
@@ -96,7 +96,7 @@
       DidOpenTextDocumentParams params, CancellationToken token) {
     final doc = params.textDocument;
     final path = pathOfDocItem(doc);
-    return path.mapResult((path) {
+    return path.mapResult((path) async {
       // We don't get a OptionalVersionedTextDocumentIdentifier with a didOpen but we
       // do get the necessary info to create one.
       server.documentVersions[path] = VersionedTextDocumentIdentifier(
@@ -109,7 +109,7 @@
       // analyzed. Add it to driver to which it should have been added.
       server.contextManager.getDriverFor(path)?.addFile(path);
 
-      server.addPriorityFile(path);
+      await server.addPriorityFile(path);
 
       return success(null);
     });
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 e4e8d17..d0300bb 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -186,7 +186,7 @@
   RefactoringWorkspace get refactoringWorkspace => _refactoringWorkspace ??=
       RefactoringWorkspace(driverMap.values, searchEngine);
 
-  void addPriorityFile(String filePath) {
+  Future<void> addPriorityFile(String filePath) async {
     // When pubspecs are opened, trigger pre-loading of pub package names and
     // versions.
     if (file_paths.isPubspecYaml(resourceProvider.pathContext, filePath)) {
@@ -197,7 +197,7 @@
     assert(didAdd);
     if (didAdd) {
       _updateDriversAndPluginsPriorityFiles();
-      _refreshAnalysisRoots();
+      await _refreshAnalysisRoots();
     }
   }
 
@@ -251,7 +251,7 @@
         clientConfiguration.replace(newGlobalConfig, workspaceFolderConfig);
 
         if (clientConfiguration.affectsAnalysisRoots(oldGlobalConfig)) {
-          _refreshAnalysisRoots();
+          await _refreshAnalysisRoots();
         }
       }
     }
@@ -497,12 +497,12 @@
     sendNotification(message);
   }
 
-  void removePriorityFile(String path) {
+  Future<void> removePriorityFile(String path) async {
     final didRemove = priorityFiles.remove(path);
     assert(didRemove);
     if (didRemove) {
       _updateDriversAndPluginsPriorityFiles();
-      _refreshAnalysisRoots();
+      await _refreshAnalysisRoots();
     }
   }
 
@@ -680,7 +680,7 @@
 
     await fetchClientConfigurationAndPerformDynamicRegistration();
 
-    _refreshAnalysisRoots();
+    await _refreshAnalysisRoots();
   }
 
   void _afterOverlayChanged(String path, plugin.HasToJson changeForPlugins) {
@@ -725,7 +725,7 @@
     capabilitiesComputer.performDynamicRegistration();
   }
 
-  void _refreshAnalysisRoots() {
+  Future<void> _refreshAnalysisRoots() async {
     // When there are open folders, they are always the roots. If there are no
     // open workspace folders, then we use the open (priority) files to compute
     // roots.
@@ -747,7 +747,8 @@
 
     notificationManager.setAnalysisRoots(
         includedPaths.toList(), excludedPaths.toList());
-    contextManager.setRoots(includedPaths.toList(), excludedPaths.toList());
+    await contextManager.setRoots(
+        includedPaths.toList(), excludedPaths.toList());
   }
 
   void _updateDriversAndPluginsPriorityFiles() {
diff --git a/pkg/analysis_server/test/analysis/get_errors_test.dart b/pkg/analysis_server/test/analysis/get_errors_test.dart
index fe232a6..baca9b0 100644
--- a/pkg/analysis_server/test/analysis/get_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/get_errors_test.dart
@@ -23,12 +23,12 @@
   static const String requestId = 'test-getError';
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
     server.handlers = [
       AnalysisDomainHandler(server),
     ];
-    createProject();
+    await createProject();
   }
 
   Future<void> test_afterAnalysisComplete() async {
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index eef7d09..980ec6e 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -29,7 +29,7 @@
       content: '// generated',
     );
 
-    createProject();
+    await createProject();
 
     addTestFile('''
 class A {}
@@ -62,9 +62,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
   }
 
   Future<void> test_class_declaration() async {
diff --git a/pkg/analysis_server/test/analysis/get_navigation_test.dart b/pkg/analysis_server/test/analysis/get_navigation_test.dart
index de8f51e..1f81f60 100644
--- a/pkg/analysis_server/test/analysis/get_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/get_navigation_test.dart
@@ -23,12 +23,12 @@
   static const String requestId = 'test-getNavigation';
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
     server.handlers = [
       AnalysisDomainHandler(server),
     ];
-    createProject();
+    await createProject();
   }
 
   Future<void> test_beforeAnalysisComplete() async {
diff --git a/pkg/analysis_server/test/analysis/get_signature_test.dart b/pkg/analysis_server/test/analysis/get_signature_test.dart
index 37c6996..d213962 100644
--- a/pkg/analysis_server/test/analysis/get_signature_test.dart
+++ b/pkg/analysis_server/test/analysis/get_signature_test.dart
@@ -41,9 +41,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
   }
 
   Future<void> test_constructor() async {
diff --git a/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart b/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
index 32081a6..6116340 100644
--- a/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
@@ -51,10 +51,8 @@
     }
   }
 
-  void setAnalysisRoot() {
-    var request =
-        AnalysisSetAnalysisRootsParams([projectPath], []).toRequest('0');
-    handleSuccessfulRequest(request);
+  Future<void> setAnalysisRoot() async {
+    await setRoots(included: [projectPath], excluded: []);
   }
 
   @override
@@ -84,7 +82,7 @@
 }
 ''');
 
-    setAnalysisRoot();
+    await setAnalysisRoot();
 
     await waitForTasksFinished();
 
@@ -111,7 +109,7 @@
 }
 ''');
 
-    setAnalysisRoot();
+    await setAnalysisRoot();
 
     await waitForTasksFinished();
 
@@ -150,7 +148,7 @@
 ''');
 
     addTestFile(testSource);
-    setAnalysisRoot();
+    await setAnalysisRoot();
 
     await waitForTasksFinished();
 
@@ -176,7 +174,7 @@
 ''');
 
     addTestFile(testSource);
-    setAnalysisRoot();
+    await setAnalysisRoot();
 
     await waitForTasksFinished();
 
@@ -188,7 +186,7 @@
 
   Future<void> test_options_file_added() async {
     addTestFile(testSource);
-    setAnalysisRoot();
+    await setAnalysisRoot();
 
     await waitForTasksFinished();
 
@@ -215,7 +213,7 @@
     addOptionsFile('''
 ; #bang
 ''');
-    setAnalysisRoot();
+    await setAnalysisRoot();
 
     await waitForTasksFinished();
 
@@ -233,7 +231,7 @@
 ''');
 
     addTestFile(testSource);
-    setAnalysisRoot();
+    await setAnalysisRoot();
 
     await waitForTasksFinished();
 
diff --git a/pkg/analysis_server/test/analysis/notification_analyzed_files_test.dart b/pkg/analysis_server/test/analysis/notification_analyzed_files_test.dart
index c7bcb7e..93cb4ac 100644
--- a/pkg/analysis_server/test/analysis/notification_analyzed_files_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_analyzed_files_test.dart
@@ -46,9 +46,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
   }
 
   Future<void> test_afterAnalysis() async {
diff --git a/pkg/analysis_server/test/analysis/notification_closing_labels_test.dart b/pkg/analysis_server/test/analysis/notification_closing_labels_test.dart
index 972025f..b61849e 100644
--- a/pkg/analysis_server/test/analysis/notification_closing_labels_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_closing_labels_test.dart
@@ -55,9 +55,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
   }
 
   void subscribeForLabels() {
diff --git a/pkg/analysis_server/test/analysis/notification_errors_test.dart b/pkg/analysis_server/test/analysis/notification_errors_test.dart
index c311ec8..e2aa4c7 100644
--- a/pkg/analysis_server/test/analysis/notification_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_errors_test.dart
@@ -59,9 +59,7 @@
     - invalid_lint_rule_name
 ''').path;
 
-    var request =
-        AnalysisSetAnalysisRootsParams([projectPath], []).toRequest('0');
-    handleSuccessfulRequest(request);
+    await setRoots(included: [projectPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
     //
@@ -81,9 +79,7 @@
 include: package:pedantic/analysis_options.yaml
 ''').path;
 
-    var request =
-        AnalysisSetAnalysisRootsParams([projectPath], []).toRequest('0');
-    handleSuccessfulRequest(request);
+    await setRoots(included: [projectPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
 
@@ -122,9 +118,7 @@
     chrome-os-manifest-checks: true
 ''');
 
-    var request =
-        AnalysisSetAnalysisRootsParams([projectPath], []).toRequest('0');
-    handleSuccessfulRequest(request);
+    await setRoots(included: [projectPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
     //
@@ -153,9 +147,7 @@
     chrome-os-manifest-checks: true
 ''');
 
-    var request =
-        AnalysisSetAnalysisRootsParams([projectPath], []).toRequest('0');
-    handleSuccessfulRequest(request);
+    await setRoots(included: [projectPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
     //
@@ -185,7 +177,7 @@
 A? a;
     ''');
 
-    createProject();
+    await createProject();
     await waitForTasksFinished();
     await pumpEventQueue(times: 5000);
     expect(filesErrors[testFile], isEmpty);
@@ -206,9 +198,7 @@
 transforms:
 ''').path;
 
-    var request =
-        AnalysisSetAnalysisRootsParams([projectPath], []).toRequest('0');
-    handleSuccessfulRequest(request);
+    await setRoots(included: [projectPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
     //
@@ -226,7 +216,7 @@
     // Files inside dotFolders should not generate error notifications even
     // if they are added to priority (priority affects only priority, not what
     // is analyzed).
-    createProject();
+    await createProject();
     addTestFile('');
     var brokenFile =
         newFile(join(projectPath, '.dart_tool/broken.dart'), content: 'err')
@@ -251,7 +241,7 @@
     // them to be opened (such as hovers) should not result in error notifications
     // because there is no event that would flush them and they'd remain in the
     // editor forever.
-    createProject();
+    await createProject();
     addTestFile('');
     var brokenFile =
         newFile(join(projectPath, '.dart_tool/broken.dart'), content: 'err')
@@ -276,7 +266,7 @@
   exclude:
     - excluded/**
 ''');
-    createProject();
+    await createProject();
     var excludedFile =
         newFile(join(projectPath, 'excluded/broken.dart'), content: 'err').path;
 
@@ -300,7 +290,7 @@
   }
 
   Future<void> test_importError() async {
-    createProject();
+    await createProject();
 
     addTestFile('''
 import 'does_not_exist.dart';
@@ -328,10 +318,7 @@
 
     addTestFile('class a { }');
 
-    var request =
-        AnalysisSetAnalysisRootsParams([projectPath], []).toRequest('0');
-    handleSuccessfulRequest(request);
-
+    await setRoots(included: [projectPath], excluded: []);
     await waitForTasksFinished();
 
     var testDriver = server.getAnalysisDriver(testFile)!;
@@ -353,7 +340,7 @@
   }
 
   Future<void> test_notInAnalysisRoot() async {
-    createProject();
+    await createProject();
     var otherFile = newFile('/other.dart', content: 'UnknownType V;').path;
     addTestFile('''
 import '/other.dart';
@@ -368,7 +355,7 @@
   Future<void> test_overlay_dotFolder() async {
     // Files inside dotFolders should not generate error notifications even
     // if they have overlays added.
-    createProject();
+    await createProject();
     addTestFile('');
     var brokenFile =
         newFile(join(projectPath, '.dart_tool/broken.dart'), content: 'err')
@@ -396,7 +383,7 @@
     // Overlays added for files that don't exist on disk should still generate
     // error notifications. Removing the overlay if the file is not on disk
     // should clear the errors.
-    createProject();
+    await createProject();
     addTestFile('');
     var brokenFile = convertPath(join(projectPath, 'broken.dart'));
 
@@ -432,7 +419,7 @@
     // error notifications. If the file is subsequently saved to disk before the
     // overlay is removed, the errors should not be flushed when the overlay is
     // removed.
-    createProject();
+    await createProject();
     addTestFile('');
     var brokenFile = convertPath(join(projectPath, 'broken.dart'));
 
@@ -468,7 +455,7 @@
   }
 
   Future<void> test_ParserError() async {
-    createProject();
+    await createProject();
     addTestFile('library lib');
     await waitForTasksFinished();
     await pumpEventQueue(times: 5000);
@@ -489,9 +476,7 @@
 version: 1.3.2
 ''').path;
 
-    var setRootsRequest =
-        AnalysisSetAnalysisRootsParams([projectPath], []).toRequest('0');
-    handleSuccessfulRequest(setRootsRequest);
+    await setRoots(included: [projectPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
     //
@@ -533,9 +518,7 @@
   a: any
 ''').path;
 
-    var setRootsRequest =
-        AnalysisSetAnalysisRootsParams([projectPath], []).toRequest('0');
-    handleSuccessfulRequest(setRootsRequest);
+    await setRoots(included: [projectPath], excluded: []);
     await waitForTasksFinished();
     await pumpEventQueue();
     //
@@ -565,7 +548,7 @@
   }
 
   Future<void> test_StaticWarning() async {
-    createProject();
+    await createProject();
     addTestFile('''
 enum E {e1, e2}
 
diff --git a/pkg/analysis_server/test/analysis/notification_folding_test.dart b/pkg/analysis_server/test/analysis/notification_folding_test.dart
index 39612a6..bc1ed96 100644
--- a/pkg/analysis_server/test/analysis/notification_folding_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_folding_test.dart
@@ -51,9 +51,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
   }
 
   void subscribeForFolding() {
diff --git a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
index a39c58d..6645f3f 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
@@ -1414,9 +1414,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
   }
 
   void _addLibraryForTestPart() {
diff --git a/pkg/analysis_server/test/analysis/notification_implemented_test.dart b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
index 7e90f36..c0deb4e 100644
--- a/pkg/analysis_server/test/analysis/notification_implemented_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
@@ -102,9 +102,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
   }
 
   void subscribeForImplemented() {
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index 035909b..d01110b 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -182,9 +182,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
   }
 
   Future<void> test_afterAnalysis() async {
diff --git a/pkg/analysis_server/test/analysis/notification_occurrences_test.dart b/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
index 576456a..777e230 100644
--- a/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
@@ -88,9 +88,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
   }
 
   Future<void> test_afterAnalysis() async {
diff --git a/pkg/analysis_server/test/analysis/notification_outline_test.dart b/pkg/analysis_server/test/analysis/notification_outline_test.dart
index 5488d67..8db0451 100644
--- a/pkg/analysis_server/test/analysis/notification_outline_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_outline_test.dart
@@ -54,9 +54,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
   }
 
   Future<void> test_afterAnalysis() async {
diff --git a/pkg/analysis_server/test/analysis/notification_overrides_test.dart b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
index a3846b4..bc48633 100644
--- a/pkg/analysis_server/test/analysis/notification_overrides_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
@@ -121,9 +121,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
   }
 
   Future<void> test_afterAnalysis() async {
diff --git a/pkg/analysis_server/test/analysis/reanalyze_test.dart b/pkg/analysis_server/test/analysis/reanalyze_test.dart
index 358df55..4fc723b 100644
--- a/pkg/analysis_server/test/analysis/reanalyze_test.dart
+++ b/pkg/analysis_server/test/analysis/reanalyze_test.dart
@@ -37,7 +37,7 @@
 
 var b = B();
 ''');
-    createProject();
+    await createProject();
 
     // b.dart does not exist, and `B` is unresolved.
     await waitForTasksFinished();
@@ -50,7 +50,7 @@
     newFile(b, content: 'class B {}');
 
     // Reanalyze.
-    server.reanalyze();
+    await server.reanalyze();
     await waitForTasksFinished();
 
     // No errors.
diff --git a/pkg/analysis_server/test/analysis/set_priority_files_test.dart b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
index 658c3ff..c39b2c1 100644
--- a/pkg/analysis_server/test/analysis/set_priority_files_test.dart
+++ b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
@@ -21,12 +21,12 @@
 @reflectiveTest
 class SetPriorityFilesTest extends AbstractAnalysisTest {
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
     server.handlers = [
       AnalysisDomainHandler(server),
     ];
-    createProject();
+    await createProject();
   }
 
   Future<void> test_fileDoesNotExist() async {
diff --git a/pkg/analysis_server/test/analysis/update_content_test.dart b/pkg/analysis_server/test/analysis/update_content_test.dart
index 3d6a4ec..f85f7d4 100644
--- a/pkg/analysis_server/test/analysis/update_content_test.dart
+++ b/pkg/analysis_server/test/analysis/update_content_test.dart
@@ -41,10 +41,10 @@
     }
   }
 
-  void test_illegal_ChangeContentOverlay() {
+  void test_illegal_ChangeContentOverlay() async {
     // It should be illegal to send a ChangeContentOverlay for a file that
     // doesn't have an overlay yet.
-    createProject();
+    await createProject();
     addTestFile('library foo;');
     var id = 'myId';
     try {
@@ -95,10 +95,7 @@
 library baz;
 f(int i) {}
 ''').path;
-    var request =
-        AnalysisSetAnalysisRootsParams([project1path, project2path], [])
-            .toRequest('0');
-    handleSuccessfulRequest(request);
+    await setRoots(included: [project1path, project2path], excluded: []);
     {
       await server.onAnalysisComplete;
       // Files foo.dart and bar.dart should both have errors, since they both
@@ -126,8 +123,7 @@
   Future<void> test_overlay_addPreviouslyImported() async {
     // The list of errors doesn't include errors for '/project/target.dart'.
     var project = newFolder('/project');
-    handleSuccessfulRequest(
-        AnalysisSetAnalysisRootsParams([project.path], []).toRequest('0'));
+    await setRoots(included: [project.path], excluded: []);
 
     server.updateContent('1',
         {'/project/main.dart': AddContentOverlay('import "target.dart";')});
@@ -153,10 +149,7 @@
     var folderPath1 = newFolder('/User/project1').path;
     var folderPath2 = newFolder('/User/project2').path;
 
-    handleSuccessfulRequest(AnalysisSetAnalysisRootsParams(
-      [folderPath1, folderPath2],
-      [],
-    ).toRequest('0'));
+    await setRoots(included: [folderPath1, folderPath2], excluded: []);
 
     // exactly 2 contexts
     expect(server.driverMap, hasLength(2));
@@ -184,7 +177,7 @@
   Future<void> test_sendNoticesAfterNopChange() async {
     // The errors are empty on the last line.
     addTestFile('');
-    createProject();
+    await createProject();
     await server.onAnalysisComplete;
     // add an overlay
     server.updateContent(
@@ -204,7 +197,7 @@
   Future<void> test_sendNoticesAfterNopChange_flushedUnit() async {
     // The list of errors is empty on the last line.
     addTestFile('');
-    createProject();
+    await createProject();
     await server.onAnalysisComplete;
     // add an overlay
     server.updateContent(
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index 558a318..ccbee9b 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -114,9 +114,9 @@
   }
 
   /// Creates a project [projectPath].
-  void createProject({Map<String, String>? packageRoots}) {
+  Future<void> createProject({Map<String, String>? packageRoots}) async {
     newFolder(projectPath);
-    setRoots(included: [projectPath], excluded: []);
+    await setRoots(included: [projectPath], excluded: []);
   }
 
   void doAllDeclarationsTrackerWork() {
@@ -175,20 +175,23 @@
     handleSuccessfulRequest(request);
   }
 
-  void setRoots({
+  Future<Response> setRoots({
     required List<String> included,
     required List<String> excluded,
-  }) {
-    var includedConverted = included.map(convertPath).toList();
-    var excludedConverted = excluded.map(convertPath).toList();
-    var request = AnalysisSetAnalysisRootsParams(
-        includedConverted, excludedConverted,
-        packageRoots: {}).toRequest('0');
-    handleSuccessfulRequest(request, handler: analysisHandler);
+    bool validateSuccessResponse = true,
+  }) async {
+    var request =
+        AnalysisSetAnalysisRootsParams(included, excluded, packageRoots: {})
+            .toRequest('0');
+    var response = await waitResponse(request);
+    if (validateSuccessResponse) {
+      expect(response, isResponseSuccess(request.id));
+    }
+    return response;
   }
 
   @mustCallSuper
-  void setUp() {
+  void setUp() async {
     serverChannel = MockServerChannel();
     projectPath = convertPath('/project');
     testFolder = convertPath('/project/bin');
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 907c39a..4f1a44d 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -10,9 +10,12 @@
 import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
 import 'package:analysis_server/src/utilities/mocks.dart';
 import 'package:analysis_server/src/utilities/progress.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/test_utilities/mock_sdk.dart';
+import 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:test/test.dart';
@@ -26,6 +29,13 @@
 
 @reflectiveTest
 class AnalysisServerTest with ResourceProviderMixin {
+  @override
+  MemoryResourceProvider resourceProvider = MemoryResourceProvider(
+    // Force the in-memory file watchers to be slowly initialized to emulate
+    // the physical watchers (for test_concurrentContextRebuilds).
+    delayWatcherInitialization: Duration(milliseconds: 1),
+  );
+
   late MockServerChannel channel;
   late AnalysisServer server;
 
@@ -38,7 +48,7 @@
     newFolder('/bar');
     newFile('/foo/foo.dart', content: 'import "../bar/bar.dart";');
     var bar = newFile('/bar/bar.dart', content: 'library bar;');
-    server.setAnalysisRoots('0', ['/foo', '/bar'], []);
+    await server.setAnalysisRoots('0', ['/foo', '/bar'], []);
     var subscriptions = <AnalysisService, Set<String>>{};
     for (var service in AnalysisService.VALUES) {
       subscriptions[service] = <String>{bar.path};
@@ -94,6 +104,72 @@
         InstrumentationService.NULL_SERVICE);
   }
 
+  /// Test that modifying package_config again while a context rebuild is in
+  /// progress does not get lost due to a gap between creating a file watcher
+  /// and it raising events.
+  /// https://github.com/Dart-Code/Dart-Code/issues/3438
+  Future test_concurrentContextRebuilds() async {
+    // Subscribe to STATUS so we'll know when analysis is done.
+    server.serverServices = {ServerService.STATUS};
+    final projectRoot = '/foo';
+    final projectTestFile = '/foo/test.dart';
+    final projectPackageConfigFile = '/foo/.dart_tool/package_config.json';
+
+    // Create a file that references two packages, which will we write to
+    // package_config.json individually.
+    newFolder(projectRoot);
+    newFile(
+      projectTestFile,
+      content: r'''
+      import "package:foo/foo.dart";'
+      import "package:bar/bar.dart";'
+      ''',
+    );
+
+    // Ensure the packages and package_config exist.
+    var fooLibFolder = _addSimplePackage('foo', '');
+    var barLibFolder = _addSimplePackage('bar', '');
+    final config = PackageConfigFileBuilder();
+    writePackageConfig(projectPackageConfigFile, config);
+
+    // Track diagnostics that arrive.
+    final errorsByFile = <String, List<AnalysisError>>{};
+    channel.notificationController.stream
+        .where((notification) => notification.event == 'analysis.errors')
+        .listen((notificaton) {
+      final params = AnalysisErrorsParams.fromNotification(notificaton);
+      errorsByFile[params.file] = params.errors;
+    });
+
+    /// Helper that waits for analysis then returns the relevant errors.
+    Future<List<AnalysisError>> getUriNotExistErrors() async {
+      await server.onAnalysisComplete;
+      expect(server.statusAnalyzing, isFalse);
+      return errorsByFile[projectTestFile]!
+          .where((error) => error.code == 'uri_does_not_exist')
+          .toList();
+    }
+
+    // Set roots and expect 2 uri_does_not_exist errors.
+    await server.setAnalysisRoots('0', [projectRoot], []);
+    expect(await getUriNotExistErrors(), hasLength(2));
+
+    // Write both packages, in two events so that the first one will trigger
+    // a rebuild.
+    config.add(name: 'foo', rootPath: fooLibFolder.parent2.path);
+    writePackageConfig(projectPackageConfigFile, config);
+    await pumpEventQueue(times: 1); // Allow server to begin processing.
+    config.add(name: 'bar', rootPath: barLibFolder.parent2.path);
+    writePackageConfig(projectPackageConfigFile, config);
+
+    // Allow the server to catch up with everything.
+    await pumpEventQueue(times: 5000);
+    await server.onAnalysisComplete;
+
+    // Expect both errors are gone.
+    expect(await getUriNotExistErrors(), hasLength(0));
+  }
+
   Future test_echo() {
     server.handlers = [EchoHandler(server)];
     var request = Request('my22', 'echo');
@@ -109,7 +185,7 @@
     newFile('/test/lib/a.dart', content: r'''
 class A {}
 ''');
-    server.setAnalysisRoots('0', [convertPath('/test')], []);
+    await server.setAnalysisRoots('0', [convertPath('/test')], []);
 
     // Pump the event queue, so that the server has finished any analysis.
     await pumpEventQueue(times: 5000);
@@ -139,7 +215,7 @@
     server.serverServices.add(ServerService.STATUS);
 
     newFolder('/test');
-    server.setAnalysisRoots('0', [convertPath('/test')], []);
+    await server.setAnalysisRoots('0', [convertPath('/test')], []);
 
     // Pump the event queue, so that the server has finished any analysis.
     await pumpEventQueue(times: 5000);
@@ -174,13 +250,13 @@
   exclude:
     - 'samples/**'
 ''');
-    server.setAnalysisRoots('0', [convertPath('/project')], []);
+    await server.setAnalysisRoots('0', [convertPath('/project')], []);
     server.setAnalysisSubscriptions(<AnalysisService, Set<String>>{
       AnalysisService.NAVIGATION: <String>{path}
     });
 
     // We respect subscriptions, even for excluded files.
-    await pumpEventQueue();
+    await pumpEventQueue(times: 5000);
     expect(channel.notificationsReceived.any((notification) {
       return notification.event == ANALYSIS_NOTIFICATION_NAVIGATION;
     }), isTrue);
@@ -195,13 +271,13 @@
   exclude:
     - 'samples/**'
 ''');
-    server.setAnalysisRoots('0', [convertPath('/project')], []);
+    await server.setAnalysisRoots('0', [convertPath('/project')], []);
     server.setAnalysisSubscriptions(<AnalysisService, Set<String>>{
       AnalysisService.NAVIGATION: <String>{path}
     });
 
     // We respect subscriptions, even for excluded files.
-    await pumpEventQueue();
+    await pumpEventQueue(times: 5000);
     expect(channel.notificationsReceived.any((notification) {
       return notification.event == ANALYSIS_NOTIFICATION_NAVIGATION;
     }), isTrue);
@@ -255,6 +331,20 @@
       expect(response.error, isNotNull);
     });
   }
+
+  void writePackageConfig(String path, PackageConfigFileBuilder config) {
+    newFile(path, content: config.toContent(toUriStr: toUriStr));
+  }
+
+  /// Creates a simple package named [name] with [content] in the file at
+  /// `package:$name/$name.dart`.
+  ///
+  /// Returns a [Folder] that represents the packages `lib` folder.
+  Folder _addSimplePackage(String name, String content) {
+    final packagePath = '/packages/$name';
+    final file = newFile('$packagePath/lib/$name.dart', content: content);
+    return file.parent2;
+  }
 }
 
 class EchoHandler implements RequestHandler {
diff --git a/pkg/analysis_server/test/client/completion_driver_test.dart b/pkg/analysis_server/test/client/completion_driver_test.dart
index c705575..50a6021 100644
--- a/pkg/analysis_server/test/client/completion_driver_test.dart
+++ b/pkg/analysis_server/test/client/completion_driver_test.dart
@@ -122,7 +122,7 @@
   }
 
   @mustCallSuper
-  void setUp() {
+  Future<void> setUp() async {
     driver = CompletionDriver(
       supportsAvailableSuggestions: supportsAvailableSuggestions,
       projectPath: projectPath,
@@ -130,7 +130,7 @@
       resourceProvider: resourceProvider,
       serverOptions: serverOptions,
     );
-    driver.createProject(packageRoots: packageRoots);
+    await driver.createProject(packageRoots: packageRoots);
 
     newPubspecYamlFile(projectPath, '');
     newDotPackagesFile(projectPath, content: '''
diff --git a/pkg/analysis_server/test/client/impl/abstract_client.dart b/pkg/analysis_server/test/client/impl/abstract_client.dart
index 999451f..d1ad27f 100644
--- a/pkg/analysis_server/test/client/impl/abstract_client.dart
+++ b/pkg/analysis_server/test/client/impl/abstract_client.dart
@@ -120,12 +120,11 @@
 
   /// Create a project at [projectPath].
   @mustCallSuper
-  void createProject({Map<String, String>? packageRoots}) {
+  Future<void> createProject({Map<String, String>? packageRoots}) async {
     newFolder(projectPath);
-    var request = AnalysisSetAnalysisRootsParams([projectPath], [],
-            packageRoots: packageRoots)
-        .toRequest('0');
-    handleSuccessfulRequest(request, handler: analysisHandler);
+
+    await setRoots(
+        included: [projectPath], excluded: [], packageRoots: packageRoots);
   }
 
   void expect(actual, matcher, {String reason});
@@ -144,6 +143,19 @@
 
   void processNotification(Notification notification);
 
+  Future<Response> setRoots({
+    required List<String> included,
+    required List<String> excluded,
+    Map<String, String>? packageRoots,
+  }) async {
+    var request = AnalysisSetAnalysisRootsParams(included, excluded,
+            packageRoots: packageRoots)
+        .toRequest('0');
+    var response = await waitResponse(request);
+    expect(response, isResponseSuccess(request.id));
+    return response;
+  }
+
   /// Returns a [Future] that completes when the server's analysis is complete.
   Future waitForTasksFinished() => server.onAnalysisComplete;
 
diff --git a/pkg/analysis_server/test/client/impl/completion_driver.dart b/pkg/analysis_server/test/client/impl/completion_driver.dart
index bbdeee9..09285b7 100644
--- a/pkg/analysis_server/test/client/impl/completion_driver.dart
+++ b/pkg/analysis_server/test/client/impl/completion_driver.dart
@@ -108,8 +108,8 @@
   }
 
   @override
-  void createProject({Map<String, String>? packageRoots}) {
-    super.createProject(packageRoots: packageRoots);
+  Future<void> createProject({Map<String, String>? packageRoots}) async {
+    await super.createProject(packageRoots: packageRoots);
     if (supportsAvailableSuggestions) {
       var request = CompletionSetSubscriptionsParams(
           [CompletionService.AVAILABLE_SUGGESTION_SETS]).toRequest('0');
diff --git a/pkg/analysis_server/test/completion_test_support.dart b/pkg/analysis_server/test/completion_test_support.dart
index 04c6b0f..35f61fd 100644
--- a/pkg/analysis_server/test/completion_test_support.dart
+++ b/pkg/analysis_server/test/completion_test_support.dart
@@ -79,8 +79,8 @@
         .toList();
   }
 
-  Future runTest(LocationSpec spec, [Map<String, String>? extraFiles]) {
-    super.setUp();
+  Future runTest(LocationSpec spec, [Map<String, String>? extraFiles]) async {
+    await super.setUp();
     return Future(() {
       var content = spec.source;
       newFile(testFile, content: content);
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index fa3b3e4..fe0da92 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -60,7 +60,7 @@
 void f(int? a) {}
 ''');
 
-    setRoots(included: [myPackageRootPath], excluded: []);
+    await setRoots(included: [myPackageRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // Cannot use `int?` without enabling null safety.
@@ -83,7 +83,7 @@
 class AnalysisDomainHandlerTest extends AbstractAnalysisTest {
   Future<void> outOfRangeTest(SourceEdit edit) async {
     var helper = AnalysisTestHelper();
-    helper.createSingleFileProject('library A;');
+    await helper.createSingleFileProject('library A;');
     await helper.onAnalysisComplete;
     helper.sendContentChange(AddContentOverlay('library B;'));
     await helper.onAnalysisComplete;
@@ -99,14 +99,14 @@
     newFile('/project/aaa/a.dart', content: '// a');
     newFile('/project/bbb/b.dart', content: '// b');
     var excludedPath = join(projectPath, 'bbb');
-    var response = testSetAnalysisRoots([projectPath], [excludedPath]);
+    var response = await testSetAnalysisRoots([projectPath], [excludedPath]);
     expect(response, isResponseSuccess('0'));
   }
 
   Future<void> test_setAnalysisRoots_included_newFolder() async {
     newPubspecYamlFile('/project', 'name: project');
     var file = newFile('/project/bin/test.dart', content: 'main() {}').path;
-    var response = testSetAnalysisRoots([projectPath], []);
+    var response = await testSetAnalysisRoots([projectPath], []);
     var serverRef = server;
     expect(response, isResponseSuccess('0'));
     // verify that unit is resolved eventually
@@ -119,7 +119,7 @@
     var projectA = convertPath('/project_a');
     var projectB = convertPath('/project_b');
     var fileB = newFile('/project_b/b.dart', content: '// b').path;
-    var response = testSetAnalysisRoots([projectA, projectB], []);
+    var response = await testSetAnalysisRoots([projectA, projectB], []);
     var serverRef = server;
     expect(response, isResponseSuccess('0'));
     // Non-existence of /project_a should not prevent files in /project_b
@@ -130,25 +130,25 @@
   }
 
   Future<void> test_setAnalysisRoots_included_notAbsolute() async {
-    var response = testSetAnalysisRoots(['foo/bar'], []);
+    var response = await testSetAnalysisRoots(['foo/bar'], []);
     expect(response,
         isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT));
   }
 
   Future<void> test_setAnalysisRoots_included_notNormalized() async {
-    var response = testSetAnalysisRoots(['/foo/../bar'], []);
+    var response = await testSetAnalysisRoots(['/foo/../bar'], []);
     expect(response,
         isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT));
   }
 
   Future<void> test_setAnalysisRoots_notAbsolute() async {
-    var response = testSetAnalysisRoots([], ['foo/bar']);
+    var response = await testSetAnalysisRoots([], ['foo/bar']);
     expect(response,
         isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT));
   }
 
   Future<void> test_setAnalysisRoots_notNormalized() async {
-    var response = testSetAnalysisRoots([], ['/foo/../bar']);
+    var response = await testSetAnalysisRoots([], ['/foo/../bar']);
     expect(response,
         isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT));
   }
@@ -161,7 +161,7 @@
     expect(response, isResponseSuccess('0'));
   }
 
-  void test_setPriorityFiles_valid() {
+  Future<void> test_setPriorityFiles_valid() async {
     var p1 = convertPath('/p1');
     var p2 = convertPath('/p2');
     var aPath = convertPath('/p1/a.dart');
@@ -171,11 +171,7 @@
     newFile(bPath, content: 'library b;');
     newFile(cPath, content: 'library c;');
 
-    var setRootsRequest =
-        AnalysisSetAnalysisRootsParams([p1, p2], []).toRequest('0');
-    var setRootsResponse =
-        handler.handleRequest(setRootsRequest, NotCancelableToken());
-    expect(setRootsResponse, isResponseSuccess('0'));
+    await setRoots(included: [p1, p2], excluded: []);
 
     void setPriorityFiles(List<String> fileList) {
       var request = AnalysisSetPriorityFilesParams(fileList).toRequest('0');
@@ -193,7 +189,7 @@
 
   Future<void> test_updateContent_badType() async {
     var helper = AnalysisTestHelper();
-    helper.createSingleFileProject('// empty');
+    await helper.createSingleFileProject('// empty');
     await helper.onAnalysisComplete;
     var request = Request('0', ANALYSIS_REQUEST_UPDATE_CONTENT, {
       ANALYSIS_REQUEST_UPDATE_CONTENT_FILES: {
@@ -208,7 +204,7 @@
 
   Future<void> test_updateContent_changeOnDisk_duringOverride() async {
     var helper = AnalysisTestHelper();
-    helper.createSingleFileProject('library A;');
+    await helper.createSingleFileProject('library A;');
     await helper.onAnalysisComplete;
     // update code
     helper.sendContentChange(AddContentOverlay('library B;'));
@@ -230,7 +226,7 @@
 
   Future<void> test_updateContent_changeOnDisk_normal() async {
     var helper = AnalysisTestHelper();
-    helper.createSingleFileProject('library A;');
+    await helper.createSingleFileProject('library A;');
     await helper.onAnalysisComplete;
     // There should be no errors
     expect(helper.getTestErrors(), hasLength(0));
@@ -244,7 +240,7 @@
 
   Future<void> test_updateContent_fullContent() async {
     var helper = AnalysisTestHelper();
-    helper.createSingleFileProject('// empty');
+    await helper.createSingleFileProject('// empty');
     await helper.onAnalysisComplete;
     // no errors initially
     var errors = helper.getTestErrors();
@@ -260,7 +256,7 @@
   Future<void> test_updateContent_incremental() async {
     var helper = AnalysisTestHelper();
     var initialContent = 'library A;';
-    helper.createSingleFileProject(initialContent);
+    await helper.createSingleFileProject(initialContent);
     await helper.onAnalysisComplete;
     // no errors initially
     var errors = helper.getTestErrors();
@@ -305,17 +301,17 @@
     expect(response, isResponseSuccess('0'));
   }
 
-  Response testSetAnalysisRoots(List<String> included, List<String> excluded) {
-    var request =
-        AnalysisSetAnalysisRootsParams(included, excluded).toRequest('0');
-    return handler.handleRequest(request, NotCancelableToken())!;
+  Future<Response> testSetAnalysisRoots(
+      List<String> included, List<String> excluded) {
+    return setRoots(
+        included: included, excluded: excluded, validateSuccessResponse: false);
   }
 
   Future<void> xtest_getReachableSources_invalidSource() async {
     // TODO(brianwilkerson) Re-enable this test if we re-enable the
     // analysis.getReachableSources request.
     newFile('/project/a.dart', content: 'import "b.dart";');
-    server.setAnalysisRoots('0', ['/project/'], []);
+    await server.setAnalysisRoots('0', ['/project/'], []);
 
     await server.onAnalysisComplete;
 
@@ -332,7 +328,7 @@
     var fileA = newFile('/project/a.dart', content: 'import "b.dart";').path;
     newFile('/project/b.dart');
 
-    server.setAnalysisRoots('0', ['/project/'], []);
+    await server.setAnalysisRoots('0', ['/project/'], []);
 
     await server.onAnalysisComplete;
 
@@ -365,7 +361,7 @@
 
     _createFilesWithErrors([a_path, b_path]);
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // Both a.dart and b.dart are analyzed.
@@ -398,7 +394,7 @@
 
     newFile(a_path, content: 'error');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // a.dart was analyzed
@@ -433,7 +429,7 @@
     chrome-os-manifest-checks: true
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
 
     newFile(path, content: '<manifest/>');
     await pumpEventQueue();
@@ -449,7 +445,7 @@
     // We have to create the folder, otherwise there is nothing to watch.
     newFolder(testPackageLibPath);
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // We don't have a.dart yet.
@@ -472,7 +468,7 @@
 void f(A a) {}
 ''');
 
-    createProject();
+    await createProject();
     await pumpEventQueue();
     await server.onAnalysisComplete;
 
@@ -507,7 +503,7 @@
 void f(A a) {}
 ''');
 
-    createProject();
+    await createProject();
     await pumpEventQueue();
     await server.onAnalysisComplete;
 
@@ -540,7 +536,7 @@
 void f(A a) {}
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // We cannot resolve `package:aaa/a.dart`
@@ -572,7 +568,7 @@
       PackageConfigFileBuilder(),
     );
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
 
     // No `fix_data.yaml` to analyze yet.
     assertNoErrorsNotification(path);
@@ -602,7 +598,7 @@
 void f(A a) {}
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // We cannot resolve `package:aaa/a.dart`
@@ -634,7 +630,7 @@
     // We look for `pubspec.yaml` files only in analysis context roots.
     newAnalysisOptionsYamlFile(testPackageRootPath, content: '');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // a.dart was analyzed
@@ -664,7 +660,7 @@
 
     newFile(a_path, content: 'error');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // a.dart was analyzed
@@ -698,7 +694,7 @@
     - lib/b.dart
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // Only a.dart is analyzed, because b.dart is excluded.
@@ -740,7 +736,7 @@
     chrome-os-manifest-checks: true
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
 
     // Forget and check that we did.
     forgetReceivedErrors();
@@ -768,7 +764,7 @@
 void f(A a) {}
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     assertNoErrors(a_path);
@@ -798,7 +794,7 @@
 void f(A a) {}
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await pumpEventQueue();
     await server.onAnalysisComplete;
 
@@ -840,7 +836,7 @@
 void f(A a) {}
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await pumpEventQueue();
     await server.onAnalysisComplete;
 
@@ -876,7 +872,7 @@
 void f(A a) {}
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // We cannot resolve `package:aaa/a.dart`
@@ -911,7 +907,7 @@
     // This file has an error.
     newFile(path, content: '0: 1');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
 
     // The file was analyzed.
     assertHasErrors(path);
@@ -950,7 +946,7 @@
 void f(A a) {}
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // We cannot resolve `package:aaa/a.dart`
@@ -986,7 +982,7 @@
     - lib/b.dart
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // Only a.dart is analyzed, because b.dart is excluded.
@@ -1023,7 +1019,7 @@
     chrome-os-manifest-checks: true
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
 
     // An error was reported.
     _assertAnalyzedFiles(hasErrors: [path], notAnalyzed: []);
@@ -1041,7 +1037,7 @@
 
     _createFilesWithErrors([a_path]);
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // a.dart was analyzed
@@ -1075,7 +1071,7 @@
 void f(A a) {}
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await pumpEventQueue();
     await server.onAnalysisComplete;
 
@@ -1110,7 +1106,7 @@
 void f(A a) {}
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // We have `A` in 'package:aaa/a.dart', so no errors.
@@ -1143,7 +1139,7 @@
     // This file has an error.
     newFile(path, content: '0: 1');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
 
     // The file was analyzed.
     _assertAnalyzedFiles(hasErrors: [path], notAnalyzed: []);
@@ -1175,7 +1171,7 @@
 void f(A a) {}
 ''');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // We have `A` in 'package:aaa/a.dart', so no errors.
@@ -1214,7 +1210,7 @@
 ''');
 
     // create project and wait for analysis
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // We have `A` in 'package:aaa/a.dart', so no errors.
@@ -1230,7 +1226,7 @@
 
     _createFilesWithErrors([a_path, b_path]);
 
-    setRoots(included: [a_path], excluded: []);
+    await setRoots(included: [a_path], excluded: []);
 
     // Only a.dart is included, so b.dart is not analyzed.
     await server.onAnalysisComplete;
@@ -1247,7 +1243,7 @@
     _createFilesWithErrors([a_path, b_path]);
 
     // Include only single file.
-    setRoots(included: [a_path], excluded: []);
+    await setRoots(included: [a_path], excluded: []);
     await server.onAnalysisComplete;
 
     // So, only a.dart is analyzed, and b.dart is not.
@@ -1257,7 +1253,7 @@
     );
 
     // Include the folder that contains both a.dart and b.dart
-    setRoots(included: [testPackageRootPath], excluded: []);
+    await setRoots(included: [testPackageRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // So, both a.dart and b.dart are analyzed.
@@ -1281,7 +1277,7 @@
       notIncludedFile,
     ]);
 
-    setRoots(included: [includedFile, includedFolder], excluded: []);
+    await setRoots(included: [includedFile, includedFolder], excluded: []);
     await server.onAnalysisComplete;
 
     // We can combine a file, and a folder as included paths.
@@ -1307,7 +1303,7 @@
 
     _createFilesWithErrors([a_path, b_path]);
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
 
     // b.dart is excluded using the options file.
     await server.onAnalysisComplete;
@@ -1324,7 +1320,7 @@
 
     _createFilesWithErrors([a_path, excluded_path]);
 
-    setRoots(
+    await setRoots(
       included: [workspaceRootPath],
       excluded: [excluded_path],
     );
@@ -1342,7 +1338,7 @@
 
     _createFilesWithErrors([a_path, excluded_path]);
 
-    setRoots(
+    await setRoots(
       included: [workspaceRootPath],
       excluded: ['$testPackageRootPath/excluded'],
     );
@@ -1368,7 +1364,7 @@
 
     newFile(path, content: '<manifest/>');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
 
     // No touch-screen.
     assertHasErrors(path);
@@ -1386,7 +1382,7 @@
     // So, `lib/fix_data.yaml` will be analyzed.
     newFile(path, content: '0: 1');
 
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
 
     assertHasErrors(path);
   }
@@ -1410,7 +1406,7 @@
 ''');
 
     // create project and wait for analysis
-    setRoots(included: [workspaceRootPath], excluded: []);
+    await setRoots(included: [workspaceRootPath], excluded: []);
     await server.onAnalysisComplete;
 
     // We have `A` in 'package:aaa/a.dart', so no errors.
@@ -1512,13 +1508,11 @@
 
   /// Creates a project with a single Dart file `/project/bin/test.dart` with
   /// the given [code].
-  void createSingleFileProject(code) {
+  Future<void> createSingleFileProject(code) async {
     testCode = _getCodeString(code);
     newFolder(projectPath);
     newFile(testFile, content: testCode);
-    var request =
-        AnalysisSetAnalysisRootsParams([projectPath], []).toRequest('0');
-    handleSuccessfulRequest(request);
+    await setRoots(included: [projectPath], excluded: []);
   }
 
   /// Returns the offset of [search] in [testCode].
@@ -1590,11 +1584,25 @@
     handleSuccessfulRequest(request);
   }
 
+  Future<void> setRoots(
+      {required List<String> included, required List<String> excluded}) async {
+    var request =
+        AnalysisSetAnalysisRootsParams(included, excluded).toRequest('0');
+    var response = await waitResponse(request);
+    expect(response, isResponseSuccess(request.id));
+  }
+
   /// Stops the associated server.
   void stopServer() {
     server.done();
   }
 
+  /// Completes with a successful [Response] for the given [request].
+  /// Otherwise fails.
+  Future<Response> waitResponse(Request request) async {
+    return serverChannel.sendRequest(request);
+  }
+
   static String _getCodeString(code) {
     if (code is List<String>) {
       code = code.join('\n');
@@ -1620,7 +1628,7 @@
 
   Future<void> test_afterAnalysis() async {
     addTestFile('int V = 42;');
-    createProject();
+    await createProject();
     // wait for analysis, no results initially
     await waitForTasksFinished();
     expect(filesHighlights[testFile], isNull);
@@ -1634,7 +1642,7 @@
   Future<void> test_afterAnalysis_noSuchFile() async {
     var file = convertPath('/no-such-file.dart');
     addTestFile('// no matter');
-    createProject();
+    await createProject();
     // wait for analysis, no results initially
     await waitForTasksFinished();
     expect(filesHighlights[testFile], isNull);
@@ -1658,7 +1666,7 @@
   new A();
 }
 ''');
-    createProject();
+    await createProject();
     // wait for analysis, no results initially
     await waitForTasksFinished();
     expect(filesHighlights[pkgFile], isNull);
@@ -1684,8 +1692,7 @@
 ''');
     // add 'pkgA' and 'pkgB' as projects
     newFolder(projectPath);
-    handleSuccessfulRequest(
-        AnalysisSetAnalysisRootsParams([pkgA, pkgB], []).toRequest('0'));
+    await setRoots(included: [pkgA, pkgB], excluded: []);
     // wait for analysis, no results initially
     await waitForTasksFinished();
     expect(filesHighlights[pkgFileA], isNull);
@@ -1704,7 +1711,7 @@
     newDotPackagesFile('/project', content: 'pkgA:/packages/pkgA/lib');
     //
     addTestFile('// no "pkgA" reference');
-    createProject();
+    await createProject();
     // wait for analysis, no results initially
     await waitForTasksFinished();
     expect(filesHighlights[pkgFile], isNull);
@@ -1720,7 +1727,7 @@
   Future<void> test_afterAnalysis_sdkFile() async {
     var file = convertPath('/sdk/lib/core/core.dart');
     addTestFile('// no matter');
-    createProject();
+    await createProject();
     // wait for analysis, no results initially
     await waitForTasksFinished();
     expect(filesHighlights[file], isNull);
@@ -1733,7 +1740,7 @@
 
   Future<void> test_beforeAnalysis() async {
     addTestFile('int V = 42;');
-    createProject();
+    await createProject();
     // subscribe
     addAnalysisSubscription(AnalysisService.HIGHLIGHTS, testFile);
     // wait for analysis
@@ -1743,7 +1750,7 @@
 
   Future<void> test_sentToPlugins() async {
     addTestFile('int V = 42;');
-    createProject();
+    await createProject();
     // subscribe
     addAnalysisSubscription(AnalysisService.HIGHLIGHTS, testFile);
     // wait for analysis
diff --git a/pkg/analysis_server/test/domain_completion_util.dart b/pkg/analysis_server/test/domain_completion_util.dart
index 8670a6f..9e64bec 100644
--- a/pkg/analysis_server/test/domain_completion_util.dart
+++ b/pkg/analysis_server/test/domain_completion_util.dart
@@ -125,9 +125,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
     handler = CompletionDomainHandler(server);
   }
 
diff --git a/pkg/analysis_server/test/domain_diagnostic_test.dart b/pkg/analysis_server/test/domain_diagnostic_test.dart
index 92ab990..2a354f2 100644
--- a/pkg/analysis_server/test/domain_diagnostic_test.dart
+++ b/pkg/analysis_server/test/domain_diagnostic_test.dart
@@ -29,7 +29,7 @@
     newPubspecYamlFile('/project', 'name: project');
     newFile('/project/bin/test.dart', content: 'main() {}');
 
-    server.setAnalysisRoots('0', [convertPath('/project')], []);
+    await server.setAnalysisRoots('0', [convertPath('/project')], []);
 
     await server.onAnalysisComplete;
 
diff --git a/pkg/analysis_server/test/domain_execution_test.dart b/pkg/analysis_server/test/domain_execution_test.dart
index 7095b0c..d3945a8 100644
--- a/pkg/analysis_server/test/domain_execution_test.dart
+++ b/pkg/analysis_server/test/domain_execution_test.dart
@@ -163,9 +163,9 @@
   late String contextId;
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
     handler = ExecutionDomainHandler(server);
     _createExecutionContext(testFile);
   }
diff --git a/pkg/analysis_server/test/edit/assists_test.dart b/pkg/analysis_server/test/edit/assists_test.dart
index e2cb0dc..d42144e 100644
--- a/pkg/analysis_server/test/edit/assists_test.dart
+++ b/pkg/analysis_server/test/edit/assists_test.dart
@@ -39,9 +39,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
     handler = EditDomainHandler(server);
   }
 
diff --git a/pkg/analysis_server/test/edit/bulk_fixes_test.dart b/pkg/analysis_server/test/edit/bulk_fixes_test.dart
index 5f58bc1..b746b44 100644
--- a/pkg/analysis_server/test/edit/bulk_fixes_test.dart
+++ b/pkg/analysis_server/test/edit/bulk_fixes_test.dart
@@ -52,11 +52,11 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
     registerLintRules();
     handler = EditDomainHandler(server);
-    createProject();
+    await createProject();
   }
 
   Future<void> test_annotateOverrides_excludedFile() async {
diff --git a/pkg/analysis_server/test/edit/fixes_test.dart b/pkg/analysis_server/test/edit/fixes_test.dart
index ff64169..8ffe486 100644
--- a/pkg/analysis_server/test/edit/fixes_test.dart
+++ b/pkg/analysis_server/test/edit/fixes_test.dart
@@ -36,7 +36,7 @@
 
     // Set up the original project, as the code fix code won't run at all
     // if there are no contexts.
-    createProject();
+    await createProject();
     await waitForTasksFinished();
 
     var request =
@@ -49,7 +49,7 @@
   }
 
   Future<void> test_fixUndefinedClass() async {
-    createProject();
+    await createProject();
     addTestFile('''
 main() {
   Completer<String> x = null;
@@ -81,7 +81,7 @@
       info: Future.value(result.toResponse('-', 1))
     };
 
-    createProject();
+    await createProject();
     addTestFile('main() {}');
     await waitForTasksFinished();
     var errorFixes = await _getFixesAt('in(');
@@ -89,7 +89,7 @@
   }
 
   Future<void> test_hasFixes() async {
-    createProject();
+    await createProject();
     addTestFile('''
 foo() {
   print(1)
@@ -134,7 +134,7 @@
   }
 
   Future<void> test_overlayOnlyFile() async {
-    createProject();
+    await createProject();
     testCode = '''
 main() {
 print(1)
@@ -167,10 +167,8 @@
     newFile('/bbb/lib/target.generated.dart', content: 'class Foo() {}');
     newFile('/bbb/lib/target.template.dart', content: 'class Foo() {}');
 
-    handleSuccessfulRequest(
-        AnalysisSetAnalysisRootsParams(
-            [convertPath('/aaa'), convertPath('/bbb')], []).toRequest('0'),
-        handler: analysisHandler);
+    await setRoots(
+        included: [convertPath('/aaa'), convertPath('/bbb')], excluded: []);
 
     // Configure the test file.
     testFile = convertPath('/aaa/main.dart');
diff --git a/pkg/analysis_server/test/edit/format_test.dart b/pkg/analysis_server/test/edit/format_test.dart
index e5576f7..d62a67e 100644
--- a/pkg/analysis_server/test/edit/format_test.dart
+++ b/pkg/analysis_server/test/edit/format_test.dart
@@ -20,9 +20,9 @@
 @reflectiveTest
 class FormatTest extends AbstractAnalysisTest {
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
     handler = EditDomainHandler(server);
   }
 
diff --git a/pkg/analysis_server/test/edit/organize_directives_test.dart b/pkg/analysis_server/test/edit/organize_directives_test.dart
index c18850e..fccfa57 100644
--- a/pkg/analysis_server/test/edit/organize_directives_test.dart
+++ b/pkg/analysis_server/test/edit/organize_directives_test.dart
@@ -22,9 +22,9 @@
   late SourceFileEdit fileEdit;
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
     handler = EditDomainHandler(server);
   }
 
diff --git a/pkg/analysis_server/test/edit/postfix_completion_test.dart b/pkg/analysis_server/test/edit/postfix_completion_test.dart
index 86085b1..0de0e1c 100644
--- a/pkg/analysis_server/test/edit/postfix_completion_test.dart
+++ b/pkg/analysis_server/test/edit/postfix_completion_test.dart
@@ -23,9 +23,9 @@
   late SourceChange change;
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
     handler = EditDomainHandler(server);
   }
 
diff --git a/pkg/analysis_server/test/edit/refactoring_test.dart b/pkg/analysis_server/test/edit/refactoring_test.dart
index bffa9fc..4ae4511 100644
--- a/pkg/analysis_server/test/edit/refactoring_test.dart
+++ b/pkg/analysis_server/test/edit/refactoring_test.dart
@@ -899,9 +899,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
     handler = EditDomainHandler(server);
     server.handlers = [handler];
   }
@@ -2289,9 +2289,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
     handler = EditDomainHandler(server);
     server.handlers = [handler];
   }
diff --git a/pkg/analysis_server/test/edit/sort_members_test.dart b/pkg/analysis_server/test/edit/sort_members_test.dart
index f6e6bd6..4c173d9 100644
--- a/pkg/analysis_server/test/edit/sort_members_test.dart
+++ b/pkg/analysis_server/test/edit/sort_members_test.dart
@@ -22,9 +22,9 @@
   late SourceFileEdit fileEdit;
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
     handler = EditDomainHandler(server);
   }
 
diff --git a/pkg/analysis_server/test/edit/statement_completion_test.dart b/pkg/analysis_server/test/edit/statement_completion_test.dart
index a692a0f..fbbff85 100644
--- a/pkg/analysis_server/test/edit/statement_completion_test.dart
+++ b/pkg/analysis_server/test/edit/statement_completion_test.dart
@@ -22,9 +22,9 @@
   late SourceChange change;
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
     handler = EditDomainHandler(server);
   }
 
diff --git a/pkg/analysis_server/test/integration/analysis/highlights_test.dart b/pkg/analysis_server/test/integration/analysis/highlights_test.dart
index 358e8c8..57c3736 100644
--- a/pkg/analysis_server/test/integration/analysis/highlights_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/highlights_test.dart
@@ -27,6 +27,7 @@
   Future<void> computeHighlights(String pathname, String text) async {
     writeFile(pathname, text);
     standardAnalysisSetup();
+    await analysisFinished;
     sendAnalysisSetSubscriptions({
       AnalysisService.HIGHLIGHTS: [pathname]
     });
diff --git a/pkg/analysis_server/test/integration/completion/get_suggestions_test.dart b/pkg/analysis_server/test/integration/completion/get_suggestions_test.dart
index ff29243..1a95731 100644
--- a/pkg/analysis_server/test/integration/completion/get_suggestions_test.dart
+++ b/pkg/analysis_server/test/integration/completion/get_suggestions_test.dart
@@ -90,10 +90,11 @@
   test.^
 }
 ''');
+    standardAnalysisSetup();
+    await analysisFinished;
     // Create an overlay but do not write the file to "disk"
     //   writeFile(pathname, text);
     // Don't wait for any results except the completion notifications
-    standardAnalysisSetup(subscribeStatus: false);
     sendAnalysisUpdateContent({path: AddContentOverlay(content)});
     sendCompletionGetSuggestions(path, completionOffset);
     var param = await onCompletionResults
@@ -109,7 +110,8 @@
     // Do not write the file to "disk"
     //   writeFile(pathname, text);
     // Don't wait for any results except the completion notifications
-    standardAnalysisSetup(subscribeStatus: false);
+    standardAnalysisSetup();
+    await analysisFinished;
     // Missing file and no overlay
     //sendAnalysisUpdateContent({path: new AddContentOverlay(content)});
     var result = await sendCompletionGetSuggestions(path, 0);
diff --git a/pkg/analysis_server/test/integration/diagnostic/get_diagnostics_test.dart b/pkg/analysis_server/test/integration/diagnostic/get_diagnostics_test.dart
index 84b84ae..0081707 100644
--- a/pkg/analysis_server/test/integration/diagnostic/get_diagnostics_test.dart
+++ b/pkg/analysis_server/test/integration/diagnostic/get_diagnostics_test.dart
@@ -17,6 +17,7 @@
 class GetDiagnosticsTest extends AbstractAnalysisServerIntegrationTest {
   Future<void> test_getDiagnostics() async {
     standardAnalysisSetup();
+    await analysisFinished;
 
     var result = await sendDiagnosticGetDiagnostics();
 
diff --git a/pkg/analysis_server/test/integration/edit/bulk_fixes_test.dart b/pkg/analysis_server/test/integration/edit/bulk_fixes_test.dart
index 4c4d82d..5cdb5ea 100644
--- a/pkg/analysis_server/test/integration/edit/bulk_fixes_test.dart
+++ b/pkg/analysis_server/test/integration/edit/bulk_fixes_test.dart
@@ -43,6 +43,7 @@
 }
 ''');
     standardAnalysisSetup();
+    await analysisFinished;
 
     var result = await sendEditBulkFixes([sourceDirectory.path]);
     expect(result.edits, hasLength(1));
diff --git a/pkg/analysis_server/test/integration/edit/get_fixes_test.dart b/pkg/analysis_server/test/integration/edit/get_fixes_test.dart
index 6610ea2..1c7c608 100644
--- a/pkg/analysis_server/test/integration/edit/get_fixes_test.dart
+++ b/pkg/analysis_server/test/integration/edit/get_fixes_test.dart
@@ -51,6 +51,7 @@
 ''';
     writeFile(pathname, text);
     standardAnalysisSetup();
+    await analysisFinished;
 
     var result = await sendEditGetFixes(pathname, text.indexOf('FutureOr f'));
     expect(result.fixes, isEmpty);
diff --git a/pkg/analysis_server/test/integration/edit/organize_directives_test.dart b/pkg/analysis_server/test/integration/edit/organize_directives_test.dart
index 2bf4c1f..deeeb37 100644
--- a/pkg/analysis_server/test/integration/edit/organize_directives_test.dart
+++ b/pkg/analysis_server/test/integration/edit/organize_directives_test.dart
@@ -26,6 +26,7 @@
 ''';
     writeFile(pathname, text);
     standardAnalysisSetup();
+    await analysisFinished;
 
     var result = await sendEditOrganizeDirectives(pathname);
     var edit = result.edit;
@@ -45,6 +46,7 @@
 ''';
     writeFile(pathname, text);
     standardAnalysisSetup();
+    await analysisFinished;
 
     var result = await sendEditOrganizeDirectives(pathname);
     var edit = result.edit;
@@ -62,6 +64,7 @@
 ''';
     writeFile(pathname, text);
     standardAnalysisSetup();
+    await analysisFinished;
 
     try {
       await sendEditOrganizeDirectives(pathname);
diff --git a/pkg/analysis_server/test/integration/edit/sort_members_test.dart b/pkg/analysis_server/test/integration/edit/sort_members_test.dart
index a49aca3..25ba753 100644
--- a/pkg/analysis_server/test/integration/edit/sort_members_test.dart
+++ b/pkg/analysis_server/test/integration/edit/sort_members_test.dart
@@ -23,6 +23,7 @@
 ''';
     writeFile(pathname, text);
     standardAnalysisSetup();
+    await analysisFinished;
 
     var result = await sendEditSortMembers(pathname);
     var edit = result.edit;
@@ -38,6 +39,7 @@
 ''';
     writeFile(pathname, text);
     standardAnalysisSetup();
+    await analysisFinished;
 
     var result = await sendEditSortMembers(pathname);
     var edit = result.edit;
@@ -52,6 +54,7 @@
 ''';
     writeFile(pathname, text);
     standardAnalysisSetup();
+    await analysisFinished;
 
     try {
       await sendEditSortMembers(pathname);
diff --git a/pkg/analysis_server/test/integration/execution/delete_context_test.dart b/pkg/analysis_server/test/integration/execution/delete_context_test.dart
index 121ba2e..609902d 100644
--- a/pkg/analysis_server/test/integration/execution/delete_context_test.dart
+++ b/pkg/analysis_server/test/integration/execution/delete_context_test.dart
@@ -19,6 +19,7 @@
     var pathname = sourcePath('lib/main.dart');
     writeFile(pathname, '// dummy');
     standardAnalysisSetup();
+    await analysisFinished;
 
     var contextId = (await sendExecutionCreateContext(sourceDirectory.path)).id;
 
diff --git a/pkg/analysis_server/test/integration/execution/map_uri_test.dart b/pkg/analysis_server/test/integration/execution/map_uri_test.dart
index e98032f..4538798 100644
--- a/pkg/analysis_server/test/integration/execution/map_uri_test.dart
+++ b/pkg/analysis_server/test/integration/execution/map_uri_test.dart
@@ -19,6 +19,7 @@
     var pathname = sourcePath('lib/main.dart');
     writeFile(pathname, '// dummy');
     standardAnalysisSetup();
+    await analysisFinished;
 
     var contextId = (await sendExecutionCreateContext(sourceDirectory.path)).id;
 
diff --git a/pkg/analysis_server/test/search/abstract_search_domain.dart b/pkg/analysis_server/test/search/abstract_search_domain.dart
index cba622f..54b8990 100644
--- a/pkg/analysis_server/test/search/abstract_search_domain.dart
+++ b/pkg/analysis_server/test/search/abstract_search_domain.dart
@@ -80,9 +80,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
     server.handlers = [
       SearchDomainHandler(server),
     ];
diff --git a/pkg/analysis_server/test/search/type_hierarchy_test.dart b/pkg/analysis_server/test/search/type_hierarchy_test.dart
index 60d734d..28f9cba 100644
--- a/pkg/analysis_server/test/search/type_hierarchy_test.dart
+++ b/pkg/analysis_server/test/search/type_hierarchy_test.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
+import 'package:analysis_server/src/domain_analysis.dart';
 import 'package:analysis_server/src/search/search_domain.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -21,10 +22,11 @@
   static const String requestId = 'test-getTypeHierarchy';
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
     server.handlers = [
+      AnalysisDomainHandler(server),
       SearchDomainHandler(server),
     ];
   }
@@ -183,9 +185,8 @@
 ''');
     await waitForTasksFinished();
     // configure roots
-    var request = AnalysisSetAnalysisRootsParams(
-        [projectPath, convertPath('/packages/pkgA')], []).toRequest('0');
-    handleSuccessfulRequest(request);
+    await setRoots(
+        included: [projectPath, convertPath('/packages/pkgA')], excluded: []);
     // test A type hierarchy
     var items = await _getTypeHierarchy('A {}');
     var names = _toClassNames(items);
diff --git a/pkg/analysis_server/test/services/completion/dart/relevance/named_argument_test.dart b/pkg/analysis_server/test/services/completion/dart/relevance/named_argument_test.dart
index beb0563..a8a5607 100644
--- a/pkg/analysis_server/test/services/completion/dart/relevance/named_argument_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/relevance/named_argument_test.dart
@@ -17,8 +17,8 @@
 @reflectiveTest
 class NamedArgumentTest extends CompletionRelevanceTest {
   @override
-  void setUp() {
-    super.setUp();
+  Future<void> setUp() async {
+    await super.setUp();
 
     var metaLibFolder = MockPackages.instance.addMeta(resourceProvider);
 
diff --git a/pkg/analysis_server/test/src/domains/completion/available_suggestions_base.dart b/pkg/analysis_server/test/src/domains/completion/available_suggestions_base.dart
index 6172336..25d24d3 100644
--- a/pkg/analysis_server/test/src/domains/completion/available_suggestions_base.dart
+++ b/pkg/analysis_server/test/src/domains/completion/available_suggestions_base.dart
@@ -72,7 +72,7 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
     projectPath = convertPath('/home');
     testFile = convertPath('/home/test/lib/test.dart');
@@ -82,7 +82,7 @@
 test:${toUri('/home/test/lib')}
 ''');
 
-    createProject();
+    await createProject();
     handler = server.handlers.whereType<CompletionDomainHandler>().single;
     _setCompletionSubscriptions([CompletionService.AVAILABLE_SUGGESTION_SETS]);
   }
diff --git a/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart b/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
index 24bd1c3..9c47432 100644
--- a/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
+++ b/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
@@ -78,7 +78,7 @@
     // Force the server to rebuild all contexts, as happens when the file watcher
     // fails on Windows.
     // https://github.com/dart-lang/sdk/issues/44650
-    server.contextManager.refresh();
+    await server.contextManager.refresh();
 
     // Give it time to process the newly scheduled files.
     await pumpEventQueue(times: 5000);
diff --git a/pkg/analysis_server/test/src/domains/flutter/base.dart b/pkg/analysis_server/test/src/domains/flutter/base.dart
index 0ab812c..50d2533 100644
--- a/pkg/analysis_server/test/src/domains/flutter/base.dart
+++ b/pkg/analysis_server/test/src/domains/flutter/base.dart
@@ -38,7 +38,7 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
     projectPath = convertPath('/home');
     testFile = convertPath('/home/test/lib/test.dart');
@@ -50,7 +50,7 @@
 
     _addFlutterPackage();
 
-    createProject();
+    await createProject();
     handler = server.handlers.whereType<FlutterDomainHandler>().single;
   }
 
diff --git a/pkg/analysis_server/test/src/flutter/flutter_outline_notification_test.dart b/pkg/analysis_server/test/src/flutter/flutter_outline_notification_test.dart
index a7e6a4a..25c479b 100644
--- a/pkg/analysis_server/test/src/flutter/flutter_outline_notification_test.dart
+++ b/pkg/analysis_server/test/src/flutter/flutter_outline_notification_test.dart
@@ -65,9 +65,9 @@
   }
 
   @override
-  void setUp() {
+  Future<void> setUp() async {
     super.setUp();
-    createProject();
+    await createProject();
     flutterFolder = MockPackages.instance.addFlutter(resourceProvider);
   }
 
@@ -79,6 +79,9 @@
 analyzer:
   strong-mode: true
 ''');
+    await pumpEventQueue();
+    await server.onAnalysisComplete;
+
     var code = '''
 import 'package:flutter/widgets.dart';
 
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index c0df15a..4d6ca01 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 3.2.0-dev
+* Deprecated `changes` getter in `File` and `Folder`, use `watch()` instead.
+
 ## 3.1.0
 * New internal API for `package:dart_style`.
 * Removed deprecated non-API `MockSdk` class.
diff --git a/pkg/analyzer/lib/file_system/file_system.dart b/pkg/analyzer/lib/file_system/file_system.dart
index 0a2bd5d..d3b6913 100644
--- a/pkg/analyzer/lib/file_system/file_system.dart
+++ b/pkg/analyzer/lib/file_system/file_system.dart
@@ -12,7 +12,13 @@
 
 /// [File]s are leaf [Resource]s which contain data.
 abstract class File implements Resource {
-  /// Watch for changes to this file
+  /// Watch for changes to this file.
+  ///
+  /// File watchers are initialized asynchronously so modifications made for a
+  /// short period after calling this getter may be lost. Use [watch()] to
+  /// obtain the stream in a [Future] that completes once initialization is
+  /// complete.
+  @Deprecated('Use watch() instead')
   Stream<WatchEvent> get changes;
 
   /// Synchronously get the length of the file.
@@ -47,6 +53,11 @@
   /// an exception is thrown.
   File renameSync(String newPath);
 
+  /// Watch for changes to the files inside this folder (and in any nested
+  /// folders, including folders reachable via links).
+  @override
+  ResourceWatcher watch();
+
   /// Synchronously write the given [bytes] to the file. The new content will
   /// replace any existing content.
   ///
@@ -75,6 +86,12 @@
 abstract class Folder implements Resource {
   /// Watch for changes to the files inside this folder (and in any nested
   /// folders, including folders reachable via links).
+  ///
+  /// File watchers are initialized asynchronously so modifications made for a
+  /// short period after calling this getter may be lost. Use [watch()] to
+  /// obtain the stream in a [Future] that completes once initialization is
+  /// complete.
+  @Deprecated('Use watch() instead')
   Stream<WatchEvent> get changes;
 
   /// Return `true` if this folder is a file system root.
@@ -120,6 +137,11 @@
   ///
   /// On I/O errors, this will throw [FileSystemException].
   List<Resource> getChildren();
+
+  /// Watch for changes to the files inside this folder (and in any nested
+  /// folders, including folders reachable via links).
+  @override
+  ResourceWatcher watch();
 }
 
 /// The abstract class [Resource] is an abstraction of file or folder.
@@ -169,6 +191,9 @@
 
   /// Return a Uri representing this resource.
   Uri toUri();
+
+  /// Watch for changes to this resource.
+  ResourceWatcher watch();
 }
 
 /// Instances of the class [ResourceProvider] convert [String] paths into
@@ -205,6 +230,24 @@
   Folder? getStateLocation(String pluginId);
 }
 
+/// Abstraction over a [Watcher] that has a [Future] to indicate when the
+/// watcher is ready.
+///
+/// The [ready] event will not fire until a listener has been set up on
+/// [changes] and the watcher initialization is complete.
+class ResourceWatcher {
+  final Stream<WatchEvent> changes;
+
+  /// An event that fires when the watcher is fully initialized and ready to
+  /// produce events.
+  ///
+  /// This event will not fire until a listener has been set up on [changes] and
+  /// the watcher initialization is complete.
+  final Future<void> ready;
+
+  ResourceWatcher(this.changes, this.ready);
+}
+
 extension FolderExtension on Folder {
   /// Return this folder and all its ancestors.
   Iterable<Folder> get withAncestors sync* {
diff --git a/pkg/analyzer/lib/file_system/memory_file_system.dart b/pkg/analyzer/lib/file_system/memory_file_system.dart
index 21ffb07..ef97f63 100644
--- a/pkg/analyzer/lib/file_system/memory_file_system.dart
+++ b/pkg/analyzer/lib/file_system/memory_file_system.dart
@@ -9,8 +9,9 @@
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/source/source_resource.dart';
+import 'package:meta/meta.dart';
 import 'package:path/path.dart' as pathos;
-import 'package:watcher/watcher.dart';
+import 'package:watcher/watcher.dart' hide Watcher;
 
 /// An in-memory implementation of [ResourceProvider].
 /// Use `/` as a path separator.
@@ -22,8 +23,20 @@
 
   final pathos.Context _pathContext;
 
-  MemoryResourceProvider({pathos.Context? context})
-      : _pathContext = context ??= pathos.style == pathos.Style.windows
+  /// An artificial delay that's waited when initializing watchers.
+  ///
+  /// This allows mirroring how the real fs watcher works, where events may be
+  /// lost between creating the watcher and its `ready` event firing.
+  ///
+  /// Like the real file watcher, the `ready` event also requires a listener
+  /// to be attached before it will fire.
+  @visibleForTesting
+  final Duration? delayWatcherInitialization;
+
+  MemoryResourceProvider({
+    pathos.Context? context,
+    this.delayWatcherInitialization,
+  }) : _pathContext = context ??= pathos.style == pathos.Style.windows
             // On Windows, ensure that the current drive matches
             // the drive inserted by MemoryResourceProvider.convertPath
             // so that packages are mapped to the correct drive
@@ -567,21 +580,7 @@
 
   _MemoryResource(this.provider, this.path);
 
-  Stream<WatchEvent> get changes {
-    StreamController<WatchEvent> streamController =
-        StreamController<WatchEvent>();
-    if (!provider._pathToWatchers.containsKey(path)) {
-      provider._pathToWatchers[path] = <StreamController<WatchEvent>>[];
-    }
-    provider._pathToWatchers[path]!.add(streamController);
-    streamController.done.then((_) {
-      provider._pathToWatchers[path]!.remove(streamController);
-      if (provider._pathToWatchers[path]!.isEmpty) {
-        provider._pathToWatchers.remove(path);
-      }
-    });
-    return streamController.stream;
-  }
+  Stream<WatchEvent> get changes => watch().changes;
 
   @override
   int get hashCode => path.hashCode;
@@ -608,6 +607,52 @@
 
   @override
   Uri toUri() => provider.pathContext.toUri(path);
+
+  /// Watch for changes to the files inside this folder (and in any nested
+  /// folders, including folders reachable via links).
+  ///
+  /// If [provider.delayWatcherInitialization] is not `null`, this method will
+  /// wait for this amount of time before it starts capturing/streaming events
+  /// to simulate the delay that occurs when initializing a real file system
+  /// watcher.
+  @override
+  ResourceWatcher watch() {
+    final streamController = StreamController<WatchEvent>();
+    final ready = Completer<void>();
+
+    /// A helper that sets up the watcher that may be called synchronously
+    /// or delayed, depending on the value of
+    /// [provider.delayWatcherInitialization].
+    void setupWatcher() {
+      if (!provider._pathToWatchers.containsKey(path)) {
+        provider._pathToWatchers[path] = <StreamController<WatchEvent>>[];
+      }
+      provider._pathToWatchers[path]!.add(streamController);
+      streamController.done.then((_) {
+        provider._pathToWatchers[path]!.remove(streamController);
+        if (provider._pathToWatchers[path]!.isEmpty) {
+          provider._pathToWatchers.remove(path);
+        }
+      });
+      ready.complete();
+    }
+
+    final delayWatcherInitialization = provider.delayWatcherInitialization;
+    if (delayWatcherInitialization != null) {
+      // Wrap this inside onListen so that (like the real watcher) it will only
+      // fire after a listener is attached.
+      streamController.onListen = () {
+        Future<void>.delayed(delayWatcherInitialization, () {
+          streamController.onListen = null;
+          setupWatcher();
+        });
+      };
+    } else {
+      setupWatcher();
+    }
+
+    return ResourceWatcher(streamController.stream, ready.future);
+  }
 }
 
 class _ResourceData {}
diff --git a/pkg/analyzer/lib/file_system/overlay_file_system.dart b/pkg/analyzer/lib/file_system/overlay_file_system.dart
index 00d6da8..2fe9521 100644
--- a/pkg/analyzer/lib/file_system/overlay_file_system.dart
+++ b/pkg/analyzer/lib/file_system/overlay_file_system.dart
@@ -123,7 +123,7 @@
       : super(provider, file);
 
   @override
-  Stream<WatchEvent> get changes => _file.changes;
+  Stream<WatchEvent> get changes => watch().changes;
 
   @override
   bool get exists => provider.hasOverlay(path) || _resource.exists;
@@ -204,6 +204,9 @@
   }
 
   @override
+  ResourceWatcher watch() => _file.watch();
+
+  @override
   void writeAsBytesSync(List<int> bytes) {
     writeAsStringSync(String.fromCharCodes(bytes));
   }
@@ -234,7 +237,7 @@
       : super(provider, folder);
 
   @override
-  Stream<WatchEvent> get changes => _folder.changes;
+  Stream<WatchEvent> get changes => watch().changes;
 
   @override
   bool get exists => provider._hasOverlayIn(path) || _resource.exists;
@@ -313,6 +316,9 @@
     }
     return children.values.toList();
   }
+
+  @override
+  ResourceWatcher watch() => _folder.watch();
 }
 
 /// The base class for resources from an [OverlayResourceProvider].
diff --git a/pkg/analyzer/lib/file_system/physical_file_system.dart b/pkg/analyzer/lib/file_system/physical_file_system.dart
index bc4791d..5a2c317 100644
--- a/pkg/analyzer/lib/file_system/physical_file_system.dart
+++ b/pkg/analyzer/lib/file_system/physical_file_system.dart
@@ -97,7 +97,7 @@
   _PhysicalFile(io.File file) : super(file);
 
   @override
-  Stream<WatchEvent> get changes => FileWatcher(_entry.path).events;
+  Stream<WatchEvent> get changes => watch().changes;
 
   @override
   int get lengthSync {
@@ -180,6 +180,12 @@
   Uri toUri() => Uri.file(path);
 
   @override
+  ResourceWatcher watch() {
+    final watcher = FileWatcher(_entry.path);
+    return ResourceWatcher(watcher.events, watcher.ready);
+  }
+
+  @override
   void writeAsBytesSync(List<int> bytes) {
     try {
       _file.writeAsBytesSync(bytes);
@@ -203,14 +209,7 @@
   _PhysicalFolder(io.Directory directory) : super(directory);
 
   @override
-  Stream<WatchEvent> get changes =>
-      DirectoryWatcher(_entry.path).events.handleError((Object error) {},
-          test: (error) =>
-              error is io.FileSystemException &&
-              // Don't suppress "Directory watcher closed," so the outer
-              // listener can see the interruption & act on it.
-              !error.message
-                  .startsWith("Directory watcher closed unexpectedly"));
+  Stream<WatchEvent> get changes => watch().changes;
 
   @override
   bool get isRoot {
@@ -308,6 +307,18 @@
 
   @override
   Uri toUri() => Uri.directory(path);
+
+  @override
+  ResourceWatcher watch() {
+    final watcher = DirectoryWatcher(_entry.path);
+    final events = watcher.events.handleError((Object error) {},
+        test: (error) =>
+            error is io.FileSystemException &&
+            // Don't suppress "Directory watcher closed," so the outer
+            // listener can see the interruption & act on it.
+            !error.message.startsWith("Directory watcher closed unexpectedly"));
+    return ResourceWatcher(events, watcher.ready);
+  }
 }
 
 /// A `dart:io` based implementation of [Resource].
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index d7b4cbe..c6e63d6 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -82,7 +82,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 199;
+  static const int DATA_VERSION = 200;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 81f1366..5bbe3e7 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -2714,7 +2714,13 @@
   bool get isMixinApplication => false;
 
   @override
-  bool get isSimplyBounded => true;
+  bool get isSimplyBounded {
+    return hasModifier(Modifier.SIMPLY_BOUNDED);
+  }
+
+  set isSimplyBounded(bool isSimplyBounded) {
+    setModifier(Modifier.SIMPLY_BOUNDED, isSimplyBounded);
+  }
 
   @override
   bool get isValidMixin => false;
diff --git a/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart b/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart
index c7a1de2..8a93e39 100644
--- a/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart
+++ b/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:collection';
+import 'dart:math' as math;
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
@@ -79,6 +80,27 @@
   }
 
   @override
+  void visitConstructorDeclaration(ConstructorDeclaration node) {
+    var element = node.declaredElement!;
+    var redirectedConstructor = node.redirectedConstructor;
+    if (redirectedConstructor != null) {
+      var redirectedElement = redirectedConstructor.staticElement;
+      if (redirectedElement != null) {
+        // TODO(scheglov) Only if not _isPubliclyAccessible
+        _matchParameters(
+          element.parameters,
+          redirectedElement.parameters,
+          (first, second) {
+            usedElements.addElement(second);
+          },
+        );
+      }
+    }
+
+    super.visitConstructorDeclaration(node);
+  }
+
+  @override
   void visitFunctionDeclaration(FunctionDeclaration node) {
     var enclosingExecOld = _enclosingExec;
     try {
@@ -170,6 +192,10 @@
 
   @override
   void visitSimpleIdentifier(SimpleIdentifier node) {
+    // TODO(scheglov) Remove after https://dart-review.googlesource.com/c/sdk/+/226960
+    if (node.parent is FieldFormalParameter) {
+      return;
+    }
     if (node.inDeclarationContext()) {
       return;
     }
@@ -341,6 +367,51 @@
     // OK
     return true;
   }
+
+  /// Invokes [f] for corresponding positional and named parameters.
+  /// Ignores parameters that don't have a corresponding pair.
+  /// TODO(scheglov) There might be a better place for this function.
+  static void _matchParameters(
+    List<ParameterElement> firstList,
+    List<ParameterElement> secondList,
+    void Function(ParameterElement first, ParameterElement second) f,
+  ) {
+    Map<String, ParameterElement>? firstNamed;
+    Map<String, ParameterElement>? secondNamed;
+    var firstPositional = <ParameterElement>[];
+    var secondPositional = <ParameterElement>[];
+    for (var element in firstList) {
+      if (element.isNamed) {
+        (firstNamed ??= {})[element.name] = element;
+      } else {
+        firstPositional.add(element);
+      }
+    }
+    for (var element in secondList) {
+      if (element.isNamed) {
+        (secondNamed ??= {})[element.name] = element;
+      } else {
+        secondPositional.add(element);
+      }
+    }
+
+    var positionalLength = math.min(
+      firstPositional.length,
+      secondPositional.length,
+    );
+    for (var i = 0; i < positionalLength; i++) {
+      f(firstPositional[i], secondPositional[i]);
+    }
+
+    if (firstNamed != null && secondNamed != null) {
+      for (var firstEntry in firstNamed.entries) {
+        var second = secondNamed[firstEntry.key];
+        if (second != null) {
+          f(firstEntry.value, second);
+        }
+      }
+    }
+  }
 }
 
 /// Instances of the class [UnusedLocalElementsVerifier] traverse an AST
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index d567258..53915eb 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -593,6 +593,7 @@
       offset: resolutionOffset,
     );
     element.setLinkedData(reference, linkedData);
+    EnumElementFlags.read(_reader, element);
 
     element.typeParameters = _readTypeParameters();
 
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index c535cd7..87b340f 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -172,6 +172,7 @@
     element as EnumElementImpl;
     _sink.writeUInt30(_resolutionSink.offset);
     _sink._writeStringReference(element.name);
+    EnumElementFlags.write(_sink, element);
     _resolutionSink._writeAnnotationList(element.metadata);
 
     _writeTypeParameters(element.typeParameters, () {
diff --git a/pkg/analyzer/lib/src/summary2/element_flags.dart b/pkg/analyzer/lib/src/summary2/element_flags.dart
index e79b496..ff4cdbc 100644
--- a/pkg/analyzer/lib/src/summary2/element_flags.dart
+++ b/pkg/analyzer/lib/src/summary2/element_flags.dart
@@ -51,6 +51,21 @@
   }
 }
 
+class EnumElementFlags {
+  static const int _isSimplyBounded = 1 << 0;
+
+  static void read(SummaryDataReader reader, EnumElementImpl element) {
+    var byte = reader.readByte();
+    element.isSimplyBounded = (byte & _isSimplyBounded) != 0;
+  }
+
+  static void write(BufferedSink sink, EnumElementImpl element) {
+    var result = 0;
+    result |= element.isSimplyBounded ? _isSimplyBounded : 0;
+    sink.writeByte(result);
+  }
+}
+
 class FieldElementFlags {
   static const int _hasImplicitType = 1 << 0;
   static const int _hasInitializer = 1 << 1;
diff --git a/pkg/analyzer/lib/src/summary2/simply_bounded.dart b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
index cc9870c..0fe77da 100644
--- a/pkg/analyzer/lib/src/summary2/simply_bounded.dart
+++ b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
@@ -21,6 +21,10 @@
         var node = walker.getNode(element);
         nodes.add(node);
       }
+      for (var element in unit.enums) {
+        var node = walker.getNode(element);
+        nodes.add(node);
+      }
       for (var element in unit.mixins) {
         var node = walker.getNode(element);
         nodes.add(node);
@@ -43,6 +47,9 @@
     } else if (node2 is ClassTypeAlias) {
       var element = node2.declaredElement as ClassElementImpl;
       element.isSimplyBounded = node.isSimplyBounded;
+    } else if (node2 is EnumDeclaration) {
+      var element = node2.declaredElement as EnumElementImpl;
+      element.isSimplyBounded = node.isSimplyBounded;
     } else if (node2 is GenericTypeAlias) {
       var element = node2.declaredElement as TypeAliasElementImpl;
       element.isSimplyBounded = node.isSimplyBounded;
@@ -95,6 +102,14 @@
           parameters ?? const <TypeParameter>[],
           const <TypeAnnotation>[],
         );
+      } else if (node is EnumDeclaration) {
+        var parameters = node.typeParameters?.typeParameters;
+        graphNode = SimplyBoundedNode(
+          this,
+          node,
+          parameters ?? const <TypeParameter>[],
+          const <TypeAnnotation>[],
+        );
       } else if (node is FunctionTypeAlias) {
         var parameters = node.typeParameters?.typeParameters;
         graphNode = SimplyBoundedNode(
diff --git a/pkg/analyzer/test/file_system/memory_file_system_test.dart b/pkg/analyzer/test/file_system/memory_file_system_test.dart
index 873dc18..ffb9e0d 100644
--- a/pkg/analyzer/test/file_system/memory_file_system_test.dart
+++ b/pkg/analyzer/test/file_system/memory_file_system_test.dart
@@ -511,7 +511,7 @@
       String path, Function(List<WatchEvent> changesReceived) test) {
     var folder = provider.getResource(path) as Folder;
     var changesReceived = <WatchEvent>[];
-    folder.changes.listen(changesReceived.add);
+    folder.watch().changes.listen(changesReceived.add);
     return test(changesReceived);
   }
 }
diff --git a/pkg/analyzer/test/file_system/physical_resource_provider_watch_test.dart b/pkg/analyzer/test/file_system/physical_resource_provider_watch_test.dart
index c08137e..08584bd 100644
--- a/pkg/analyzer/test/file_system/physical_resource_provider_watch_test.dart
+++ b/pkg/analyzer/test/file_system/physical_resource_provider_watch_test.dart
@@ -146,7 +146,7 @@
       var file =
           PhysicalResourceProvider.INSTANCE.getResource(filePath) as File;
       var changesReceived = <WatchEvent>[];
-      var subscription = file.changes.listen(changesReceived.add);
+      var subscription = file.watch().changes.listen(changesReceived.add);
       // Delay running the rest of the test to allow file.changes propagate.
       return _delayed(() => test(changesReceived)).whenComplete(() {
         subscription.cancel();
@@ -164,7 +164,7 @@
       var folder =
           PhysicalResourceProvider.INSTANCE.getResource(filePath) as Folder;
       var changesReceived = <WatchEvent>[];
-      var subscription = folder.changes.listen(changesReceived.add);
+      var subscription = folder.watch().changes.listen(changesReceived.add);
       // Delay running the rest of the test to allow folder.changes to
       // take a snapshot of the current directory state.  Otherwise it
       // won't be able to reliably distinguish new files from modified
diff --git a/pkg/analyzer/test/src/diagnostics/unused_element_test.dart b/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
index b9104c2..fb070cc 100644
--- a/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
@@ -1858,6 +1858,98 @@
     expect(result.errors, isNotEmpty);
   }
 
+  test_parameter_optionalNamed_fieldFormal_isUsed_constructorInvocation() async {
+    await assertNoErrorsInCode(r'''
+class _A {
+  final int? f;
+  _A({this.f});
+}
+f() => _A(f: 0);
+''');
+  }
+
+  test_parameter_optionalNamed_fieldFormal_isUsed_factoryRedirect() async {
+    await assertNoErrorsInCode(r'''
+class _A {
+  final int? f;
+  _A({this.f});
+  factory _A.named({int? f}) = _A;
+}
+f() => _A.named(f: 0);
+''');
+  }
+
+  test_parameter_optionalNamed_fieldFormal_notUsed() async {
+    await assertErrorsInCode(r'''
+class _A {
+  final int? f;
+  _A({this.f});
+}
+f() => _A();
+''', [
+      error(HintCode.UNUSED_ELEMENT_PARAMETER, 38, 1),
+    ]);
+  }
+
+  test_parameter_optionalNamed_fieldFormal_notUsed_factoryRedirect() async {
+    await assertErrorsInCode(r'''
+class _A {
+  final int? f;
+  _A({this.f});
+  factory _A.named() = _A;
+}
+f() => _A.named();
+''', [
+      error(HintCode.UNUSED_ELEMENT_PARAMETER, 38, 1),
+    ]);
+  }
+
+  test_parameter_optionalPositional_fieldFormal_isUsed_constructorInvocation() async {
+    await assertNoErrorsInCode(r'''
+class _A {
+  final int? f;
+  _A([this.f]);
+}
+f() => _A(0);
+''');
+  }
+
+  test_parameter_optionalPositional_fieldFormal_isUsed_factoryRedirect() async {
+    await assertNoErrorsInCode(r'''
+class _A {
+  final int? f;
+  _A([this.f]);
+  factory _A.named([int a]) = _A;
+}
+f() => _A.named(0);
+''');
+  }
+
+  test_parameter_optionalPositional_fieldFormal_notUsed() async {
+    await assertErrorsInCode(r'''
+class _A {
+  final int? f;
+  _A([this.f]);
+}
+f() => _A();
+''', [
+      error(HintCode.UNUSED_ELEMENT_PARAMETER, 38, 1),
+    ]);
+  }
+
+  test_parameter_optionalPositional_fieldFormal_notUsed_factoryRedirect() async {
+    await assertErrorsInCode(r'''
+class _A {
+  final int? f;
+  _A([this.f]);
+  factory _A.named() = _A;
+}
+f() => _A.named();
+''', [
+      error(HintCode.UNUSED_ELEMENT_PARAMETER, 38, 1),
+    ]);
+  }
+
   test_typeAlias_interfaceType_isUsed_typeName_isExpression() async {
     await assertNoErrorsInCode(r'''
 typedef _A = List<int>;
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index ac4593d..a61787f 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -17766,7 +17766,7 @@
 library
   definingUnit
     enums
-      enum E @5
+      notSimplyBounded enum E @5
         typeParameters
           covariant T @7
             bound: num
@@ -17850,7 +17850,7 @@
 library
   definingUnit
     enums
-      enum E @5
+      notSimplyBounded enum E @5
         typeParameters
           covariant T @7
             bound: dynamic
@@ -17893,7 +17893,7 @@
 library
   definingUnit
     enums
-      enum E @5
+      notSimplyBounded enum E @5
         typeParameters
           covariant T @7
             bound: dynamic
@@ -17942,7 +17942,7 @@
 library
   definingUnit
     enums
-      enum E @5
+      notSimplyBounded enum E @5
         typeParameters
           covariant T @7
             bound: void Function(E<dynamic>)
diff --git a/pkg/dartdev/lib/src/analysis_server.dart b/pkg/dartdev/lib/src/analysis_server.dart
index 1666afc..970d4a8 100644
--- a/pkg/dartdev/lib/src/analysis_server.dart
+++ b/pkg/dartdev/lib/src/analysis_server.dart
@@ -138,7 +138,7 @@
       }
     });
 
-    _sendCommand('analysis.setAnalysisRoots', params: <String, dynamic>{
+    await _sendCommand('analysis.setAnalysisRoots', params: <String, dynamic>{
       'included': analysisRootPaths,
       'excluded': <String>[]
     });
diff --git a/pkg/expect/lib/config.dart b/pkg/expect/lib/config.dart
new file mode 100644
index 0000000..5229645
--- /dev/null
+++ b/pkg/expect/lib/config.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2012, 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.
+
+/// Access to the runner configuration this test is running in.
+///
+/// Provides queries against and properties of the current configuration
+/// that a test is being compiled and executed in.
+///
+/// This library is separate from `expect.dart` because it uses
+/// `fromEnvironment` constants that cannot be precompiled,
+/// and we precompile `expect.dart`.
+
+library expect_config;
+
+import 'package:smith/smith.dart';
+
+final Configuration _configuration = Configuration.parse(
+    const String.fromEnvironment("test_runner.configuration"),
+    <String, dynamic>{});
+
+bool get isDart2jsConfiguration {
+  return _configuration.compiler == Compiler.dart2js;
+}
+
+bool get isDdcConfiguration {
+  return _configuration.compiler == Compiler.dartdevk ||
+      _configuration.compiler == Compiler.dartdevc;
+}
+
+bool get isVmAotConfiguration {
+  return _configuration.compiler == Compiler.dartkp;
+}
diff --git a/pkg/expect/pubspec.yaml b/pkg/expect/pubspec.yaml
index 70c2817..54c4ad1 100644
--- a/pkg/expect/pubspec.yaml
+++ b/pkg/expect/pubspec.yaml
@@ -13,7 +13,10 @@
 
 dependencies:
   meta: any
+  smith: any
 
 dependency_overrides:
  meta:
   path: ../meta
+ smith:
+  path: ../smith
diff --git a/pkg/modular_test/lib/src/loader.dart b/pkg/modular_test/lib/src/loader.dart
index 9050017..825e679 100644
--- a/pkg/modular_test/lib/src/loader.dart
+++ b/pkg/modular_test/lib/src/loader.dart
@@ -252,6 +252,7 @@
 /// Default entries for a .packages file with paths relative to the SDK root.
 List<int> _defaultPackagesInput = utf8.encode('''
 expect:pkg/expect/lib
+smith:pkg/smith/lib
 async_helper:pkg/async_helper/lib
 meta:pkg/meta/lib
 collection:third_party/pkg/collection/lib
@@ -264,7 +265,8 @@
 // import graph, or adding tests that validate this is always up to date.
 String _defaultPackagesSpec = '''
 dependencies:
-  expect: meta
+  expect: [meta, smith]
+  smith: []
   meta: []
   async_helper: []
   collection: []
diff --git a/pkg/modular_test/test/loader/default_package_dependency_error/expectation.txt b/pkg/modular_test/test/loader/default_package_dependency_error/expectation.txt
index e00a4e2..3f41f4c 100644
--- a/pkg/modular_test/test/loader/default_package_dependency_error/expectation.txt
+++ b/pkg/modular_test/test/loader/default_package_dependency_error/expectation.txt
@@ -4,7 +4,8 @@
   is package? yes
   is shared?  yes
   is sdk?  no
-  dependencies: meta, sdk
+  dependencies: meta, smith, sdk
+  lib/config.dart
   lib/expect.dart
   lib/minitest.dart
 
@@ -31,3 +32,13 @@
   is sdk?  yes
   (no dependencies)
   (sdk sources omitted)
+
+smith
+  is package? yes
+  is shared?  yes
+  is sdk?  no
+  dependencies: sdk
+  lib/builder.dart
+  lib/configuration.dart
+  lib/smith.dart
+  lib/test_matrix.dart
diff --git a/pkg/modular_test/test/loader/valid_packages/expectation.txt b/pkg/modular_test/test/loader/valid_packages/expectation.txt
index e3bfaeb..1274277 100644
--- a/pkg/modular_test/test/loader/valid_packages/expectation.txt
+++ b/pkg/modular_test/test/loader/valid_packages/expectation.txt
@@ -4,7 +4,8 @@
   is package? yes
   is shared?  yes
   is sdk?  no
-  dependencies: meta, sdk
+  dependencies: meta, smith, sdk
+  lib/config.dart
   lib/expect.dart
   lib/minitest.dart
 
@@ -40,3 +41,13 @@
   is sdk?  yes
   (no dependencies)
   (sdk sources omitted)
+
+smith
+  is package? yes
+  is shared?  yes
+  is sdk?  no
+  dependencies: sdk
+  lib/builder.dart
+  lib/configuration.dart
+  lib/smith.dart
+  lib/test_matrix.dart
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index 142b123..c028e33 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -778,7 +778,10 @@
               data['test_server_cross_origin_port'] as int,
           testDriverErrorPort: data["test_driver_error_port"] as int,
           localIP: data["local_ip"] as String,
-          sharedOptions: sharedOptions,
+          sharedOptions: <String>[
+            ...sharedOptions,
+            "-Dtest_runner.configuration=${innerConfiguration.name}"
+          ],
           packages: data["packages"] as String,
           serviceResponseSizesDirectory:
               data['service_response_sizes_directory'] as String,
diff --git a/tests/language/library/env_test.dart b/tests/language/library/env_test.dart
index 9adcf8d..3dc36dd 100644
--- a/tests/language/library/env_test.dart
+++ b/tests/language/library/env_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:expect/expect.dart';
+import 'package:expect/config.dart';
 
 main() {
   const NOT_PRESENT = false;
@@ -61,18 +62,12 @@
         const bool.fromEnvironment("dart.library.io", defaultValue: false));
   }
 
-  bool? hasMirrorSupport;
-  hasMirrorSupport = true; //# has_mirror_support: ok
-  hasMirrorSupport = false; //# has_no_mirror_support: ok
-
-  if (hasMirrorSupport != null) {
-    bool expectedResult = hasMirrorSupport ? true : NOT_PRESENT;
-
-    Expect.equals(
-        expectedResult,
-        const bool.fromEnvironment("dart.library.mirrors",
-            defaultValue: NOT_PRESENT));
-  }
+  bool hasMirrorSupport = !isDart2jsConfiguration &&
+      !isDdcConfiguration && !isVmAotConfiguration;
+  Expect.equals(
+      hasMirrorSupport,
+      const bool.fromEnvironment("dart.library.mirrors",
+          defaultValue: NOT_PRESENT));
 
   Expect.equals(
       NOT_PRESENT,
diff --git a/tests/language_2/library/env_test.dart b/tests/language_2/library/env_test.dart
index 8df205b..34fd5b5 100644
--- a/tests/language_2/library/env_test.dart
+++ b/tests/language_2/library/env_test.dart
@@ -5,6 +5,7 @@
 // @dart = 2.9
 
 import 'package:expect/expect.dart';
+import 'package:expect/config.dart';
 
 main() {
   const NOT_PRESENT = false;
@@ -63,18 +64,12 @@
         const bool.fromEnvironment("dart.library.io", defaultValue: false));
   }
 
-  bool hasMirrorSupport;
-  hasMirrorSupport = true; //# has_mirror_support: ok
-  hasMirrorSupport = false; //# has_no_mirror_support: ok
-
-  if (hasMirrorSupport != null) {
-    bool expectedResult = hasMirrorSupport ? true : NOT_PRESENT;
-
-    Expect.equals(
-        expectedResult,
-        const bool.fromEnvironment("dart.library.mirrors",
-            defaultValue: NOT_PRESENT));
-  }
+  bool hasMirrorSupport = !isDart2jsConfiguration &&
+      !isDdcConfiguration && !isVmAotConfiguration;
+  Expect.equals(
+      hasMirrorSupport,
+      const bool.fromEnvironment("dart.library.mirrors",
+          defaultValue: NOT_PRESENT));
 
   Expect.equals(
       NOT_PRESENT,
diff --git a/tools/VERSION b/tools/VERSION
index b5e4760..bd29315 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 19
+PRERELEASE 20
 PRERELEASE_PATCH 0
\ No newline at end of file