Abort not-yet-imported suggestions on a new completion request.
Change-Id: Id08b7ca328253ea5190038d2204cbfb2015aac01
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/218541
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 85c3ac9..9936e74 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -97,13 +97,9 @@
librariesToImport: librariesToImport,
);
- try {
- suggestions.addAll(
- await manager.computeSuggestions(request, performance),
- );
- } on AbortCompletion {
- suggestions.clear();
- }
+ suggestions.addAll(
+ await manager.computeSuggestions(request, performance),
+ );
});
// TODO (danrubel) if request is obsolete (processAnalysisRequest returns
// false) then send empty results
@@ -261,14 +257,28 @@
),
documentationCache: server.getDocumentationCacheFor(resolvedUnit),
);
+ setNewRequest(completionRequest);
var librariesToImport = <Uri>[];
- var suggestions = await computeSuggestions(
- budget: budget,
- performance: performance,
- request: completionRequest,
- librariesToImport: librariesToImport,
- );
+ var suggestions = <CompletionSuggestion>[];
+ try {
+ suggestions = await computeSuggestions(
+ budget: budget,
+ performance: performance,
+ request: completionRequest,
+ librariesToImport: librariesToImport,
+ );
+ } on AbortCompletion {
+ return server.sendResponse(
+ CompletionGetSuggestions2Result(
+ completionRequest.replacementOffset,
+ completionRequest.replacementLength,
+ [],
+ [],
+ true,
+ ).toResponse(request.id),
+ );
+ }
performance.run('filter', (performance) {
performance.getDataInt('count').add(suggestions.length);
@@ -436,14 +446,19 @@
// Compute suggestions in the background
try {
- var suggestions = await computeSuggestions(
- budget: budget,
- performance: perf,
- request: completionRequest,
- includedElementKinds: includedElementKinds,
- includedElementNames: includedElementNames,
- includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
- );
+ var suggestions = <CompletionSuggestion>[];
+ try {
+ suggestions = await computeSuggestions(
+ budget: budget,
+ performance: perf,
+ request: completionRequest,
+ includedElementKinds: includedElementKinds,
+ includedElementNames: includedElementNames,
+ includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
+ );
+ } on AbortCompletion {
+ // Continue with empty suggestions list.
+ }
String? libraryFile;
var includedSuggestionSets = <IncludedSuggestionSet>[];
if (includedElementKinds != null && includedElementNames != null) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart
index 4fba896..938228c 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart
@@ -16,9 +16,14 @@
import 'package:analyzer/src/lint/pub.dart';
import 'package:analyzer/src/workspace/pub.dart';
import 'package:collection/collection.dart';
+import 'package:meta/meta.dart';
/// A contributor of suggestions from not yet imported libraries.
class NotImportedContributor extends DartCompletionContributor {
+ /// Tests set this function to abort the current request.
+ @visibleForTesting
+ static void Function(FileState)? onFile;
+
final CompletionBudget budget;
final List<Uri> librariesToImport;
@@ -49,6 +54,9 @@
var knownFiles = fsState.knownFiles.toList();
for (var file in knownFiles) {
+ onFile?.call(file);
+ request.checkAborted();
+
if (budget.isEmpty) {
return;
}
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index ca7daef..5021221 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'dart:async';
+
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/domain_analysis.dart';
import 'package:analysis_server/src/domain_completion.dart';
@@ -9,6 +11,7 @@
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
+import 'package:analysis_server/src/services/completion/dart/not_imported_contributor.dart';
import 'package:analysis_server/src/utilities/mocks.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/instrumentation/service.dart';
@@ -95,6 +98,42 @@
completionDomain.budgetDuration = const Duration(seconds: 30);
}
+ void tearDown() {
+ NotImportedContributor.onFile = null;
+ }
+
+ Future<void> test_notImported_abort() async {
+ await _configureWithWorkspaceRoot();
+
+ NotImportedContributor.onFile = (file) {
+ if (file.uriStr == 'dart:math') {
+ unawaited(
+ _getSuggestions(
+ path: convertPath(testFilePath),
+ completionOffset: 0,
+ maxResults: 100,
+ ),
+ );
+ }
+ };
+
+ var responseValidator = await _getTestCodeSuggestions('''
+void f() {
+ Rand^
+}
+''');
+
+ responseValidator
+ ..assertIncomplete()
+ ..assertReplacementBack(4)
+ ..assertLibrariesToImport(includes: [], excludes: [
+ 'dart:core',
+ 'dart:math',
+ ]);
+
+ responseValidator.suggestions.assertEmpty();
+ }
+
Future<void> test_notImported_emptyBudget() async {
await _configureWithWorkspaceRoot();