Issue 32849. Use export namespace for import prefix and combinator completions.

R=brianwilkerson@google.com

Closes https://github.com/dart-lang/sdk/issues/32849
Change-Id: I43621a1c917095fab6be1f1798ea8596f7c3a173
Reviewed-on: https://dart-review.googlesource.com/53863
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/combinator_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/combinator_contributor.dart
index 4d30f30..2914658 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/combinator_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/combinator_contributor.dart
@@ -32,7 +32,9 @@
         LibraryElementSuggestionBuilder builder =
             new LibraryElementSuggestionBuilder(request.libraryElement,
                 CompletionSuggestionKind.IDENTIFIER, false, false);
-        library.visitChildren(builder);
+        for (var element in library.exportNamespace.definedNames.values) {
+          element.accept(builder);
+        }
         return builder.suggestions;
       }
     }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
index 078959a..1e3c378 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
@@ -57,7 +57,9 @@
           LibraryElementSuggestionBuilder builder =
               new LibraryElementSuggestionBuilder(containingLibrary,
                   CompletionSuggestionKind.INVOCATION, typesOnly, instCreation);
-          library.visitChildren(builder);
+          for (var element in library.exportNamespace.definedNames.values) {
+            element.accept(builder);
+          }
           suggestions.addAll(builder.suggestions);
 
           // If the import is 'deferred' then suggest 'loadLibrary'
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index 909345c..7c88a82 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -211,21 +211,15 @@
 }
 
 /**
- * This class visits elements in a library and provides suggestions based upon
- * the visible members in that library.
+ * This class creates suggestions based upon top-level elements.
  */
-class LibraryElementSuggestionBuilder extends GeneralizingElementVisitor
+class LibraryElementSuggestionBuilder extends SimpleElementVisitor
     with ElementSuggestionBuilder {
   final LibraryElement containingLibrary;
   final CompletionSuggestionKind kind;
   final bool typesOnly;
   final bool instCreation;
 
-  /**
-   * The set of libraries that have been, or are currently being, visited.
-   */
-  final Set<LibraryElement> visitedLibraries = new Set<LibraryElement>();
-
   LibraryElementSuggestionBuilder(
       this.containingLibrary, this.kind, this.typesOnly, this.instCreation);
 
@@ -239,17 +233,6 @@
   }
 
   @override
-  visitCompilationUnitElement(CompilationUnitElement element) {
-    element.visitChildren(this);
-    LibraryElement containingLibrary = element.library;
-    if (containingLibrary != null) {
-      for (var lib in containingLibrary.exportedLibraries) {
-        lib.accept(this);
-      }
-    }
-  }
-
-  @override
   visitConstructorElement(ConstructorElement element) {
     if (instCreation) {
       ClassElement classElem = element.enclosingElement;
@@ -263,11 +246,6 @@
   }
 
   @override
-  visitElement(Element element) {
-    // ignored
-  }
-
-  @override
   visitFunctionElement(FunctionElement element) {
     if (!typesOnly) {
       int relevance = element.library == containingLibrary
@@ -285,19 +263,13 @@
   }
 
   @override
-  visitLibraryElement(LibraryElement element) {
-    if (visitedLibraries.add(element)) {
-      element.visitChildren(this);
-    }
-  }
-
-  @override
-  visitTopLevelVariableElement(TopLevelVariableElement element) {
+  visitPropertyAccessorElement(PropertyAccessorElement element) {
     if (!typesOnly) {
-      int relevance = element.library == containingLibrary
+      PropertyInducingElement variable = element.variable;
+      int relevance = variable.library == containingLibrary
           ? DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE
           : DART_RELEVANCE_DEFAULT;
-      addSuggestion(element, relevance: relevance);
+      addSuggestion(variable, relevance: relevance);
     }
   }
 }
diff --git a/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart
index 2aa2825..ac4c454 100644
--- a/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart
@@ -123,6 +123,24 @@
     assertNotSuggested('Object');
   }
 
+  test_Combinator_show_export_withShow() async {
+    addSource('/a.dart', r'''
+class A {}
+class B {}
+''');
+    addSource('/b.dart', r'''
+export 'a.dart' show A;
+''');
+    addTestSource(r'''
+import 'b.dart' show ^;
+''');
+    await computeSuggestions();
+    assertSuggestClass('A',
+        relevance: DART_RELEVANCE_DEFAULT,
+        kind: CompletionSuggestionKind.IDENTIFIER);
+    assertNotSuggested('B');
+  }
+
   test_Combinator_show_PI() async {
     addTestSource('import "dart:math" show ^;');
     await computeSuggestions();
diff --git a/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
index 9679580..d190e7e 100644
--- a/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
@@ -142,6 +142,45 @@
     assertNotSuggested('==');
   }
 
+  test_PrefixedIdentifier_library_export_withShow() async {
+    addSource('/a.dart', r'''
+class A {}
+class B {}
+''');
+    addSource('/b.dart', r'''
+export 'a.dart' show A;
+''');
+    addTestSource(r'''
+import 'b.dart' as p;
+main() {
+  p.^
+}
+''');
+    await computeSuggestions();
+    assertSuggestClass('A');
+    assertNotSuggested('B');
+  }
+
+  @failingTest
+  test_PrefixedIdentifier_library_import_withShow() async {
+    // As it is designed now, I think we should not suggest B.
+    // However an alternative design could be suggesting it, but updating show.
+    // This could be a part of project-wide suggesting and auto-importing.
+    addSource('/a.dart', r'''
+class A {}
+class B {}
+''');
+    addTestSource(r'''
+import 'a.dart' as p show A;
+main() {
+  p.^
+}
+''');
+    await computeSuggestions();
+    assertSuggestClass('A');
+    assertNotSuggested('B');
+  }
+
   test_PrefixedIdentifier_library_inPart() async {
     // SimpleIdentifier  PrefixedIdentifier  ExpressionStatement
     var libFile = '${testFile.substring(0, testFile.length - 5)}A.dart';