Version 2.17.0-66.0.dev

Merge commit '7ad1786e45a8056269103576b05d0d4d69b38f13' into 'dev'
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
index 5c222c3..7d095d7 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
@@ -169,29 +169,167 @@
       CompletionItemResolutionInfo.canParse,
       CompletionItemResolutionInfo.fromJson);
 
-  CompletionItemResolutionInfo({required this.file, required this.offset});
   static CompletionItemResolutionInfo fromJson(Map<String, Object?> json) {
-    if (DartCompletionItemResolutionInfo.canParse(json, nullLspJsonReporter)) {
-      return DartCompletionItemResolutionInfo.fromJson(json);
+    if (DartSuggestionSetCompletionItemResolutionInfo.canParse(
+        json, nullLspJsonReporter)) {
+      return DartSuggestionSetCompletionItemResolutionInfo.fromJson(json);
     }
     if (PubPackageCompletionItemResolutionInfo.canParse(
         json, nullLspJsonReporter)) {
       return PubPackageCompletionItemResolutionInfo.fromJson(json);
     }
+    return CompletionItemResolutionInfo();
+  }
+
+  Map<String, Object?> toJson() {
+    var __result = <String, Object?>{};
+    return __result;
+  }
+
+  static bool canParse(Object? obj, LspJsonReporter reporter) {
+    if (obj is Map<String, Object?>) {
+      return true;
+    } else {
+      reporter.reportError('must be of type CompletionItemResolutionInfo');
+      return false;
+    }
+  }
+
+  @override
+  bool operator ==(Object other) {
+    if (other is CompletionItemResolutionInfo &&
+        other.runtimeType == CompletionItemResolutionInfo) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode => 42;
+
+  @override
+  String toString() => jsonEncoder.convert(toJson());
+}
+
+class DartDiagnosticServer implements ToJsonable {
+  static const jsonHandler = LspJsonHandler(
+      DartDiagnosticServer.canParse, DartDiagnosticServer.fromJson);
+
+  DartDiagnosticServer({required this.port});
+  static DartDiagnosticServer fromJson(Map<String, Object?> json) {
+    final portJson = json['port'];
+    final port = portJson as int;
+    return DartDiagnosticServer(port: port);
+  }
+
+  final int port;
+
+  Map<String, Object?> toJson() {
+    var __result = <String, Object?>{};
+    __result['port'] = port;
+    return __result;
+  }
+
+  static bool canParse(Object? obj, LspJsonReporter reporter) {
+    if (obj is Map<String, Object?>) {
+      reporter.push('port');
+      try {
+        if (!obj.containsKey('port')) {
+          reporter.reportError('must not be undefined');
+          return false;
+        }
+        final port = obj['port'];
+        if (port == null) {
+          reporter.reportError('must not be null');
+          return false;
+        }
+        if (!(port is int)) {
+          reporter.reportError('must be of type int');
+          return false;
+        }
+      } finally {
+        reporter.pop();
+      }
+      return true;
+    } else {
+      reporter.reportError('must be of type DartDiagnosticServer');
+      return false;
+    }
+  }
+
+  @override
+  bool operator ==(Object other) {
+    if (other is DartDiagnosticServer &&
+        other.runtimeType == DartDiagnosticServer) {
+      return port == other.port && true;
+    }
+    return false;
+  }
+
+  @override
+  int get hashCode => port.hashCode;
+
+  @override
+  String toString() => jsonEncoder.convert(toJson());
+}
+
+class DartSuggestionSetCompletionItemResolutionInfo
+    implements CompletionItemResolutionInfo, ToJsonable {
+  static const jsonHandler = LspJsonHandler(
+      DartSuggestionSetCompletionItemResolutionInfo.canParse,
+      DartSuggestionSetCompletionItemResolutionInfo.fromJson);
+
+  DartSuggestionSetCompletionItemResolutionInfo(
+      {required this.file,
+      required this.offset,
+      required this.libId,
+      required this.displayUri,
+      required this.rOffset,
+      required this.iLength,
+      required this.rLength});
+  static DartSuggestionSetCompletionItemResolutionInfo fromJson(
+      Map<String, Object?> json) {
     final fileJson = json['file'];
     final file = fileJson as String;
     final offsetJson = json['offset'];
     final offset = offsetJson as int;
-    return CompletionItemResolutionInfo(file: file, offset: offset);
+    final libIdJson = json['libId'];
+    final libId = libIdJson as int;
+    final displayUriJson = json['displayUri'];
+    final displayUri = displayUriJson as String;
+    final rOffsetJson = json['rOffset'];
+    final rOffset = rOffsetJson as int;
+    final iLengthJson = json['iLength'];
+    final iLength = iLengthJson as int;
+    final rLengthJson = json['rLength'];
+    final rLength = rLengthJson as int;
+    return DartSuggestionSetCompletionItemResolutionInfo(
+        file: file,
+        offset: offset,
+        libId: libId,
+        displayUri: displayUri,
+        rOffset: rOffset,
+        iLength: iLength,
+        rLength: rLength);
   }
 
+  final String displayUri;
   final String file;
+  final int iLength;
+  final int libId;
   final int offset;
+  final int rLength;
+  final int rOffset;
 
   Map<String, Object?> toJson() {
     var __result = <String, Object?>{};
     __result['file'] = file;
     __result['offset'] = offset;
+    __result['libId'] = libId;
+    __result['displayUri'] = displayUri;
+    __result['rOffset'] = rOffset;
+    __result['iLength'] = iLength;
+    __result['rLength'] = rLength;
     return __result;
   }
 
@@ -233,90 +371,6 @@
       } finally {
         reporter.pop();
       }
-      return true;
-    } else {
-      reporter.reportError('must be of type CompletionItemResolutionInfo');
-      return false;
-    }
-  }
-
-  @override
-  bool operator ==(Object other) {
-    if (other is CompletionItemResolutionInfo &&
-        other.runtimeType == CompletionItemResolutionInfo) {
-      return file == other.file && offset == other.offset && true;
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode => Object.hash(file, offset);
-
-  @override
-  String toString() => jsonEncoder.convert(toJson());
-}
-
-class DartCompletionItemResolutionInfo
-    implements CompletionItemResolutionInfo, ToJsonable {
-  static const jsonHandler = LspJsonHandler(
-      DartCompletionItemResolutionInfo.canParse,
-      DartCompletionItemResolutionInfo.fromJson);
-
-  DartCompletionItemResolutionInfo(
-      {required this.libId,
-      required this.displayUri,
-      required this.rOffset,
-      required this.iLength,
-      required this.rLength,
-      required this.file,
-      required this.offset});
-  static DartCompletionItemResolutionInfo fromJson(Map<String, Object?> json) {
-    final libIdJson = json['libId'];
-    final libId = libIdJson as int;
-    final displayUriJson = json['displayUri'];
-    final displayUri = displayUriJson as String;
-    final rOffsetJson = json['rOffset'];
-    final rOffset = rOffsetJson as int;
-    final iLengthJson = json['iLength'];
-    final iLength = iLengthJson as int;
-    final rLengthJson = json['rLength'];
-    final rLength = rLengthJson as int;
-    final fileJson = json['file'];
-    final file = fileJson as String;
-    final offsetJson = json['offset'];
-    final offset = offsetJson as int;
-    return DartCompletionItemResolutionInfo(
-        libId: libId,
-        displayUri: displayUri,
-        rOffset: rOffset,
-        iLength: iLength,
-        rLength: rLength,
-        file: file,
-        offset: offset);
-  }
-
-  final String displayUri;
-  final String file;
-  final int iLength;
-  final int libId;
-  final int offset;
-  final int rLength;
-  final int rOffset;
-
-  Map<String, Object?> toJson() {
-    var __result = <String, Object?>{};
-    __result['libId'] = libId;
-    __result['displayUri'] = displayUri;
-    __result['rOffset'] = rOffset;
-    __result['iLength'] = iLength;
-    __result['rLength'] = rLength;
-    __result['file'] = file;
-    __result['offset'] = offset;
-    return __result;
-  }
-
-  static bool canParse(Object? obj, LspJsonReporter reporter) {
-    if (obj is Map<String, Object?>) {
       reporter.push('libId');
       try {
         if (!obj.containsKey('libId')) {
@@ -407,60 +461,25 @@
       } finally {
         reporter.pop();
       }
-      reporter.push('file');
-      try {
-        if (!obj.containsKey('file')) {
-          reporter.reportError('must not be undefined');
-          return false;
-        }
-        final file = obj['file'];
-        if (file == null) {
-          reporter.reportError('must not be null');
-          return false;
-        }
-        if (!(file is String)) {
-          reporter.reportError('must be of type String');
-          return false;
-        }
-      } finally {
-        reporter.pop();
-      }
-      reporter.push('offset');
-      try {
-        if (!obj.containsKey('offset')) {
-          reporter.reportError('must not be undefined');
-          return false;
-        }
-        final offset = obj['offset'];
-        if (offset == null) {
-          reporter.reportError('must not be null');
-          return false;
-        }
-        if (!(offset is int)) {
-          reporter.reportError('must be of type int');
-          return false;
-        }
-      } finally {
-        reporter.pop();
-      }
       return true;
     } else {
-      reporter.reportError('must be of type DartCompletionItemResolutionInfo');
+      reporter.reportError(
+          'must be of type DartSuggestionSetCompletionItemResolutionInfo');
       return false;
     }
   }
 
   @override
   bool operator ==(Object other) {
-    if (other is DartCompletionItemResolutionInfo &&
-        other.runtimeType == DartCompletionItemResolutionInfo) {
-      return libId == other.libId &&
+    if (other is DartSuggestionSetCompletionItemResolutionInfo &&
+        other.runtimeType == DartSuggestionSetCompletionItemResolutionInfo) {
+      return file == other.file &&
+          offset == other.offset &&
+          libId == other.libId &&
           displayUri == other.displayUri &&
           rOffset == other.rOffset &&
           iLength == other.iLength &&
           rLength == other.rLength &&
-          file == other.file &&
-          offset == other.offset &&
           true;
     }
     return false;
@@ -468,69 +487,7 @@
 
   @override
   int get hashCode =>
-      Object.hash(libId, displayUri, rOffset, iLength, rLength, file, offset);
-
-  @override
-  String toString() => jsonEncoder.convert(toJson());
-}
-
-class DartDiagnosticServer implements ToJsonable {
-  static const jsonHandler = LspJsonHandler(
-      DartDiagnosticServer.canParse, DartDiagnosticServer.fromJson);
-
-  DartDiagnosticServer({required this.port});
-  static DartDiagnosticServer fromJson(Map<String, Object?> json) {
-    final portJson = json['port'];
-    final port = portJson as int;
-    return DartDiagnosticServer(port: port);
-  }
-
-  final int port;
-
-  Map<String, Object?> toJson() {
-    var __result = <String, Object?>{};
-    __result['port'] = port;
-    return __result;
-  }
-
-  static bool canParse(Object? obj, LspJsonReporter reporter) {
-    if (obj is Map<String, Object?>) {
-      reporter.push('port');
-      try {
-        if (!obj.containsKey('port')) {
-          reporter.reportError('must not be undefined');
-          return false;
-        }
-        final port = obj['port'];
-        if (port == null) {
-          reporter.reportError('must not be null');
-          return false;
-        }
-        if (!(port is int)) {
-          reporter.reportError('must be of type int');
-          return false;
-        }
-      } finally {
-        reporter.pop();
-      }
-      return true;
-    } else {
-      reporter.reportError('must be of type DartDiagnosticServer');
-      return false;
-    }
-  }
-
-  @override
-  bool operator ==(Object other) {
-    if (other is DartDiagnosticServer &&
-        other.runtimeType == DartDiagnosticServer) {
-      return port == other.port && true;
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode => port.hashCode;
+      Object.hash(file, offset, libId, displayUri, rOffset, iLength, rLength);
 
   @override
   String toString() => jsonEncoder.convert(toJson());
@@ -1211,29 +1168,19 @@
       PubPackageCompletionItemResolutionInfo.canParse,
       PubPackageCompletionItemResolutionInfo.fromJson);
 
-  PubPackageCompletionItemResolutionInfo(
-      {required this.packageName, required this.file, required this.offset});
+  PubPackageCompletionItemResolutionInfo({required this.packageName});
   static PubPackageCompletionItemResolutionInfo fromJson(
       Map<String, Object?> json) {
     final packageNameJson = json['packageName'];
     final packageName = packageNameJson as String;
-    final fileJson = json['file'];
-    final file = fileJson as String;
-    final offsetJson = json['offset'];
-    final offset = offsetJson as int;
-    return PubPackageCompletionItemResolutionInfo(
-        packageName: packageName, file: file, offset: offset);
+    return PubPackageCompletionItemResolutionInfo(packageName: packageName);
   }
 
-  final String file;
-  final int offset;
   final String packageName;
 
   Map<String, Object?> toJson() {
     var __result = <String, Object?>{};
     __result['packageName'] = packageName;
-    __result['file'] = file;
-    __result['offset'] = offset;
     return __result;
   }
 
@@ -1257,42 +1204,6 @@
       } finally {
         reporter.pop();
       }
-      reporter.push('file');
-      try {
-        if (!obj.containsKey('file')) {
-          reporter.reportError('must not be undefined');
-          return false;
-        }
-        final file = obj['file'];
-        if (file == null) {
-          reporter.reportError('must not be null');
-          return false;
-        }
-        if (!(file is String)) {
-          reporter.reportError('must be of type String');
-          return false;
-        }
-      } finally {
-        reporter.pop();
-      }
-      reporter.push('offset');
-      try {
-        if (!obj.containsKey('offset')) {
-          reporter.reportError('must not be undefined');
-          return false;
-        }
-        final offset = obj['offset'];
-        if (offset == null) {
-          reporter.reportError('must not be null');
-          return false;
-        }
-        if (!(offset is int)) {
-          reporter.reportError('must be of type int');
-          return false;
-        }
-      } finally {
-        reporter.pop();
-      }
       return true;
     } else {
       reporter.reportError(
@@ -1305,16 +1216,13 @@
   bool operator ==(Object other) {
     if (other is PubPackageCompletionItemResolutionInfo &&
         other.runtimeType == PubPackageCompletionItemResolutionInfo) {
-      return packageName == other.packageName &&
-          file == other.file &&
-          offset == other.offset &&
-          true;
+      return packageName == other.packageName && true;
     }
     return false;
   }
 
   @override
-  int get hashCode => Object.hash(packageName, file, offset);
+  int get hashCode => packageName.hashCode;
 
   @override
   String toString() => jsonEncoder.convert(toJson());
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 d2bd74d..736ab90 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -31,13 +31,14 @@
 import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
 import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
 
-class CompletionHandler
-    extends MessageHandler<CompletionParams, List<CompletionItem>>
+class CompletionHandler extends MessageHandler<CompletionParams, CompletionList>
     with LspPluginRequestHandlerMixin {
+  /// Whether to include symbols from libraries that have not been imported.
   final bool suggestFromUnimportedLibraries;
-  CompletionHandler(
-      LspAnalysisServer server, this.suggestFromUnimportedLibraries)
-      : super(server);
+
+  CompletionHandler(LspAnalysisServer server, LspInitializationOptions options)
+      : suggestFromUnimportedLibraries = options.suggestFromUnimportedLibraries,
+        super(server);
 
   @override
   Method get handlesMessage => Method.textDocument_completion;
@@ -47,7 +48,7 @@
       CompletionParams.jsonHandler;
 
   @override
-  Future<ErrorOr<List<CompletionItem>>> handle(
+  Future<ErrorOr<CompletionList>> handle(
       CompletionParams params, CancellationToken token) async {
     final clientCapabilities = server.clientCapabilities;
     if (clientCapabilities == null) {
@@ -56,9 +57,6 @@
           'Requests not before server is initilized');
     }
 
-    final includeSuggestionSets =
-        suggestFromUnimportedLibraries && clientCapabilities.applyEdit;
-
     final triggerCharacter = params.context?.triggerCharacter;
     final pos = params.position;
     final path = pathOfDoc(params.textDocument);
@@ -75,14 +73,13 @@
         await lineInfo.mapResult((lineInfo) => toOffset(lineInfo, pos));
 
     return offset.mapResult((offset) async {
-      Future<ErrorOr<List<CompletionItem>>>? serverResultsFuture;
+      Future<ErrorOr<CompletionList>>? serverResultsFuture;
       final pathContext = server.resourceProvider.pathContext;
       final fileExtension = pathContext.extension(path.result);
 
       if (fileExtension == '.dart' && !unit.isError) {
         serverResultsFuture = _getServerDartItems(
           clientCapabilities,
-          includeSuggestionSets,
           unit.result,
           offset,
           triggerCharacter,
@@ -110,7 +107,8 @@
         }
       }
 
-      serverResultsFuture ??= Future.value(success(const <CompletionItem>[]));
+      serverResultsFuture ??=
+          Future.value(success(CompletionList(isIncomplete: false, items: [])));
 
       final pluginResultsFuture = _getPluginResults(
           clientCapabilities, lineInfo.result, path.result, offset);
@@ -125,9 +123,15 @@
       if (serverResults.isError) return serverResults;
       if (pluginResults.isError) return pluginResults;
 
-      return success(
-        serverResults.result.followedBy(pluginResults.result).toList(),
-      );
+      return success(CompletionList(
+        // If any set of the results is incomplete, the whole batch must be
+        // marked as such.
+        isIncomplete: serverResults.result.isIncomplete ||
+            pluginResults.result.isIncomplete,
+        items: serverResults.result.items
+            .followedBy(pluginResults.result.items)
+            .toList(),
+      ));
     });
   }
 
@@ -174,7 +178,7 @@
   String _createImportedSymbolKey(String name, Uri declaringUri) =>
       '$name/$declaringUri';
 
-  Future<ErrorOr<List<CompletionItem>>> _getPluginResults(
+  Future<ErrorOr<CompletionList>> _getPluginResults(
     LspClientCapabilities capabilities,
     LineInfo lineInfo,
     String path,
@@ -188,22 +192,27 @@
         .map((e) => plugin.CompletionGetSuggestionsResult.fromResponse(e))
         .toList();
 
-    return success(_pluginResultsToItems(
-      capabilities,
-      lineInfo,
-      offset,
-      pluginResults,
-    ).toList());
+    return success(CompletionList(
+      isIncomplete: false,
+      items: _pluginResultsToItems(
+        capabilities,
+        lineInfo,
+        offset,
+        pluginResults,
+      ).toList(),
+    ));
   }
 
-  Future<ErrorOr<List<CompletionItem>>> _getServerDartItems(
+  Future<ErrorOr<CompletionList>> _getServerDartItems(
     LspClientCapabilities capabilities,
-    bool includeSuggestionSets,
     ResolvedUnitResult unit,
     int offset,
     String? triggerCharacter,
     CancellationToken token,
   ) async {
+    final useSuggestionSets =
+        suggestFromUnimportedLibraries && capabilities.applyEdit;
+
     var performance = OperationPerformanceImpl('<root>');
     return await performance.runAsync(
       'request',
@@ -226,14 +235,14 @@
 
         if (triggerCharacter != null) {
           if (!_triggerCharacterValid(offset, triggerCharacter, target)) {
-            return success([]);
+            return success(CompletionList(isIncomplete: false, items: []));
           }
         }
 
         Set<ElementKind>? includedElementKinds;
         Set<String>? includedElementNames;
         List<IncludedSuggestionRelevanceTag>? includedSuggestionRelevanceTags;
-        if (includeSuggestionSets) {
+        if (useSuggestionSets) {
           includedElementKinds = <ElementKind>{};
           includedElementNames = <String>{};
           includedSuggestionRelevanceTags = <IncludedSuggestionRelevanceTag>[];
@@ -284,18 +293,22 @@
                     offset, itemReplacementOffset, itemInsertLength);
               }
 
+              // Convert to LSP ranges using the LineInfo.
+              Range? replacementRange = toRange(
+                  unit.lineInfo, itemReplacementOffset, itemReplacementLength);
+              Range? insertionRange = toRange(
+                  unit.lineInfo, itemReplacementOffset, itemInsertLength);
+
               return toCompletionItem(
                 capabilities,
                 unit.lineInfo,
                 item,
-                itemReplacementOffset,
-                itemInsertLength,
-                itemReplacementLength,
-                // TODO(dantup): Including commit characters in every completion
-                // increases the payload size. The LSP spec is ambigious
-                // about how this should be handled (and VS Code requires it) but
-                // this should be removed (or made conditional based on a capability)
-                // depending on how the spec is updated.
+                replacementRange: replacementRange,
+                insertionRange: insertionRange,
+                // TODO(dantup): Move commit characters to the main response
+                // and remove from each individual item (to reduce payload size)
+                // once the following change ships (and the Dart VS Code
+                // extension is updated to use it).
                 // https://github.com/microsoft/vscode-languageserver-node/issues/673
                 includeCommitCharacters:
                     server.clientConfiguration.global.previewCommitCharacters,
@@ -390,11 +403,10 @@
                         completionRequest.replacementOffset,
                         insertLength,
                         completionRequest.replacementLength,
-                        // TODO(dantup): Including commit characters in every completion
-                        // increases the payload size. The LSP spec is ambigious
-                        // about how this should be handled (and VS Code requires it) but
-                        // this should be removed (or made conditional based on a capability)
-                        // depending on how the spec is updated.
+                        // TODO(dantup): Move commit characters to the main response
+                        // and remove from each individual item (to reduce payload size)
+                        // once the following change ships (and the Dart VS Code
+                        // extension is updated to use it).
                         // https://github.com/microsoft/vscode-languageserver-node/issues/673
                         includeCommitCharacters: server
                             .clientConfiguration.global.previewCommitCharacters,
@@ -415,15 +427,16 @@
 
           completionPerformance.suggestionCount = results.length;
 
-          return success(matchingResults);
+          return success(
+              CompletionList(isIncomplete: false, items: matchingResults));
         } on AbortCompletion {
-          return success([]);
+          return success(CompletionList(isIncomplete: false, items: []));
         }
       },
     );
   }
 
-  Future<ErrorOr<List<CompletionItem>>> _getServerYamlItems(
+  Future<ErrorOr<CompletionList>> _getServerYamlItems(
     YamlCompletionGenerator generator,
     LspClientCapabilities capabilities,
     String path,
@@ -437,23 +450,25 @@
       suggestions.replacementOffset,
       suggestions.replacementLength,
     );
+    final replacementRange = toRange(
+        lineInfo, suggestions.replacementOffset, suggestions.replacementLength);
+    final insertionRange =
+        toRange(lineInfo, suggestions.replacementOffset, insertLength);
+
     final completionItems = suggestions.suggestions
         .map(
           (item) => toCompletionItem(
             capabilities,
             lineInfo,
             item,
-            suggestions.replacementOffset,
-            insertLength,
-            suggestions.replacementLength,
+            replacementRange: replacementRange,
+            insertionRange: insertionRange,
             includeCommitCharacters: false,
             completeFunctionCalls: false,
             // Add on any completion-kind-specific resolution data that will be
             // used during resolve() calls to provide additional information.
             resolutionData: item.kind == CompletionSuggestionKind.PACKAGE_NAME
                 ? PubPackageCompletionItemResolutionInfo(
-                    file: path,
-                    offset: offset,
                     // The completion for package names may contain a trailing
                     // ': ' for convenience, so if it's there, trim it off.
                     packageName: item.completion.split(':').first,
@@ -462,7 +477,7 @@
           ),
         )
         .toList();
-    return success(completionItems);
+    return success(CompletionList(isIncomplete: false, items: completionItems));
   }
 
   /// Returns true if [node] is part of an invocation and already has an argument
@@ -495,18 +510,23 @@
     List<plugin.CompletionGetSuggestionsResult> pluginResults,
   ) {
     return pluginResults.expand((result) {
+      final insertLength = _computeInsertLength(
+        offset,
+        result.replacementOffset,
+        result.replacementLength,
+      );
+      final replacementRange =
+          toRange(lineInfo, result.replacementOffset, result.replacementLength);
+      final insertionRange =
+          toRange(lineInfo, result.replacementOffset, insertLength);
+
       return result.results.map(
         (item) => toCompletionItem(
           capabilities,
           lineInfo,
           item,
-          result.replacementOffset,
-          _computeInsertLength(
-            offset,
-            result.replacementOffset,
-            result.replacementLength,
-          ),
-          result.replacementLength,
+          replacementRange: replacementRange,
+          insertionRange: insertionRange,
           // Plugins cannot currently contribute commit characters and we should
           // not assume that the Dart ones would be correct for all of their
           // completions.
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
index 72903a8..d2d2bec 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
@@ -2,16 +2,19 @@
 // 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/lsp_protocol/protocol_custom_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart'
+    hide Element;
 import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
 import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/lsp/client_capabilities.dart';
 import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/handlers/handlers.dart';
 import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
 import 'package:analysis_server/src/lsp/mapping.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/analysis/session.dart';
-import 'package:analyzer/dart/element/element.dart' as analyzer;
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/source/line_info.dart';
 import 'package:analyzer/src/util/comment.dart' as analyzer;
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 
@@ -39,8 +42,8 @@
   ) async {
     final resolutionInfo = item.data;
 
-    if (resolutionInfo is DartCompletionItemResolutionInfo) {
-      return resolveDartCompletion(item, resolutionInfo, token);
+    if (resolutionInfo is DartSuggestionSetCompletionItemResolutionInfo) {
+      return resolveDartSuggestionSetCompletion(item, resolutionInfo, token);
     } else if (resolutionInfo is PubPackageCompletionItemResolutionInfo) {
       return resolvePubPackageCompletion(item, resolutionInfo, token);
     } else {
@@ -50,51 +53,14 @@
 
   Future<ErrorOr<CompletionItem>> resolveDartCompletion(
     CompletionItem item,
-    DartCompletionItemResolutionInfo data,
-    CancellationToken token,
-  ) async {
-    final clientCapabilities = server.clientCapabilities;
-    if (clientCapabilities == null) {
-      // This should not happen unless a client misbehaves.
-      return error(ErrorCodes.ServerNotInitialized,
-          'Requests not before server is initilized');
-    }
-
-    final file = data.file;
-    final lineInfo = server.getLineInfo(file);
-    if (lineInfo == null) {
-      return error(
-        ErrorCodes.InternalError,
-        'Line info not available for $file',
-        null,
-      );
-    }
-
-    // TODO(dantup): This logic is all repeated from domain_completion and needs
-    // extracting (with support for the different types of responses between
-    // the servers). Where is an appropriate place to put it?
-
-    var library = server.declarationsTracker?.getLibrary(data.libId);
-    if (library == null) {
-      return error(
-        ErrorCodes.InvalidParams,
-        'Library ID is not valid: ${data.libId}',
-        data.libId.toString(),
-      );
-    }
-
-    // If filterText is different to the label, it's because label has parens/args
-    // appended and we should take the basic label. We cannot use insertText as
-    // it may include snippets, whereas filterText is always just the pure string.
-    var requestedName = item.filterText ?? item.label;
-    // The label might be `MyEnum.myValue`, but we import only `MyEnum`.
-    if (requestedName.contains('.')) {
-      requestedName = requestedName.substring(
-        0,
-        requestedName.indexOf('.'),
-      );
-    }
-
+    LspClientCapabilities clientCapabilities,
+    LineInfo lineInfo,
+    CancellationToken token, {
+    required String file,
+    required Uri libraryUri,
+    required Range insertionRange,
+    required Range replacementRange,
+  }) async {
     const timeout = Duration(milliseconds: 1000);
     var timer = Stopwatch()..start();
     _latestCompletionItem = item;
@@ -110,38 +76,23 @@
           return cancelled();
         }
 
-        analyzer.LibraryElement requestedLibraryElement;
-        {
-          final result = await session.getLibraryByUri(library.uriStr);
-          if (result is LibraryElementResult) {
-            requestedLibraryElement = result.element;
-          } else {
-            return error(
-              ErrorCodes.InvalidParams,
-              'Invalid library URI: ${library.uriStr}',
-              '${result.runtimeType}',
-            );
-          }
+        final element = await _getElement(session, libraryUri, item);
+        if (element == null) {
+          return error(
+            ErrorCodes.InvalidParams,
+            'No such element: ${item.label} in $libraryUri',
+            item.label,
+          );
         }
 
         if (token.isCancellationRequested) {
           return cancelled();
         }
 
-        var requestedElement =
-            requestedLibraryElement.exportNamespace.get(requestedName);
-        if (requestedElement == null) {
-          return error(
-            ErrorCodes.InvalidParams,
-            'No such element: $requestedName in ${library.uriStr}',
-            requestedName,
-          );
-        }
-
         var newInsertText = item.insertText ?? item.label;
         final builder = ChangeBuilder(session: session);
         await builder.addDartFileEdit(file, (builder) {
-          final result = builder.importLibraryElement(library.uri);
+          final result = builder.importLibraryElement(libraryUri);
           if (result.prefix != null) {
             newInsertText = '${result.prefix}.$newInsertText';
           }
@@ -169,21 +120,30 @@
               arguments: [workspaceEdit]);
         }
 
-        // Documentation is added on during resolve for LSP.
         final formats = clientCapabilities.completionDocumentationFormats;
-        final supportsInsertReplace =
-            clientCapabilities.insertReplaceCompletionRanges;
         final dartDoc =
-            analyzer.getDartDocPlainText(requestedElement.documentationComment);
+            analyzer.getDartDocPlainText(element.documentationComment);
         final documentation =
             dartDoc != null ? asStringOrMarkupContent(formats, dartDoc) : null;
+        final supportsInsertReplace =
+            clientCapabilities.insertReplaceCompletionRanges;
+
+        // If the only URI we have is a file:// URI, display it as relative to
+        // the file we're importing into, rather than the full URI.
+        final pathContext = server.resourceProvider.pathContext;
+        final autoImportDisplayUri = libraryUri.isScheme('file')
+            ? pathContext.relative(
+                libraryUri.toFilePath(),
+                from: pathContext.dirname(file),
+              )
+            : libraryUri.toString();
 
         return success(CompletionItem(
           label: item.label,
           kind: item.kind,
           tags: item.tags,
           detail: thisFilesChanges.isNotEmpty
-              ? "Auto import from '${data.displayUri}'\n\n${item.detail ?? ''}"
+              ? "Auto import from '$autoImportDisplayUri'\n\n${item.detail ?? ''}"
                   .trim()
               : item.detail,
           documentation: documentation,
@@ -193,17 +153,17 @@
           filterText: item.filterText,
           insertText: newInsertText,
           insertTextFormat: item.insertTextFormat,
-          textEdit: supportsInsertReplace && data.iLength != data.rLength
+          textEdit: supportsInsertReplace && insertionRange != replacementRange
               ? Either2<TextEdit, InsertReplaceEdit>.t2(
                   InsertReplaceEdit(
-                    insert: toRange(lineInfo, data.rOffset, data.iLength),
-                    replace: toRange(lineInfo, data.rOffset, data.rLength),
+                    insert: insertionRange,
+                    replace: replacementRange,
                     newText: newInsertText,
                   ),
                 )
               : Either2<TextEdit, InsertReplaceEdit>.t1(
                   TextEdit(
-                    range: toRange(lineInfo, data.rOffset, data.rLength),
+                    range: replacementRange,
                     newText: newInsertText,
                   ),
                 ),
@@ -229,6 +189,52 @@
     );
   }
 
+  Future<ErrorOr<CompletionItem>> resolveDartSuggestionSetCompletion(
+    CompletionItem item,
+    DartSuggestionSetCompletionItemResolutionInfo data,
+    CancellationToken token,
+  ) async {
+    final clientCapabilities = server.clientCapabilities;
+    if (clientCapabilities == null) {
+      // This should not happen unless a client misbehaves.
+      return error(ErrorCodes.ServerNotInitialized,
+          'Requests not before server is initilized');
+    }
+
+    final file = data.file;
+    final lineInfo = server.getLineInfo(file);
+    if (lineInfo == null) {
+      return error(
+        ErrorCodes.InternalError,
+        'Line info not available for $file',
+        null,
+      );
+    }
+
+    var library = server.declarationsTracker?.getLibrary(data.libId);
+    if (library == null) {
+      return error(
+        ErrorCodes.InvalidParams,
+        'Library ID is not valid: ${data.libId}',
+        data.libId.toString(),
+      );
+    }
+
+    final insertionRange = toRange(lineInfo, data.rOffset, data.iLength);
+    final replacementRange = toRange(lineInfo, data.rOffset, data.rLength);
+
+    return resolveDartCompletion(
+      item,
+      clientCapabilities,
+      lineInfo,
+      token,
+      file: file,
+      libraryUri: library.uri,
+      insertionRange: insertionRange,
+      replacementRange: replacementRange,
+    );
+  }
+
   Future<ErrorOr<CompletionItem>> resolvePubPackageCompletion(
     CompletionItem item,
     PubPackageCompletionItemResolutionInfo data,
@@ -265,4 +271,31 @@
       data: item.data,
     ));
   }
+
+  /// Gets the [Element] for the completion item [item] in [libraryUri].
+  Future<Element?> _getElement(
+    AnalysisSession session,
+    Uri libraryUri,
+    CompletionItem item,
+  ) async {
+    // If filterText is different to the label, it's because label has
+    // parens/args appended so we should take the filterText to get the
+    // elements name without. We cannot use insertText as it may include
+    // snippets, whereas filterText is always just the pure string.
+    var name = item.filterText ?? item.label;
+
+    // The label might be `MyEnum.myValue`, but we need to find `MyEnum`.
+    if (name.contains('.')) {
+      name = name.substring(0, name.indexOf('.'));
+    }
+
+    // TODO(dantup): This is not handling default constructors or enums
+    // correctly, so they will both show dart docs from the class/enum and not
+    // the constructor/enum member.
+
+    final result = await session.getLibraryByUri(libraryUri.toString());
+    return result is LibraryElementResult
+        ? result.element.exportNamespace.get(name)
+        : null;
+  }
 }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
index 0d9eb19..abc53cf 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
@@ -61,6 +61,7 @@
   InitializedStateMessageHandler(
     LspAnalysisServer server,
   ) : super(server) {
+    final options = server.initializationOptions;
     reject(Method.initialize, ServerErrorCodes.ServerAlreadyInitialized,
         'Server already initialized');
     reject(Method.initialized, ServerErrorCodes.ServerAlreadyInitialized,
@@ -75,13 +76,10 @@
       TextDocumentCloseHandler(server),
     );
     registerHandler(HoverHandler(server));
-    registerHandler(CompletionHandler(
-      server,
-      server.initializationOptions.suggestFromUnimportedLibraries,
-    ));
+    registerHandler(CompletionHandler(server, options));
+    registerHandler(CompletionResolveHandler(server));
     registerHandler(DocumentColorHandler(server));
     registerHandler(DocumentColorPresentationHandler(server));
-    registerHandler(CompletionResolveHandler(server));
     registerHandler(SignatureHelpHandler(server));
     registerHandler(DefinitionHandler(server));
     registerHandler(SuperHandler(server));
@@ -94,12 +92,8 @@
     registerHandler(DocumentSymbolHandler(server));
     registerHandler(CodeActionHandler(server));
     registerHandler(ExecuteCommandHandler(server));
-    registerHandler(
-      WorkspaceFoldersHandler(
-        server,
-        !server.initializationOptions.onlyAnalyzeProjectsWithOpenFiles,
-      ),
-    );
+    registerHandler(WorkspaceFoldersHandler(
+        server, !options.onlyAnalyzeProjectsWithOpenFiles));
     registerHandler(PrepareRenameHandler(server));
     registerHandler(RenameHandler(server));
     registerHandler(FoldingHandler(server));
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index 305bc67..c182eee 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -418,7 +418,7 @@
         ? InsertTextMode.asIs
         : null,
     // data, used for completionItem/resolve.
-    data: lsp.DartCompletionItemResolutionInfo(
+    data: lsp.DartSuggestionSetCompletionItemResolutionInfo(
         file: file,
         offset: offset,
         libId: includedSuggestionSet.id,
@@ -1007,10 +1007,9 @@
 lsp.CompletionItem toCompletionItem(
   LspClientCapabilities capabilities,
   server.LineInfo lineInfo,
-  server.CompletionSuggestion suggestion,
-  int replacementOffset,
-  int insertLength,
-  int replacementLength, {
+  server.CompletionSuggestion suggestion, {
+  Range? replacementRange,
+  Range? insertionRange,
   required bool includeCommitCharacters,
   required bool completeFunctionCalls,
   CompletionItemResolutionInfo? resolutionData,
@@ -1127,20 +1126,22 @@
     insertTextMode: supportsAsIsInsertMode && isMultilineCompletion
         ? InsertTextMode.asIs
         : null,
-    textEdit: supportsInsertReplace && insertLength != replacementLength
-        ? Either2<TextEdit, InsertReplaceEdit>.t2(
-            InsertReplaceEdit(
-              insert: toRange(lineInfo, replacementOffset, insertLength),
-              replace: toRange(lineInfo, replacementOffset, replacementLength),
-              newText: insertText,
-            ),
-          )
-        : Either2<TextEdit, InsertReplaceEdit>.t1(
-            TextEdit(
-              range: toRange(lineInfo, replacementOffset, replacementLength),
-              newText: insertText,
-            ),
-          ),
+    textEdit: (insertionRange == null || replacementRange == null)
+        ? null
+        : supportsInsertReplace && insertionRange != replacementRange
+            ? Either2<TextEdit, InsertReplaceEdit>.t2(
+                InsertReplaceEdit(
+                  insert: insertionRange,
+                  replace: replacementRange,
+                  newText: insertText,
+                ),
+              )
+            : Either2<TextEdit, InsertReplaceEdit>.t1(
+                TextEdit(
+                  range: replacementRange,
+                  newText: insertText,
+                ),
+              ),
   );
 }
 
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart
index cbacc55..01f2b09 100644
--- a/pkg/analysis_server/test/lsp/completion_dart_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -1268,7 +1268,7 @@
     expect(res.any((c) => c.label == 'UniqueNamedClassForLspThree'), isTrue);
   }
 
-  Future<void> test_suggestionSets() async {
+  Future<void> test_unimportedSymbols() async {
     newFile(
       join(projectFolderPath, 'other_file.dart'),
       content: '''
@@ -1342,7 +1342,7 @@
   }
 
   Future<void>
-      test_suggestionSets_doesNotDuplicate_importedViaMultipleLibraries() async {
+      test_unimportedSymbols_doesNotDuplicate_importedViaMultipleLibraries() async {
     // An item that's already imported through multiple libraries that
     // export it should not result in multiple entries.
     newFile(
@@ -1387,7 +1387,7 @@
   }
 
   Future<void>
-      test_suggestionSets_doesNotDuplicate_importedViaSingleLibrary() async {
+      test_unimportedSymbols_doesNotDuplicate_importedViaSingleLibrary() async {
     // An item that's already imported through a library that exports it
     // should not result in multiple entries.
     newFile(
@@ -1430,7 +1430,7 @@
     expect(completions, hasLength(1));
   }
 
-  Future<void> test_suggestionSets_doesNotFilterSymbolsWithSameName() async {
+  Future<void> test_unimportedSymbols_doesNotFilterSymbolsWithSameName() async {
     // Classes here are not re-exports, so should not be filtered out.
     newFile(
       join(projectFolderPath, 'source_file1.dart'),
@@ -1472,7 +1472,7 @@
     expectAutoImportCompletion(resolvedCompletions, '../source_file3.dart');
   }
 
-  Future<void> test_suggestionSets_enumValues() async {
+  Future<void> test_unimportedSymbols_enumValues() async {
     newFile(
       join(projectFolderPath, 'source_file.dart'),
       content: '''
@@ -1536,7 +1536,7 @@
     '''));
   }
 
-  Future<void> test_suggestionSets_enumValuesAlreadyImported() async {
+  Future<void> test_unimportedSymbols_enumValuesAlreadyImported() async {
     newFile(
       join(projectFolderPath, 'lib', 'source_file.dart'),
       content: '''
@@ -1577,10 +1577,10 @@
     expect(completions, hasLength(1));
     final resolved = await resolveCompletion(completions.first);
     // It should not include auto-import text since it's already imported.
-    expect(resolved.detail, isNull);
+    expect(resolved.detail, isNot(contains('Auto import from')));
   }
 
-  Future<void> test_suggestionSets_filtersOutAlreadyImportedSymbols() async {
+  Future<void> test_unimportedSymbols_filtersOutAlreadyImportedSymbols() async {
     newFile(
       join(projectFolderPath, 'lib', 'source_file.dart'),
       content: '''
@@ -1623,7 +1623,7 @@
     expect(resolved.detail, isNull);
   }
 
-  Future<void> test_suggestionSets_importsPackageUri() async {
+  Future<void> test_unimportedSymbols_importsPackageUri() async {
     newFile(
       join(projectFolderPath, 'lib', 'my_class.dart'),
       content: 'class MyClass {}',
@@ -1654,7 +1654,7 @@
   }
 
   Future<void>
-      test_suggestionSets_includesReexportedSymbolsForEachFile() async {
+      test_unimportedSymbols_includesReexportedSymbolsForEachFile() async {
     newFile(
       join(projectFolderPath, 'source_file.dart'),
       content: '''
@@ -1700,7 +1700,7 @@
     expectAutoImportCompletion(resolvedCompletions, '../reexport2.dart');
   }
 
-  Future<void> test_suggestionSets_insertReplaceRanges() async {
+  Future<void> test_unimportedSymbols_insertReplaceRanges() async {
     newFile(
       join(projectFolderPath, 'other_file.dart'),
       content: '''
@@ -1792,7 +1792,7 @@
     '''));
   }
 
-  Future<void> test_suggestionSets_insertsIntoPartFiles() async {
+  Future<void> test_unimportedSymbols_insertsIntoPartFiles() async {
     // File we'll be adding an import for.
     newFile(
       join(projectFolderPath, 'other_file.dart'),
@@ -1883,7 +1883,7 @@
 part 'main.dart';'''));
   }
 
-  Future<void> test_suggestionSets_members() async {
+  Future<void> test_unimportedSymbols_members() async {
     newFile(
       join(projectFolderPath, 'source_file.dart'),
       content: '''
@@ -1961,7 +1961,7 @@
   /// (as it always used 0 as the modification stamp) which would prevent
   /// completion including items from files that were open (had overlays).
   /// https://github.com/Dart-Code/Dart-Code/issues/2286#issuecomment-658597532
-  Future<void> test_suggestionSets_modifiedFiles() async {
+  Future<void> test_unimportedSymbols_modifiedFiles() async {
     final otherFilePath = join(projectFolderPath, 'lib', 'other_file.dart');
     final otherFileUri = Uri.file(otherFilePath);
 
@@ -1991,7 +1991,7 @@
     expect(matching, hasLength(1));
   }
 
-  Future<void> test_suggestionSets_namedConstructors() async {
+  Future<void> test_unimportedSymbols_namedConstructors() async {
     newFile(
       join(projectFolderPath, 'other_file.dart'),
       content: '''
@@ -2050,7 +2050,8 @@
     '''));
   }
 
-  Future<void> test_suggestionSets_preferRelativeImportsLib_insideLib() async {
+  Future<void>
+      test_unimportedSymbols_preferRelativeImportsLib_insideLib() async {
     _enableLints([LintNames.prefer_relative_imports]);
     final importingFilePath =
         join(projectFolderPath, 'lib', 'nested1', 'main.dart');
@@ -2085,7 +2086,8 @@
     );
   }
 
-  Future<void> test_suggestionSets_preferRelativeImportsLib_outsideLib() async {
+  Future<void>
+      test_unimportedSymbols_preferRelativeImportsLib_outsideLib() async {
     // Files outside of the lib folder should still get absolute imports to
     // files inside lib, even with the lint enabled.
     _enableLints([LintNames.prefer_relative_imports]);
@@ -2122,7 +2124,7 @@
     );
   }
 
-  Future<void> test_suggestionSets_unavailableIfDisabled() async {
+  Future<void> test_unimportedSymbols_unavailableIfDisabled() async {
     newFile(
       join(projectFolderPath, 'other_file.dart'),
       content: 'class InOtherFile {}',
@@ -2137,7 +2139,9 @@
     final initialAnalysis = waitForAnalysisComplete();
     // Support applyEdit, but explicitly disable the suggestions.
     await initialize(
-      initializationOptions: {'suggestFromUnimportedLibraries': false},
+      initializationOptions: {
+        'suggestFromUnimportedLibraries': false,
+      },
       workspaceCapabilities:
           withApplyEditSupport(emptyWorkspaceClientCapabilities),
     );
@@ -2151,7 +2155,7 @@
     expect(completion, isNull);
   }
 
-  Future<void> test_suggestionSets_unavailableWithoutApplyEdit() async {
+  Future<void> test_unimportedSymbols_unavailableWithoutApplyEdit() async {
     // If client doesn't advertise support for workspace/applyEdit, we won't
     // include suggestion sets.
     newFile(
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index 851966e..4bc57a0 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -1055,6 +1055,12 @@
   }
 
   Future<List<CompletionItem>> getCompletion(Uri uri, Position pos,
+      {CompletionContext? context}) async {
+    final response = await getCompletionList(uri, pos, context: context);
+    return response.items;
+  }
+
+  Future<CompletionList> getCompletionList(Uri uri, Position pos,
       {CompletionContext? context}) {
     final request = makeRequest(
       Method.textDocument_completion,
@@ -1064,8 +1070,7 @@
         position: pos,
       ),
     );
-    return expectSuccessfulResponseTo(
-        request, _fromJsonList(CompletionItem.fromJson));
+    return expectSuccessfulResponseTo(request, CompletionList.fromJson);
   }
 
   Future<Either2<List<Location>, List<LocationLink>>> getDefinition(
diff --git a/pkg/analysis_server/tool/lsp_spec/generate_all.dart b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
index f1783c2..58a60e2 100644
--- a/pkg/analysis_server/tool/lsp_spec/generate_all.dart
+++ b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
@@ -251,17 +251,17 @@
       ],
     ),
     interface(
+      // Used as a base class for all resolution data classes.
       'CompletionItemResolutionInfo',
-      [
-        field('file', type: 'string'),
-        field('offset', type: 'int'),
-      ],
+      [],
     ),
     interface(
-      'DartCompletionItemResolutionInfo',
+      'DartSuggestionSetCompletionItemResolutionInfo',
       [
         // These fields have short-ish names because they're on the payload
         // for all suggestion-set backed completions.
+        field('file', type: 'string'),
+        field('offset', type: 'int'),
         field('libId', type: 'int'),
         field('displayUri', type: 'string'),
         field('rOffset', type: 'int'), // replacementOffset
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index a38e3c7..e4e2869 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -53,9 +53,7 @@
 namespace dart {
 
 DECLARE_FLAG(bool, print_class_table);
-DEFINE_FLAG(bool, keep_code, false, "Keep deoptimized code for profiling.");
 DEFINE_FLAG(bool, trace_shutdown, false, "Trace VM shutdown on stderr");
-DECLARE_FLAG(bool, strong);
 
 Isolate* Dart::vm_isolate_ = NULL;
 int64_t Dart::start_time_micros_ = 0;
diff --git a/tools/VERSION b/tools/VERSION
index 633bc51..fd91618 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 65
+PRERELEASE 66
 PRERELEASE_PATCH 0
\ No newline at end of file