| // Copyright (c) 2023, 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:analysis_server/src/services/completion/dart/candidate_suggestion.dart'; |
| import 'package:analysis_server/src/services/completion/dart/completion_state.dart'; |
| import 'package:analysis_server/src/services/completion/dart/suggestion_collector.dart'; |
| import 'package:analyzer/dart/ast/ast.dart'; |
| |
| /// A helper class that produces candidate suggestions for all of the labels |
| /// that are in scope at the completion location. |
| class LabelHelper { |
| /// The suggestion collector to which suggestions will be added. |
| final SuggestionCollector collector; |
| |
| /// The state used to compute the candidate suggestions. |
| final CompletionState state; |
| |
| /// Initialize a newly created helper to add suggestions to the [collector]. |
| LabelHelper({required this.collector, required this.state}); |
| |
| /// Add the labels that are visible at the `break` or `continue` [statement]. |
| void addLabels(Statement statement) { |
| var includeCaseLabels = statement is ContinueStatement; |
| AstNode? currentNode = statement; |
| while (currentNode != null) { |
| switch (currentNode) { |
| case SwitchStatement(): |
| if (includeCaseLabels) { |
| for (var member in currentNode.members) { |
| _visitLabels(member.labels); |
| } |
| } |
| case FunctionBody(): |
| return; |
| case LabeledStatement(): |
| _visitLabels(currentNode.labels); |
| } |
| currentNode = currentNode.parent; |
| } |
| } |
| |
| void _visitLabels(NodeList<Label> labels) { |
| for (var label in labels) { |
| var matcherScore = state.matcher.score(label.label.name); |
| if (matcherScore != -1) { |
| var suggestion = |
| LabelSuggestion(label: label, matcherScore: matcherScore); |
| collector.addSuggestion(suggestion); |
| } |
| } |
| } |
| } |