From d976ce5b134a3bcd6907b04d90ea32bb597474f4 Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Tue, 5 Mar 2024 21:24:32 +0000 Subject: [PATCH] Completion. Issue 54231. Fix suggesting through import prefix, when there is another identifier after it. Bug: https://github.com/dart-lang/sdk/issues/54231 Change-Id: I06a5eb3763814fde99e2e2ba583679cc27c1a4b6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/355546 Reviewed-by: Brian Wilkerson Commit-Queue: Konstantin Shcheglov --- .../completion/dart/declaration_helper.dart | 16 ++++++++++++ .../dart/in_scope_completion_pass.dart | 16 ++++++++++++ .../property_access_expression_test.dart | 25 +++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart b/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart index 3ce86a005b4..a654a33529f 100644 --- a/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart +++ b/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart @@ -133,6 +133,22 @@ class DeclarationHelper { } } + /// Add suggestions for declarations through [prefixElement]. + void addDeclarationsThroughImportPrefix(PrefixElement prefixElement) { + for (var importElement in prefixElement.imports) { + var importedLibrary = importElement.importedLibrary; + if (importedLibrary == null) { + continue; + } + + _addDeclarationsImportedFrom( + library: importedLibrary, + namespace: importElement.namespace, + prefix: null, + ); + } + } + /// Add any fields that can be initialized in the initializer list of the /// given [constructor]. If a [fieldToInclude] is provided, then it should not /// be skipped because the cursor is inside that field's name. diff --git a/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart b/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart index dd52f627381..135c1b789ea 100644 --- a/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart +++ b/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart @@ -1525,6 +1525,22 @@ class InScopeCompletionPass extends SimpleAstVisitor { @override void visitNamedType(NamedType node) { + var importPrefix = node.importPrefix; + var prefixElement = importPrefix?.element; + + // `prefix.x^ print(0);` is recovered as `prefix.x print; (0);`. + if (prefixElement is PrefixElement) { + if (node.parent case VariableDeclarationList variableList) { + if (variableList.parent case VariableDeclarationStatement statement) { + if (statement.semicolon.isSynthetic) { + declarationHelper() + .addDeclarationsThroughImportPrefix(prefixElement); + return; + } + } + } + } + _forTypeAnnotation(node); } diff --git a/pkg/analysis_server/test/services/completion/dart/location/property_access_expression_test.dart b/pkg/analysis_server/test/services/completion/dart/location/property_access_expression_test.dart index 4bfee6799c7..79a792dcf60 100644 --- a/pkg/analysis_server/test/services/completion/dart/location/property_access_expression_test.dart +++ b/pkg/analysis_server/test/services/completion/dart/location/property_access_expression_test.dart @@ -55,6 +55,31 @@ suggestions '''); } + Future test_afterIdentifier_beforeIdentifier_partial() async { + newFile('$testPackageLibPath/a.dart', r''' +void v01() {} +void g01() {} +'''); + + // There should be no `void`, we use `v` to verify this. + await computeSuggestions(''' +import 'a.dart' as prefix; + +void f() { + prefix.v^ + print(0); +} +'''); + + assertResponse(r''' +replacement + left: 1 +suggestions + v01 + kind: functionInvocation +'''); + } + Future test_afterIdentifier_partial() async { await computeSuggestions(''' class A { foo() {bar.as^}}