| // Copyright (c) 2014, 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. |
| |
| import 'dart:async'; |
| |
| import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart'; |
| import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart'; |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| |
| import '../../../protocol_server.dart' |
| show CompletionSuggestion, CompletionSuggestionKind; |
| |
| /// A contributor that produces suggestions based on the members of a library |
| /// when the library was imported using a prefix. More concretely, this class |
| /// produces suggestions for expressions of the form `p.^`, where `p` is a |
| /// prefix. |
| class LibraryMemberContributor extends DartCompletionContributor { |
| @override |
| Future<List<CompletionSuggestion>> computeSuggestions( |
| DartCompletionRequest request, SuggestionBuilder builder) async { |
| // Determine if the target looks like a library prefix. |
| var targetId = request.dotTarget; |
| if (targetId is SimpleIdentifier && !request.target.isCascade) { |
| var elem = targetId.staticElement; |
| if (elem is PrefixElement && !elem.isSynthetic) { |
| var containingLibrary = request.libraryElement; |
| // Gracefully degrade if the library or directives could not be |
| // determined (e.g. detached part file or source change). |
| if (containingLibrary != null) { |
| var imports = containingLibrary.imports; |
| if (imports != null) { |
| return _buildSuggestions(request, elem, imports); |
| } |
| } |
| } |
| } |
| return const <CompletionSuggestion>[]; |
| } |
| |
| List<CompletionSuggestion> _buildSuggestions(DartCompletionRequest request, |
| PrefixElement elem, List<ImportElement> imports) { |
| var parent = request.target.containingNode.parent; |
| var isConstructor = parent.parent is ConstructorName; |
| var typesOnly = parent is TypeName; |
| var instCreation = typesOnly && isConstructor; |
| var builder = LibraryElementSuggestionBuilder( |
| request, CompletionSuggestionKind.INVOCATION, typesOnly, instCreation); |
| for (var importElem in imports) { |
| if (importElem.prefix?.name == elem.name) { |
| var library = importElem.importedLibrary; |
| if (library != null) { |
| // Suggest elements from the imported library. |
| for (var element in importElem.namespace.definedNames.values) { |
| element.accept(builder); |
| } |
| // If the import is 'deferred' then suggest 'loadLibrary'. |
| if (importElem.isDeferred) { |
| var function = library.loadLibraryFunction; |
| var useNewRelevance = request.useNewRelevance; |
| var relevance = useNewRelevance |
| ? Relevance.loadLibrary |
| : DART_RELEVANCE_DEFAULT; |
| builder.suggestions.add(createSuggestion(request, function, |
| relevance: relevance, useNewRelevance: useNewRelevance)); |
| } |
| } |
| } |
| } |
| return builder.suggestions; |
| } |
| } |