22// for details. All rights reserved. Use of this source code is governed by a
33// BSD-style license that can be found in the LICENSE file.
44
5+ import 'dart:collection' ;
6+
57import 'package:analysis_server/src/protocol_server.dart' as protocol;
68import 'package:analysis_server/src/protocol_server.dart'
79 hide Element, ElementKind;
@@ -12,6 +14,8 @@ import 'package:analyzer/dart/element/type.dart';
1214import 'package:analyzer/dart/element/visitor.dart' ;
1315import 'package:analyzer/src/util/comment.dart' ;
1416
17+ import '../../../protocol_server.dart' show CompletionSuggestion;
18+
1519/**
1620 * Return a suggestion based upon the given element or `null` if a suggestion
1721 * is not appropriate for the given element.
@@ -238,3 +242,124 @@ class LibraryElementSuggestionBuilder extends SimpleElementVisitor
238242 }
239243 }
240244}
245+
246+ /**
247+ * This class provides suggestions based upon the visible instance members in
248+ * an interface type.
249+ */
250+ class MemberSuggestionBuilder {
251+ /**
252+ * Enumerated value indicating that we have not generated any completions for
253+ * a given identifier yet.
254+ */
255+ static const int _COMPLETION_TYPE_NONE = 0 ;
256+
257+ /**
258+ * Enumerated value indicating that we have generated a completion for a
259+ * getter.
260+ */
261+ static const int _COMPLETION_TYPE_GETTER = 1 ;
262+
263+ /**
264+ * Enumerated value indicating that we have generated a completion for a
265+ * setter.
266+ */
267+ static const int _COMPLETION_TYPE_SETTER = 2 ;
268+
269+ /**
270+ * Enumerated value indicating that we have generated a completion for a
271+ * field, a method, or a getter/setter pair.
272+ */
273+ static const int _COMPLETION_TYPE_FIELD_OR_METHOD_OR_GETSET = 3 ;
274+
275+ /**
276+ * The library containing the unit in which the completion is requested.
277+ */
278+ final LibraryElement containingLibrary;
279+
280+ /**
281+ * Map indicating, for each possible completion identifier, whether we have
282+ * already generated completions for a getter, setter, or both. The "both"
283+ * case also handles the case where have generated a completion for a method
284+ * or a field.
285+ *
286+ * Note: the enumerated values stored in this map are intended to be bitwise
287+ * compared.
288+ */
289+ final Map <String , int > _completionTypesGenerated = new HashMap <String , int >();
290+
291+ /**
292+ * Map from completion identifier to completion suggestion
293+ */
294+ final Map <String , CompletionSuggestion > _suggestionMap =
295+ < String , CompletionSuggestion > {};
296+
297+ MemberSuggestionBuilder (this .containingLibrary);
298+
299+ Iterable <CompletionSuggestion > get suggestions => _suggestionMap.values;
300+
301+ /**
302+ * Add a suggestion based upon the given element, provided that it is not
303+ * shadowed by a previously added suggestion.
304+ */
305+ void addSuggestion (Element element,
306+ {int relevance = DART_RELEVANCE_DEFAULT }) {
307+ if (element.isPrivate) {
308+ if (element.library != containingLibrary) {
309+ // Do not suggest private members for imported libraries
310+ return ;
311+ }
312+ }
313+ String identifier = element.displayName;
314+
315+ if (relevance == DART_RELEVANCE_DEFAULT && identifier != null ) {
316+ // Decrease relevance of suggestions starting with $
317+ // https://github.com/dart-lang/sdk/issues/27303
318+ if (identifier.startsWith (r'$' )) {
319+ relevance = DART_RELEVANCE_LOW ;
320+ }
321+ }
322+
323+ int alreadyGenerated = _completionTypesGenerated.putIfAbsent (
324+ identifier, () => _COMPLETION_TYPE_NONE );
325+ if (element is MethodElement ) {
326+ // Anything shadows a method.
327+ if (alreadyGenerated != _COMPLETION_TYPE_NONE ) {
328+ return ;
329+ }
330+ _completionTypesGenerated[identifier] =
331+ _COMPLETION_TYPE_FIELD_OR_METHOD_OR_GETSET ;
332+ } else if (element is PropertyAccessorElement ) {
333+ if (element.isGetter) {
334+ // Getters, fields, and methods shadow a getter.
335+ if ((alreadyGenerated & _COMPLETION_TYPE_GETTER ) != 0 ) {
336+ return ;
337+ }
338+ _completionTypesGenerated[identifier] | = _COMPLETION_TYPE_GETTER ;
339+ } else {
340+ // Setters, fields, and methods shadow a setter.
341+ if ((alreadyGenerated & _COMPLETION_TYPE_SETTER ) != 0 ) {
342+ return ;
343+ }
344+ _completionTypesGenerated[identifier] | = _COMPLETION_TYPE_SETTER ;
345+ }
346+ } else if (element is FieldElement ) {
347+ // Fields and methods shadow a field. A getter/setter pair shadows a
348+ // field, but a getter or setter by itself doesn't.
349+ if (alreadyGenerated == _COMPLETION_TYPE_FIELD_OR_METHOD_OR_GETSET ) {
350+ return ;
351+ }
352+ _completionTypesGenerated[identifier] =
353+ _COMPLETION_TYPE_FIELD_OR_METHOD_OR_GETSET ;
354+ } else {
355+ // Unexpected element type; skip it.
356+ assert (false );
357+ return ;
358+ }
359+ CompletionSuggestion suggestion =
360+ createSuggestion (element, relevance: relevance);
361+ if (suggestion != null ) {
362+ _suggestionMap[suggestion.completion] = suggestion;
363+ }
364+ }
365+ }
0 commit comments