[Analyzer] Enable code completion for YAML files in LSP

Change-Id: I13a6fe43f7b822b9c88fd0e1ca69091f82d70119
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/173000
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Danny Tuppeny <danny@tuppeny.com>
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 98e3a03..0aafdda 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -20,6 +20,7 @@
 import 'package:analysis_server/src/services/completion/yaml/analysis_options_generator.dart';
 import 'package:analysis_server/src/services/completion/yaml/fix_data_generator.dart';
 import 'package:analysis_server/src/services/completion/yaml/pubspec_generator.dart';
+import 'package:analysis_server/src/services/completion/yaml/yaml_completion_generator.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/exception/exception.dart';
@@ -150,7 +151,7 @@
 
   /// Return the suggestions that should be presented in the YAML [file] at the
   /// given [offset].
-  List<CompletionSuggestion> computeYamlSuggestions(String file, int offset) {
+  YamlCompletionResults computeYamlSuggestions(String file, int offset) {
     var provider = server.resourceProvider;
     if (AnalysisEngine.isAnalysisOptionsFileName(file)) {
       var generator = AnalysisOptionsGenerator(provider);
@@ -164,7 +165,7 @@
       var generator = FixDataGenerator(provider);
       return generator.getSuggestions(file, offset);
     }
-    return <CompletionSuggestion>[];
+    return const YamlCompletionResults.empty();
   }
 
   /// Process a `completion.getSuggestionDetails` request.
@@ -325,11 +326,12 @@
         server.sendResponse(CompletionGetSuggestionsResult(completionId)
             .toResponse(request.id));
         // Send a notification with results.
+        final suggestions = computeYamlSuggestions(file, offset);
         sendCompletionNotification(
           completionId,
-          0, // replacementOffset
-          0, // replacementLength,
-          computeYamlSuggestions(file, offset),
+          suggestions.replacementOffset,
+          suggestions.replacementLength,
+          suggestions.suggestions,
           null,
           null,
           null,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index 88c5e97..c0b5988 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -16,8 +16,13 @@
 import 'package:analysis_server/src/services/completion/completion_performance.dart';
 import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
 import 'package:analysis_server/src/services/completion/filtering/fuzzy_matcher.dart';
+import 'package:analysis_server/src/services/completion/yaml/analysis_options_generator.dart';
+import 'package:analysis_server/src/services/completion/yaml/fix_data_generator.dart';
+import 'package:analysis_server/src/services/completion/yaml/pubspec_generator.dart';
+import 'package:analysis_server/src/services/completion/yaml/yaml_completion_generator.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/source/line_info.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/services/available_declarations.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
@@ -89,18 +94,47 @@
         await lineInfo.mapResult((lineInfo) => toOffset(lineInfo, pos));
 
     return offset.mapResult((offset) async {
-      // For server results we need a valid unit, but if we don't have one
-      // we shouldn't consider this an error when merging with plugin results.
-      final serverResultsFuture = unit.isError
-          ? Future.value(success(const <CompletionItem>[]))
-          : _getServerItems(
-              completionCapabilities,
-              clientSupportedCompletionKinds,
-              includeSuggestionSets,
-              unit.result,
-              offset,
-              token,
-            );
+      Future<ErrorOr<List<CompletionItem>>> serverResultsFuture;
+      final pathContext = server.resourceProvider.pathContext;
+      final filename = pathContext.basename(path.result);
+      final fileExtension = pathContext.extension(path.result);
+
+      if (fileExtension == '.dart' && !unit.isError) {
+        serverResultsFuture = _getServerDartItems(
+          completionCapabilities,
+          clientSupportedCompletionKinds,
+          includeSuggestionSets,
+          unit.result,
+          offset,
+          token,
+        );
+      } else if (fileExtension == '.yaml') {
+        YamlCompletionGenerator generator;
+        switch (filename) {
+          case AnalysisEngine.PUBSPEC_YAML_FILE:
+            generator = PubspecGenerator(server.resourceProvider);
+            break;
+          case AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE:
+            generator = AnalysisOptionsGenerator(server.resourceProvider);
+            break;
+          case AnalysisEngine.FIX_DATA_FILE:
+            generator = FixDataGenerator(server.resourceProvider);
+            break;
+        }
+        if (generator != null) {
+          serverResultsFuture = _getServerYamlItems(
+            generator,
+            completionCapabilities,
+            clientSupportedCompletionKinds,
+            path.result,
+            lineInfo.result,
+            offset,
+            token,
+          );
+        }
+      }
+
+      serverResultsFuture ??= Future.value(success(const <CompletionItem>[]));
 
       final pluginResultsFuture = _getPluginResults(completionCapabilities,
           clientSupportedCompletionKinds, lineInfo.result, path.result, offset);
@@ -175,7 +209,7 @@
     ).toList());
   }
 
-  Future<ErrorOr<List<CompletionItem>>> _getServerItems(
+  Future<ErrorOr<List<CompletionItem>>> _getServerDartItems(
     CompletionClientCapabilities completionCapabilities,
     HashSet<CompletionItemKind> clientSupportedCompletionKinds,
     bool includeSuggestionSets,
@@ -355,6 +389,33 @@
     });
   }
 
+  Future<ErrorOr<List<CompletionItem>>> _getServerYamlItems(
+    YamlCompletionGenerator generator,
+    CompletionClientCapabilities completionCapabilities,
+    HashSet<CompletionItemKind> clientSupportedCompletionKinds,
+    String path,
+    LineInfo lineInfo,
+    int offset,
+    CancellationToken token,
+  ) async {
+    final suggestions = generator.getSuggestions(path, offset);
+    final completionItems = suggestions.suggestions
+        .map(
+          (item) => toCompletionItem(
+            completionCapabilities,
+            clientSupportedCompletionKinds,
+            lineInfo,
+            item,
+            suggestions.replacementOffset,
+            suggestions.replacementLength,
+            includeCommitCharacters: false,
+            completeFunctionCalls: false,
+          ),
+        )
+        .toList();
+    return success(completionItems);
+  }
+
   Iterable<CompletionItem> _pluginResultsToItems(
     CompletionClientCapabilities completionCapabilities,
     HashSet<CompletionItemKind> clientSupportedCompletionKinds,
diff --git a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
index fe82284..08e8739 100644
--- a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
+++ b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
@@ -242,15 +242,25 @@
         // folders as well.
         .map((glob) => DocumentFilter(scheme: 'file', pattern: '**/$glob'));
 
-    final allTypes = {dartFiles, ...pluginTypes}.toList();
+    final fullySupportedTypes = {dartFiles, ...pluginTypes}.toList();
 
     // Add pubspec + analysis options only for synchronisation. We do not support
     // things like hovers/formatting/etc. for these files so there's no point
     // in having the client send those requests (plus, for things like formatting
     // this could result in the editor reporting "multiple formatters installed"
     // and prevent a built-in YAML formatter from being selected).
-    final allSynchronisedTypes = {
-      ...allTypes,
+    final synchronisedTypes = {
+      ...fullySupportedTypes,
+      pubspecFile,
+      analysisOptionsFile,
+      fixDataFile,
+    }.toList();
+
+    // Completion is supported for some synchronised files that we don't _fully_
+    // support (eg. YAML). If these gain support for things like hover, we may
+    // wish to move them to fullySupprtedTypes but add an exclusion for formatting.
+    final completionSupportedTypes = {
+      ...fullySupportedTypes,
       pubspecFile,
       analysisOptionsFile,
       fixDataFile,
@@ -278,25 +288,25 @@
     register(
       dynamicRegistrations.textSync,
       Method.textDocument_didOpen,
-      TextDocumentRegistrationOptions(documentSelector: allSynchronisedTypes),
+      TextDocumentRegistrationOptions(documentSelector: synchronisedTypes),
     );
     register(
       dynamicRegistrations.textSync,
       Method.textDocument_didClose,
-      TextDocumentRegistrationOptions(documentSelector: allSynchronisedTypes),
+      TextDocumentRegistrationOptions(documentSelector: synchronisedTypes),
     );
     register(
       dynamicRegistrations.textSync,
       Method.textDocument_didChange,
       TextDocumentChangeRegistrationOptions(
           syncKind: TextDocumentSyncKind.Incremental,
-          documentSelector: allSynchronisedTypes),
+          documentSelector: synchronisedTypes),
     );
     register(
       dynamicRegistrations.completion,
       Method.textDocument_completion,
       CompletionRegistrationOptions(
-        documentSelector: allTypes,
+        documentSelector: completionSupportedTypes,
         triggerCharacters: dartCompletionTriggerCharacters,
         allCommitCharacters:
             previewCommitCharacters ? dartCompletionCommitCharacters : null,
@@ -306,13 +316,13 @@
     register(
       dynamicRegistrations.hover,
       Method.textDocument_hover,
-      TextDocumentRegistrationOptions(documentSelector: allTypes),
+      TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
     );
     register(
       dynamicRegistrations.signatureHelp,
       Method.textDocument_signatureHelp,
       SignatureHelpRegistrationOptions(
-        documentSelector: allTypes,
+        documentSelector: fullySupportedTypes,
         triggerCharacters: dartSignatureHelpTriggerCharacters,
         retriggerCharacters: dartSignatureHelpRetriggerCharacters,
       ),
@@ -320,22 +330,22 @@
     register(
       dynamicRegistrations.references,
       Method.textDocument_references,
-      TextDocumentRegistrationOptions(documentSelector: allTypes),
+      TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
     );
     register(
       dynamicRegistrations.documentHighlights,
       Method.textDocument_documentHighlight,
-      TextDocumentRegistrationOptions(documentSelector: allTypes),
+      TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
     );
     register(
       dynamicRegistrations.documentSymbol,
       Method.textDocument_documentSymbol,
-      TextDocumentRegistrationOptions(documentSelector: allTypes),
+      TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
     );
     register(
       enableFormatter && dynamicRegistrations.formatting,
       Method.textDocument_formatting,
-      TextDocumentRegistrationOptions(documentSelector: allTypes),
+      TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
     );
     register(
       enableFormatter && dynamicRegistrations.typeFormatting,
@@ -356,18 +366,18 @@
     register(
       dynamicRegistrations.definition,
       Method.textDocument_definition,
-      TextDocumentRegistrationOptions(documentSelector: allTypes),
+      TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
     );
     register(
       dynamicRegistrations.implementation,
       Method.textDocument_implementation,
-      TextDocumentRegistrationOptions(documentSelector: allTypes),
+      TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
     );
     register(
       dynamicRegistrations.codeActions,
       Method.textDocument_codeAction,
       CodeActionRegistrationOptions(
-        documentSelector: allTypes,
+        documentSelector: fullySupportedTypes,
         codeActionKinds: DartCodeActionKind.serverSupportedKinds,
       ),
     );
@@ -375,12 +385,12 @@
       dynamicRegistrations.rename,
       Method.textDocument_rename,
       RenameRegistrationOptions(
-          documentSelector: allTypes, prepareProvider: true),
+          documentSelector: fullySupportedTypes, prepareProvider: true),
     );
     register(
       dynamicRegistrations.folding,
       Method.textDocument_foldingRange,
-      TextDocumentRegistrationOptions(documentSelector: allTypes),
+      TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
     );
     register(
       dynamicRegistrations.didChangeConfiguration,
diff --git a/pkg/analysis_server/lib/src/services/completion/yaml/yaml_completion_generator.dart b/pkg/analysis_server/lib/src/services/completion/yaml/yaml_completion_generator.dart
index 3d0b64c..b00768b 100644
--- a/pkg/analysis_server/lib/src/services/completion/yaml/yaml_completion_generator.dart
+++ b/pkg/analysis_server/lib/src/services/completion/yaml/yaml_completion_generator.dart
@@ -24,7 +24,7 @@
 
   /// Return the completion suggestions appropriate for the given [offset] in
   /// the file at the given [filePath].
-  List<CompletionSuggestion> getSuggestions(String filePath, int offset) {
+  YamlCompletionResults getSuggestions(String filePath, int offset) {
     var file = resourceProvider.getFile(filePath);
     String content;
     try {
@@ -32,12 +32,12 @@
     } on FileSystemException {
       // If the file doesn't exist or can't be read, then there are no
       // suggestions.
-      return const <CompletionSuggestion>[];
+      return const YamlCompletionResults.empty();
     }
     var root = _parseYaml(content);
     if (root == null) {
       // If the contents can't be parsed, then there are no suggestions.
-      return const <CompletionSuggestion>[];
+      return const YamlCompletionResults.empty();
     }
     var path = _pathToOffset(root, offset);
     var completionNode = path.last;
@@ -52,17 +52,16 @@
       return getSuggestionsForPath(path, offset);
     }
     // There are no completions at the given location.
-    return const <CompletionSuggestion>[];
+    return const YamlCompletionResults.empty();
   }
 
   /// Given a [path] to the node in which completions are being requested and
   /// the offset of the cursor, return the completions appropriate at that
   /// location.
-  List<CompletionSuggestion> getSuggestionsForPath(
-      List<YamlNode> path, int offset) {
+  YamlCompletionResults getSuggestionsForPath(List<YamlNode> path, int offset) {
     var producer = _producerForPath(path);
     if (producer == null) {
-      return const <CompletionSuggestion>[];
+      return const YamlCompletionResults.empty();
     }
     var invalidSuggestions = _siblingsOnPath(path);
     var suggestions = <CompletionSuggestion>[];
@@ -71,7 +70,12 @@
         suggestions.add(suggestion);
       }
     }
-    return suggestions;
+    final node = path.isNotEmpty ? path.last : null;
+    final replaceNode = node is YamlScalar && node.containsOffset(offset);
+    final replacementOffset = replaceNode ? node.span.start.offset : offset;
+    final replacementLength = replaceNode ? node.span.length : 0;
+    return YamlCompletionResults(
+        suggestions, replacementOffset, replacementLength);
   }
 
   /// Return the result of parsing the file [content] into a YAML node.
@@ -164,6 +168,20 @@
   }
 }
 
+class YamlCompletionResults {
+  final List<CompletionSuggestion> suggestions;
+  final int replacementOffset;
+  final int replacementLength;
+
+  const YamlCompletionResults(
+      this.suggestions, this.replacementOffset, this.replacementLength);
+
+  const YamlCompletionResults.empty()
+      : suggestions = const [],
+        replacementOffset = 0,
+        replacementLength = 0;
+}
+
 extension on YamlMap {
   /// Return the node representing the key that corresponds to the value
   /// represented by the [value] node.
diff --git a/pkg/analysis_server/test/lsp/completion_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart
similarity index 100%
rename from pkg/analysis_server/test/lsp/completion_test.dart
rename to pkg/analysis_server/test/lsp/completion_dart_test.dart
diff --git a/pkg/analysis_server/test/lsp/completion_yaml_test.dart b/pkg/analysis_server/test/lsp/completion_yaml_test.dart
new file mode 100644
index 0000000..0802d65
--- /dev/null
+++ b/pkg/analysis_server/test/lsp/completion_yaml_test.dart
@@ -0,0 +1,302 @@
+// Copyright (c) 2020, 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:linter/src/rules.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'server_abstract.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(PubspecCompletionTest);
+    defineReflectiveTests(AnalysisOptionsCompletionTest);
+    defineReflectiveTests(FixDataCompletionTest);
+  });
+}
+
+@reflectiveTest
+class AnalysisOptionsCompletionTest extends AbstractLspAnalysisServerTest
+    with CompletionTestMixin {
+  @override
+  void setUp() {
+    registerLintRules();
+    super.setUp();
+  }
+
+  Future<void> test_nested() async {
+    final content = '''
+linter:
+  rules:
+    - ^''';
+
+    final expected = '''
+linter:
+  rules:
+    - annotate_overrides''';
+
+    await verifyCompletions(
+      analysisOptionsUri,
+      content,
+      expectCompletions: [
+        'always_declare_return_types',
+        'annotate_overrides',
+      ],
+      verifyEditsFor: 'annotate_overrides',
+      expectedContent: expected,
+    );
+  }
+
+  Future<void> test_nested_prefix() async {
+    final content = '''
+linter:
+  rules:
+    - ann^''';
+
+    final expected = '''
+linter:
+  rules:
+    - annotate_overrides''';
+
+    await verifyCompletions(
+      analysisOptionsUri,
+      content,
+      expectCompletions: ['annotate_overrides'],
+      verifyEditsFor: 'annotate_overrides',
+      expectedContent: expected,
+    );
+  }
+
+  Future<void> test_topLevel() async {
+    final content = '''
+^''';
+    final expected = '''
+linter: ''';
+
+    await verifyCompletions(
+      analysisOptionsUri,
+      content,
+      expectCompletions: ['linter: '],
+      verifyEditsFor: 'linter: ',
+      expectedContent: expected,
+    );
+  }
+
+  Future<void> test_topLevel_prefix() async {
+    final content = '''
+li^''';
+    final expected = '''
+linter: ''';
+
+    await verifyCompletions(
+      analysisOptionsUri,
+      content,
+      expectCompletions: ['linter: '],
+      verifyEditsFor: 'linter: ',
+      expectedContent: expected,
+    );
+  }
+}
+
+mixin CompletionTestMixin on AbstractLspAnalysisServerTest {
+  Future<void> verifyCompletions(
+    Uri fileUri,
+    String content, {
+    List<String> expectCompletions,
+    String verifyEditsFor,
+    String expectedContent,
+  }) async {
+    await initialize();
+    await openFile(fileUri, withoutMarkers(content));
+    final res = await getCompletion(fileUri, positionFromMarker(content));
+
+    for (final expectedCompletion in expectCompletions) {
+      expect(
+        res.any((c) => c.label == expectedCompletion),
+        isTrue,
+        reason:
+            '"$expectedCompletion" was not in ${res.map((c) => '"${c.label}"')}',
+      );
+    }
+
+    // Check the edits apply correctly.
+    if (verifyEditsFor != null) {
+      final item = res.singleWhere((c) => c.label == verifyEditsFor);
+      expect(item.insertTextFormat, isNull);
+      expect(item.insertText, isNull);
+      final updated = applyTextEdits(withoutMarkers(content), [item.textEdit]);
+      expect(updated, equals(expectedContent));
+    }
+  }
+}
+
+@reflectiveTest
+class FixDataCompletionTest extends AbstractLspAnalysisServerTest
+    with CompletionTestMixin {
+  Uri fixDataUri;
+
+  @override
+  void setUp() {
+    super.setUp();
+    fixDataUri = Uri.file(join(projectFolderPath, 'lib', 'fix_data.yaml'));
+  }
+
+  Future<void> test_nested() async {
+    final content = '''
+version: 1.0.0
+transforms:
+  - changes:
+    - ^''';
+    final expected = '''
+version: 1.0.0
+transforms:
+  - changes:
+    - kind: ''';
+
+    await verifyCompletions(
+      fixDataUri,
+      content,
+      expectCompletions: ['kind: '],
+      verifyEditsFor: 'kind: ',
+      expectedContent: expected,
+    );
+  }
+
+  Future<void> test_nested_prefix() async {
+    final content = '''
+version: 1.0.0
+transforms:
+  - changes:
+    - ki^''';
+    final expected = '''
+version: 1.0.0
+transforms:
+  - changes:
+    - kind: ''';
+
+    await verifyCompletions(
+      fixDataUri,
+      content,
+      expectCompletions: ['kind: '],
+      verifyEditsFor: 'kind: ',
+      expectedContent: expected,
+    );
+  }
+
+  Future<void> test_topLevel() async {
+    final content = '''
+version: 1.0.0
+^''';
+    final expected = '''
+version: 1.0.0
+transforms:''';
+
+    await verifyCompletions(
+      fixDataUri,
+      content,
+      expectCompletions: ['transforms:'],
+      verifyEditsFor: 'transforms:',
+      expectedContent: expected,
+    );
+  }
+
+  Future<void> test_topLevel_prefix() async {
+    final content = '''
+tra^''';
+    final expected = '''
+transforms:''';
+
+    await verifyCompletions(
+      fixDataUri,
+      content,
+      expectCompletions: ['transforms:'],
+      verifyEditsFor: 'transforms:',
+      expectedContent: expected,
+    );
+  }
+}
+
+@reflectiveTest
+class PubspecCompletionTest extends AbstractLspAnalysisServerTest
+    with CompletionTestMixin {
+  Future<void> test_nested() async {
+    final content = '''
+name: foo
+version: 1.0.0
+
+environment:
+  ^''';
+
+    final expected = '''
+name: foo
+version: 1.0.0
+
+environment:
+  sdk: ''';
+
+    await verifyCompletions(
+      pubspecFileUri,
+      content,
+      expectCompletions: ['flutter: ', 'sdk: '],
+      verifyEditsFor: 'sdk: ',
+      expectedContent: expected,
+    );
+  }
+
+  Future<void> test_nested_prefix() async {
+    final content = '''
+name: foo
+version: 1.0.0
+
+environment:
+  sd^''';
+
+    final expected = '''
+name: foo
+version: 1.0.0
+
+environment:
+  sdk: ''';
+
+    await verifyCompletions(
+      pubspecFileUri,
+      content,
+      expectCompletions: ['flutter: ', 'sdk: '],
+      verifyEditsFor: 'sdk: ',
+      expectedContent: expected,
+    );
+  }
+
+  Future<void> test_topLevel() async {
+    final content = '''
+version: 1.0.0
+^''';
+    final expected = '''
+version: 1.0.0
+name: ''';
+
+    await verifyCompletions(
+      pubspecFileUri,
+      content,
+      expectCompletions: ['name: ', 'description: '],
+      verifyEditsFor: 'name: ',
+      expectedContent: expected,
+    );
+  }
+
+  Future<void> test_topLevel_prefix() async {
+    final content = '''
+na^''';
+    final expected = '''
+name: ''';
+
+    await verifyCompletions(
+      pubspecFileUri,
+      content,
+      expectCompletions: ['name: ', 'description: '],
+      verifyEditsFor: 'name: ',
+      expectedContent: expected,
+    );
+  }
+}
diff --git a/pkg/analysis_server/test/lsp/test_all.dart b/pkg/analysis_server/test/lsp/test_all.dart
index 628b142..ea56793 100644
--- a/pkg/analysis_server/test/lsp/test_all.dart
+++ b/pkg/analysis_server/test/lsp/test_all.dart
@@ -13,7 +13,8 @@
 import 'code_actions_fixes_test.dart' as code_actions_fixes;
 import 'code_actions_refactor_test.dart' as code_actions_refactor;
 import 'code_actions_source_test.dart' as code_actions_source;
-import 'completion_test.dart' as completion;
+import 'completion_dart_test.dart' as completion_dart;
+import 'completion_yaml_test.dart' as completion_yaml;
 import 'configuration_test.dart' as configuration;
 import 'definition_test.dart' as definition;
 import 'diagnostic_test.dart' as diagnostic;
@@ -48,7 +49,8 @@
     code_actions_fixes.main();
     code_actions_source.main();
     code_actions_refactor.main();
-    completion.main();
+    completion_dart.main();
+    completion_yaml.main();
     configuration.main();
     definition.main();
     diagnostic.main();
diff --git a/pkg/analysis_server/test/src/services/completion/yaml/yaml_generator_test_support.dart b/pkg/analysis_server/test/src/services/completion/yaml/yaml_generator_test_support.dart
index 7e4cc84..3baebe1 100644
--- a/pkg/analysis_server/test/src/services/completion/yaml/yaml_generator_test_support.dart
+++ b/pkg/analysis_server/test/src/services/completion/yaml/yaml_generator_test_support.dart
@@ -59,6 +59,6 @@
     // Add the file to the file system.
     var file = newFile('/home/test/$fileName', content: content);
     // Generate completions.
-    results = generator.getSuggestions(file.path, completionOffset);
+    results = generator.getSuggestions(file.path, completionOffset).suggestions;
   }
 }