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