| // Copyright (c) 2017, 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 'package:analyzer/dart/element/element.dart'; | |
| import 'package:analyzer/file_system/file_system.dart'; | |
| import 'package:analyzer_plugin/protocol/protocol_common.dart' | |
| hide Element, ElementKind; | |
| import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol; | |
| import 'package:analyzer_plugin/src/utilities/completion/suggestion_builder.dart'; | |
| import 'package:analyzer_plugin/utilities/completion/relevance.dart'; | |
| /// Common mixin for sharing behavior. | |
| mixin ElementSuggestionBuilder { | |
| // Copied from analysis_server/lib/src/services/completion/dart/suggestion_builder.dart | |
| /// A collection of completion suggestions. | |
| final List<CompletionSuggestion> suggestions = <CompletionSuggestion>[]; | |
| /// A set of existing completions used to prevent duplicate suggestions. | |
| final Set<String> _completions = <String>{}; | |
| /// A map of element names to suggestions for synthetic getters and setters. | |
| final Map<String, CompletionSuggestion> _syntheticMap = | |
| <String, CompletionSuggestion>{}; | |
| /// Return the library in which the completion is requested. | |
| LibraryElement? get containingLibrary; | |
| /// Return the kind of suggestions that should be built. | |
| CompletionSuggestionKind? get kind; | |
| /// Return the resource provider used to access the file system. | |
| ResourceProvider? get resourceProvider; | |
| /// Add a suggestion based upon the given element. | |
| void addSuggestion( | |
| Element element, { | |
| String? prefix, | |
| int relevance = DART_RELEVANCE_DEFAULT, | |
| }) { | |
| if (element.isPrivate) { | |
| if (element.library != containingLibrary) { | |
| return; | |
| } | |
| } | |
| var completion = element.displayName; | |
| if (prefix != null && prefix.isNotEmpty) { | |
| if (completion.isEmpty) { | |
| completion = prefix; | |
| } else { | |
| completion = '$prefix.$completion'; | |
| } | |
| } | |
| if (completion.isEmpty) { | |
| return; | |
| } | |
| var builder = SuggestionBuilderImpl(resourceProvider); | |
| var suggestion = builder.forElement( | |
| element, | |
| completion: completion, | |
| kind: kind, | |
| relevance: relevance, | |
| ); | |
| if (suggestion != null) { | |
| if (element is PropertyAccessorElement && element.isOriginVariable) { | |
| var cacheKey = element.name; | |
| if (cacheKey != null) { | |
| var existingSuggestion = _syntheticMap[cacheKey]; | |
| // Pair getter/setter by updating the existing suggestion | |
| if (existingSuggestion != null) { | |
| var getter = element is GetterElement | |
| ? suggestion | |
| : existingSuggestion; | |
| var elemKind = element.enclosingElement is ClassElement | |
| ? protocol.ElementKind.FIELD | |
| : protocol.ElementKind.TOP_LEVEL_VARIABLE; | |
| existingSuggestion.element = protocol.Element( | |
| elemKind, | |
| existingSuggestion.element!.name, | |
| existingSuggestion.element!.flags, | |
| location: getter.element?.location, | |
| typeParameters: getter.element?.typeParameters, | |
| parameters: null, | |
| returnType: getter.returnType, | |
| ); | |
| return; | |
| } | |
| // Cache lone getter/setter so that it can be paired | |
| _syntheticMap[cacheKey] = suggestion; | |
| } | |
| } | |
| if (_completions.add(suggestion.completion)) { | |
| suggestions.add(suggestion); | |
| } | |
| } | |
| } | |
| } |