[analyzer] Migrate remaining LSP code to null-safe

Change-Id: I52c7d16bdaf9f68148a8d7a956330bc54608ec43
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/195980
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Danny Tuppeny
2021-04-19 19:35:28 +00:00
committed by commit-bot@chromium.org
parent 543d653ca8
commit 77466f2b83
56 changed files with 869 additions and 791 deletions
@@ -188,7 +188,7 @@ class CompletionItemResolutionInfo implements ToJsonable {
}
final String file;
final num offset;
final int offset;
Map<String, dynamic> toJson() {
var __result = <String, dynamic>{};
@@ -226,8 +226,8 @@ class CompletionItemResolutionInfo implements ToJsonable {
reporter.reportError('must not be null');
return false;
}
if (!(obj['offset'] is num)) {
reporter.reportError('must be of type num');
if (!(obj['offset'] is int)) {
reporter.reportError('must be of type int');
return false;
}
} finally {
@@ -295,11 +295,11 @@ class DartCompletionItemResolutionInfo
final String displayUri;
final String file;
final num iLength;
final num libId;
final num offset;
final num rLength;
final num rOffset;
final int iLength;
final int libId;
final int offset;
final int rLength;
final int rOffset;
Map<String, dynamic> toJson() {
var __result = <String, dynamic>{};
@@ -325,8 +325,8 @@ class DartCompletionItemResolutionInfo
reporter.reportError('must not be null');
return false;
}
if (!(obj['libId'] is num)) {
reporter.reportError('must be of type num');
if (!(obj['libId'] is int)) {
reporter.reportError('must be of type int');
return false;
}
} finally {
@@ -359,8 +359,8 @@ class DartCompletionItemResolutionInfo
reporter.reportError('must not be null');
return false;
}
if (!(obj['rOffset'] is num)) {
reporter.reportError('must be of type num');
if (!(obj['rOffset'] is int)) {
reporter.reportError('must be of type int');
return false;
}
} finally {
@@ -376,8 +376,8 @@ class DartCompletionItemResolutionInfo
reporter.reportError('must not be null');
return false;
}
if (!(obj['iLength'] is num)) {
reporter.reportError('must be of type num');
if (!(obj['iLength'] is int)) {
reporter.reportError('must be of type int');
return false;
}
} finally {
@@ -393,8 +393,8 @@ class DartCompletionItemResolutionInfo
reporter.reportError('must not be null');
return false;
}
if (!(obj['rLength'] is num)) {
reporter.reportError('must be of type num');
if (!(obj['rLength'] is int)) {
reporter.reportError('must be of type int');
return false;
}
} finally {
@@ -427,8 +427,8 @@ class DartCompletionItemResolutionInfo
reporter.reportError('must not be null');
return false;
}
if (!(obj['offset'] is num)) {
reporter.reportError('must be of type num');
if (!(obj['offset'] is int)) {
reporter.reportError('must be of type int');
return false;
}
} finally {
@@ -484,7 +484,7 @@ class DartDiagnosticServer implements ToJsonable {
return DartDiagnosticServer(port: port);
}
final num port;
final int port;
Map<String, dynamic> toJson() {
var __result = <String, dynamic>{};
@@ -504,8 +504,8 @@ class DartDiagnosticServer implements ToJsonable {
reporter.reportError('must not be null');
return false;
}
if (!(obj['port'] is num)) {
reporter.reportError('must be of type num');
if (!(obj['port'] is int)) {
reporter.reportError('must be of type int');
return false;
}
} finally {
@@ -1207,7 +1207,7 @@ class PubPackageCompletionItemResolutionInfo
}
final String file;
final num offset;
final int offset;
final String packageName;
Map<String, dynamic> toJson() {
@@ -1264,8 +1264,8 @@ class PubPackageCompletionItemResolutionInfo
reporter.reportError('must not be null');
return false;
}
if (!(obj['offset'] is num)) {
reporter.reportError('must be of type num');
if (!(obj['offset'] is int)) {
reporter.reportError('must be of type int');
return false;
}
} finally {
@@ -6320,10 +6320,10 @@ class CompletionItemKind {
const CompletionItemKind(this._value);
const CompletionItemKind.fromJson(this._value);
final num _value;
final int _value;
static bool canParse(Object obj, LspJsonReporter reporter) {
return obj is num;
return obj is int;
}
static const Text = CompletionItemKind(1);
@@ -6370,10 +6370,10 @@ class CompletionItemTag {
const CompletionItemTag(this._value);
const CompletionItemTag.fromJson(this._value);
final num _value;
final int _value;
static bool canParse(Object obj, LspJsonReporter reporter) {
return obj is num;
return obj is int;
}
/// Render a completion as obsolete, usually using a strike-out.
@@ -10715,10 +10715,10 @@ class DocumentHighlightKind {
const DocumentHighlightKind(this._value);
const DocumentHighlightKind.fromJson(this._value);
final num _value;
final int _value;
static bool canParse(Object obj, LspJsonReporter reporter) {
return obj is num;
return obj is int;
}
/// A textual occurrence.
@@ -13758,10 +13758,10 @@ class FileChangeType {
const FileChangeType(this._value);
const FileChangeType.fromJson(this._value);
final num _value;
final int _value;
static bool canParse(Object obj, LspJsonReporter reporter) {
return obj is num;
return obj is int;
}
/// The file got created.
@@ -16902,7 +16902,7 @@ class InsertTextFormat {
const InsertTextFormat._(this._value);
const InsertTextFormat.fromJson(this._value);
final num _value;
final int _value;
static bool canParse(Object obj, LspJsonReporter reporter) {
switch (obj) {
@@ -18204,10 +18204,10 @@ class MessageType {
const MessageType(this._value);
const MessageType.fromJson(this._value);
final num _value;
final int _value;
static bool canParse(Object obj, LspJsonReporter reporter) {
return obj is num;
return obj is int;
}
/// An error message.
@@ -19499,10 +19499,10 @@ class Position implements ToJsonable {
///
/// If the character value is greater than the line length it defaults back to
/// the line length.
final num character;
final int character;
/// Line position in a document (zero-based).
final num line;
final int line;
Map<String, dynamic> toJson() {
var __result = <String, dynamic>{};
@@ -19523,8 +19523,8 @@ class Position implements ToJsonable {
reporter.reportError('must not be null');
return false;
}
if (!(obj['line'] is num)) {
reporter.reportError('must be of type num');
if (!(obj['line'] is int)) {
reporter.reportError('must be of type int');
return false;
}
} finally {
@@ -19540,8 +19540,8 @@ class Position implements ToJsonable {
reporter.reportError('must not be null');
return false;
}
if (!(obj['character'] is num)) {
reporter.reportError('must be of type num');
if (!(obj['character'] is int)) {
reporter.reportError('must be of type int');
return false;
}
} finally {
@@ -28247,10 +28247,10 @@ class SymbolKind {
const SymbolKind(this._value);
const SymbolKind.fromJson(this._value);
final num _value;
final int _value;
static bool canParse(Object obj, LspJsonReporter reporter) {
return obj is num;
return obj is int;
}
static const File = SymbolKind(1);
@@ -29926,10 +29926,10 @@ class TextDocumentSaveReason {
const TextDocumentSaveReason(this._value);
const TextDocumentSaveReason.fromJson(this._value);
final num _value;
final int _value;
static bool canParse(Object obj, LspJsonReporter reporter) {
return obj is num;
return obj is int;
}
/// Manually triggered, e.g. by the user pressing save, by starting debugging,
@@ -30183,10 +30183,10 @@ class TextDocumentSyncKind {
const TextDocumentSyncKind(this._value);
const TextDocumentSyncKind.fromJson(this._value);
final num _value;
final int _value;
static bool canParse(Object obj, LspJsonReporter reporter) {
return obj is num;
return obj is int;
}
/// Documents should not be synced at all.
@@ -31206,10 +31206,10 @@ class WatchKind {
const WatchKind(this._value);
const WatchKind.fromJson(this._value);
final num _value;
final int _value;
static bool canParse(Object obj, LspJsonReporter reporter) {
return obj is num;
return obj is int;
}
/// Interested in create events.
@@ -73,8 +73,8 @@ abstract class AbstractAnalysisServer {
/// The object used to manage the SDK's known to this server.
final DartSdkManager sdkManager;
/// The [SearchEngine] for this server, may be `null` if indexing is disabled.
SearchEngine? searchEngine;
/// The [SearchEngine] for this server.
late SearchEngine searchEngine;
late ByteStore byteStore;
@@ -85,9 +85,8 @@ class EditDomainHandler extends AbstractRequestHandler {
/// [server].
EditDomainHandler(AnalysisServer server) : super(server) {
var search = searchEngine = server.searchEngine;
refactoringWorkspace = search == null
? null
: RefactoringWorkspace(server.driverMap.values, search);
refactoringWorkspace =
RefactoringWorkspace(server.driverMap.values, search);
_newRefactoringManager();
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'dart:async';
import 'dart:convert';
import 'dart:io';
@@ -51,7 +49,7 @@ class LspByteStreamServerChannel implements LspServerCommunicationChannel {
@override
void listen(void Function(Message message) onMessage,
{Function onError, void Function() onDone}) {
{Function? onError, void Function()? onDone}) {
_input.transform(LspPacketTransformer()).listen(
(String data) => _readMessage(data, onMessage),
onError: onError,
@@ -95,7 +93,7 @@ class LspByteStreamServerChannel implements LspServerCommunicationChannel {
}
/// Sends a message prefixed with the required LSP headers.
void _sendLsp(Map<String, Object> json) {
void _sendLsp(Map<String, dynamic> json) {
// Don't send any further responses after the communication channel is
// closed.
if (_closeRequested) {
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
@@ -20,7 +18,7 @@ class OrganizeImportsCommandHandler extends SimpleEditCommandHandler {
String get commandName => 'Organize Imports';
@override
Future<ErrorOr<void>> handle(List<dynamic> arguments,
Future<ErrorOr<void>> handle(List<dynamic>? arguments,
ProgressReporter reporter, CancellationToken cancellationToken) async {
if (arguments == null || arguments.length != 1 || arguments[0] is! String) {
return ErrorOr.error(ResponseError(
@@ -43,8 +41,8 @@ class OrganizeImportsCommandHandler extends SimpleEditCommandHandler {
}
return result.mapResult((result) {
final code = result.content;
final unit = result.unit;
final code = result.content!;
final unit = result.unit!;
if (hasScanParseErrors(result.errors)) {
// It's not uncommon for editors to run this command automatically on-save
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
@@ -26,7 +24,7 @@ class PerformRefactorCommandHandler extends SimpleEditCommandHandler {
String get commandName => 'Perform Refactor';
@override
Future<ErrorOr<void>> handle(List<dynamic> arguments,
Future<ErrorOr<void>> handle(List<dynamic>? arguments,
ProgressReporter reporter, CancellationToken cancellationToken) async {
if (arguments == null ||
arguments.length != 6 ||
@@ -60,26 +58,29 @@ class PerformRefactorCommandHandler extends SimpleEditCommandHandler {
// If the token we were given is not cancellable, replace it with one that
// is for the rest of this request, as a future refactor may need to cancel
// this request.
if (cancellationToken is! CancelableToken) {
cancellationToken = CancelableToken();
}
_manager.begin(cancellationToken);
// The original token should be kept and also checked for cancellation.
final cancelableToken = cancellationToken is CancelableToken
? cancellationToken
: CancelableToken();
_manager.begin(cancelableToken);
try {
reporter.begin('Refactoring…');
final status = await refactoring.checkAllConditions();
if (status.hasError) {
return error(ServerErrorCodes.RefactorFailed, status.message);
return error(ServerErrorCodes.RefactorFailed, status.message!);
}
if (cancellationToken.isCancellationRequested) {
if (cancellationToken.isCancellationRequested ||
cancelableToken.isCancellationRequested) {
return error(ErrorCodes.RequestCancelled, 'Request was cancelled');
}
final change = await refactoring.createChange();
if (cancellationToken.isCancellationRequested) {
if (cancellationToken.isCancellationRequested ||
cancelableToken.isCancellationRequested) {
return error(ErrorCodes.RequestCancelled, 'Request was cancelled');
}
@@ -94,7 +95,7 @@ class PerformRefactorCommandHandler extends SimpleEditCommandHandler {
} on InconsistentAnalysisException {
return fileModifiedError;
} finally {
_manager.end(cancellationToken);
_manager.end(cancelableToken);
reporter.end();
}
});
@@ -106,7 +107,7 @@ class PerformRefactorCommandHandler extends SimpleEditCommandHandler {
ResolvedUnitResult result,
int offset,
int length,
Map<String, dynamic> options,
Map<String, dynamic>? options,
) async {
switch (kind) {
case RefactoringKind.EXTRACT_METHOD:
@@ -168,7 +169,7 @@ class PerformRefactorCommandHandler extends SimpleEditCommandHandler {
/// Manages a running refactor to help ensure only one refactor runs at a time.
class _RefactorManager {
/// The cancellation token for the current in-progress refactor (or null).
CancelableToken _currentRefactoringCancellationToken;
CancelableToken? _currentRefactoringCancellationToken;
/// Begins a new refactor, cancelling any other in-progress refactors.
void begin(CancelableToken cancelToken) {
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
@@ -26,7 +24,7 @@ class SendWorkspaceEditCommandHandler extends SimpleEditCommandHandler {
String get commandName => 'Send Workspace Edit';
@override
Future<ErrorOr<void>> handle(List<dynamic> arguments,
Future<ErrorOr<void>> handle(List<dynamic>? arguments,
ProgressReporter reporter, CancellationToken cancellationToken) async {
if (arguments == null ||
arguments.length != 1 ||
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
@@ -39,9 +37,22 @@ abstract class SimpleEditCommandHandler
return success(null);
}
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 lineInfo = unit.lineInfo;
if (lineInfo == null) {
return error(ErrorCodes.InternalError,
'Unable to produce edits for $docIdentifier as no LineInfo was found');
}
final workspaceEdit = toWorkspaceEdit(
server.clientCapabilities,
[FileEditInformation(docIdentifier, unit.lineInfo, edits)],
clientCapabilities,
[FileEditInformation(docIdentifier, lineInfo, edits)],
);
return sendWorkspaceEditToClient(workspaceEdit);
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
@@ -21,7 +19,7 @@ class SortMembersCommandHandler extends SimpleEditCommandHandler {
String get commandName => 'Sort Members';
@override
Future<ErrorOr<void>> handle(List<dynamic> arguments,
Future<ErrorOr<void>> handle(List<dynamic>? arguments,
ProgressReporter reporter, CancellationToken cancellationToken) async {
if (arguments == null || arguments.length != 1 || arguments[0] is! String) {
return ErrorOr.error(ResponseError(
@@ -38,20 +36,19 @@ class SortMembersCommandHandler extends SimpleEditCommandHandler {
final docIdentifier = server.getVersionedDocumentIdentifier(path);
var driver = server.getAnalysisDriver(path);
final result0 = await driver?.parseFile2(path);
final result = await driver?.parseFile2(path);
if (cancellationToken.isCancellationRequested) {
return error(ErrorCodes.RequestCancelled, 'Request was cancelled');
}
if (result0 is! ParsedUnitResult) {
if (result is! ParsedUnitResult) {
return ErrorOr.error(ResponseError(
code: ServerErrorCodes.FileNotAnalyzed,
message: '$commandName is only available for analyzed files',
));
}
// TODO(scheglov) inline after migration
var result = result0 as ParsedUnitResult;
final code = result.content;
final unit = result.unit;
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
@@ -23,7 +21,13 @@ class DiagnosticServerHandler
@override
Future<ErrorOr<DartDiagnosticServer>> handle(
void _, CancellationToken token) async {
final port = await server.diagnosticServer.getServerPort();
final diagnosticServer = server.diagnosticServer;
if (diagnosticServer == null) {
return error(ServerErrorCodes.FeatureDisabled,
'The diagnostic server is not available');
}
final port = await diagnosticServer.getServerPort();
return success(DartDiagnosticServer(port: port));
}
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
@@ -11,9 +9,10 @@ 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:analysis_server/src/search/type_hierarchy.dart';
import 'package:collection/collection.dart';
class SuperHandler
extends MessageHandler<TextDocumentPositionParams, Location> {
extends MessageHandler<TextDocumentPositionParams, Location?> {
SuperHandler(LspAnalysisServer server) : super(server);
@override
Method get handlesMessage => CustomMethods.super_;
@@ -23,7 +22,7 @@ class SuperHandler
TextDocumentPositionParams.jsonHandler;
@override
Future<ErrorOr<Location>> handle(
Future<ErrorOr<Location?>> handle(
TextDocumentPositionParams params, CancellationToken token) async {
if (!isDartDocument(params.textDocument)) {
return success(null);
@@ -44,8 +43,8 @@ class SuperHandler
// finding supers even if the cursor location was inside a method or on its
// return type.
var element = server.getElementOfNode(node);
while (element == null && node.parent != null) {
node = node.parent;
while (element == null && node?.parent != null) {
node = node?.parent;
element = server.getElementOfNode(node);
}
if (element == null) {
@@ -64,21 +63,22 @@ class SuperHandler
// The class will have a memberElement if we were searching for an element
// otherwise we're looking for a class.
final isMember = items.first.memberElement != null;
final superItem = items.skip(1).firstWhere(
(elm) =>
isMember ? elm.memberElement != null : elm.classElement != null,
orElse: () => null,
);
final superItem = items.skip(1).firstWhereOrNull(
(elm) => isMember ? elm.memberElement != null : true);
if (superItem == null) {
final location = superItem?.memberElement?.location ??
superItem?.classElement.location;
if (location == null) {
return success(null);
}
final location = isMember
? superItem.memberElement.location
: superItem.classElement.location;
final locationLineInfo = server.getLineInfo(location.file);
if (locationLineInfo == null) {
return success(null);
}
return success(toLocation(location, server.getLineInfo(location.file)));
return success(toLocation(location, locationLineInfo));
});
}
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -32,13 +30,12 @@ class WorkspaceFoldersHandler
return success(null);
}
final added = params?.event?.added
?.map((wf) => Uri.parse(wf.uri).toFilePath())
?.toList();
final added =
params.event.added.map((wf) => Uri.parse(wf.uri).toFilePath()).toList();
final removed = params?.event?.removed
?.map((wf) => Uri.parse(wf.uri).toFilePath())
?.toList();
final removed = params.event.removed
.map((wf) => Uri.parse(wf.uri).toFilePath())
.toList();
server.updateWorkspaceFolders(added, removed);
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
@@ -50,18 +48,21 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
return success(const []);
}
final supportsApplyEdit = server.clientCapabilities.applyEdit;
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 supportsLiteralCodeActions =
server.clientCapabilities.literalCodeActions;
final supportedKinds = server.clientCapabilities.codeActionKinds;
final supportedDiagnosticTags = server.clientCapabilities.diagnosticTags;
final supportsApplyEdit = clientCapabilities.applyEdit;
final supportsLiteralCodeActions = clientCapabilities.literalCodeActions;
final supportedKinds = clientCapabilities.codeActionKinds;
final supportedDiagnosticTags = clientCapabilities.diagnosticTags;
final unit = await path.mapResult(requireResolvedUnit);
bool shouldIncludeKind(CodeActionKind kind) {
bool shouldIncludeKind(CodeActionKind? kind) {
/// Checks whether the kind matches the [wanted] kind.
///
/// If `wanted` is `refactor.foo` then:
@@ -72,8 +73,9 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
kind == wanted || kind.toString().startsWith('${wanted.toString()}.');
// If the client wants only a specific set, use only that filter.
if (params.context?.only != null) {
return params.context.only.any(isMatch);
final only = params.context.only;
if (only != null) {
return only.any(isMatch);
}
// Otherwise, filter out anything not supported by the client (if they
@@ -108,11 +110,14 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
}
/// Creates a comparer for [CodeActions] that compares the column distance from [pos].
Function(CodeAction a, CodeAction b) _codeActionColumnDistanceComparer(
int Function(CodeAction a, CodeAction b) _codeActionColumnDistanceComparer(
Position pos) {
Position posOf(CodeAction action) => action.diagnostics.isNotEmpty
? action.diagnostics.first.range.start
: pos;
Position posOf(CodeAction action) {
final diagnostics = action.diagnostics;
return diagnostics != null && diagnostics.isNotEmpty
? diagnostics.first.range.start
: pos;
}
return (a, b) => _columnDistance(posOf(a), pos)
.compareTo(_columnDistance(posOf(b), pos));
@@ -174,7 +179,7 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
List<CodeAction> _dedupeActions(Iterable<CodeAction> actions, Position pos) {
final groups = groupBy(actions, (CodeAction action) => action.title);
return groups.keys.map((title) {
final actions = groups[title];
final actions = groups[title]!;
// If there's only one in the group, just return it.
if (actions.length == 1) {
@@ -213,7 +218,7 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
}
Future<List<Either2<Command, CodeAction>>> _getAssistActions(
bool Function(CodeActionKind) shouldIncludeKind,
bool Function(CodeActionKind?) shouldIncludeKind,
bool supportsLiteralCodeActions,
Range range,
int offset,
@@ -248,7 +253,7 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
}
Future<ErrorOr<List<Either2<Command, CodeAction>>>> _getCodeActions(
bool Function(CodeActionKind) shouldIncludeKind,
bool Function(CodeActionKind?) shouldIncludeKind,
bool supportsLiterals,
bool supportsWorkspaceApplyEdit,
Set<DiagnosticTag> supportedDiagnosticTags,
@@ -274,7 +279,7 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
}
Future<List<Either2<Command, CodeAction>>> _getFixActions(
bool Function(CodeActionKind) shouldIncludeKind,
bool Function(CodeActionKind?) shouldIncludeKind,
bool supportsLiteralCodeActions,
Set<DiagnosticTag> supportedDiagnosticTags,
Range range,
@@ -301,10 +306,10 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
var workspace = DartChangeWorkspace(server.currentSessions);
var context = DartFixContextImpl(
server.instrumentationService, workspace, unit, error, (name) {
var tracker = server.declarationsTracker;
var tracker = server.declarationsTracker!;
return TopLevelDeclarationsProvider(tracker).get(
unit.session.analysisContext,
unit.path,
unit.path!,
name,
);
});
@@ -357,7 +362,7 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
CodeActionKind actionKind,
String name,
RefactoringKind refactorKind, [
Map<String, dynamic> options,
Map<String, dynamic>? options,
]) {
return _commandOrCodeAction(
supportsLiteralCodeActions,
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'dart:math' as math;
import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart';
@@ -51,15 +49,22 @@ class CompletionHandler
@override
Future<ErrorOr<List<CompletionItem>>> handle(
CompletionParams params, 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 includeSuggestionSets =
suggestFromUnimportedLibraries && server.clientCapabilities.applyEdit;
suggestFromUnimportedLibraries && clientCapabilities.applyEdit;
final triggerCharacter = params.context?.triggerCharacter;
final pos = params.position;
final path = pathOfDoc(params.textDocument);
final unit = await path.mapResult(requireResolvedUnit);
final lineInfo = unit.map<ErrorOr<LineInfo>>(
final lineInfo = await unit.map(
// If we don't have a unit, we can still try to obtain the line info for
// plugin contributors.
(error) => path.mapResult(getLineInfo),
@@ -69,13 +74,13 @@ class CompletionHandler
await lineInfo.mapResult((lineInfo) => toOffset(lineInfo, pos));
return offset.mapResult((offset) async {
Future<ErrorOr<List<CompletionItem>>> serverResultsFuture;
Future<ErrorOr<List<CompletionItem>>>? serverResultsFuture;
final pathContext = server.resourceProvider.pathContext;
final fileExtension = pathContext.extension(path.result);
if (fileExtension == '.dart' && !unit.isError) {
serverResultsFuture = _getServerDartItems(
server.clientCapabilities,
clientCapabilities,
includeSuggestionSets,
unit.result,
offset,
@@ -83,7 +88,7 @@ class CompletionHandler
token,
);
} else if (fileExtension == '.yaml') {
YamlCompletionGenerator generator;
YamlCompletionGenerator? generator;
if (file_paths.isAnalysisOptionsYaml(pathContext, path.result)) {
generator = AnalysisOptionsGenerator(server.resourceProvider);
} else if (file_paths.isFixDataYaml(pathContext, path.result)) {
@@ -95,7 +100,7 @@ class CompletionHandler
if (generator != null) {
serverResultsFuture = _getServerYamlItems(
generator,
server.clientCapabilities,
clientCapabilities,
path.result,
lineInfo.result,
offset,
@@ -107,7 +112,7 @@ class CompletionHandler
serverResultsFuture ??= Future.value(success(const <CompletionItem>[]));
final pluginResultsFuture = _getPluginResults(
server.clientCapabilities, lineInfo.result, path.result, offset);
clientCapabilities, lineInfo.result, path.result, offset);
// Await both server + plugin results together to allow async/IO to
// overlap.
@@ -138,14 +143,15 @@ class CompletionHandler
if (importedLibrary == null) continue;
for (var element in import.namespace.definedNames.values) {
if (element.librarySource != null) {
final declaringLibraryUri = element.librarySource.uri;
final elementName = element.name;
final librarySource = element.librarySource;
final elementName = element.name;
if (librarySource != null && elementName != null) {
final declaringLibraryUri = librarySource.uri;
final key =
_createImportedSymbolKey(elementName, declaringLibraryUri);
alreadyImportedSymbols.putIfAbsent(key, () => <String>{});
alreadyImportedSymbols[key]
alreadyImportedSymbols[key]!
.add('${importedLibrary.librarySource.uri}');
}
}
@@ -194,12 +200,12 @@ class CompletionHandler
bool includeSuggestionSets,
ResolvedUnitResult unit,
int offset,
String triggerCharacter,
String? triggerCharacter,
CancellationToken token,
) async {
final performance = CompletionPerformance();
performance.path = unit.path;
performance.setContentsAndOffset(unit.content, offset);
performance.setContentsAndOffset(unit.content!, offset);
server.performanceStats.completion.add(performance);
return await performance.runRequestOperation((perf) async {
@@ -217,9 +223,9 @@ class CompletionHandler
}
}
Set<ElementKind> includedElementKinds;
Set<String> includedElementNames;
List<IncludedSuggestionRelevanceTag> includedSuggestionRelevanceTags;
Set<ElementKind>? includedElementKinds;
Set<String>? includedElementNames;
List<IncludedSuggestionRelevanceTag>? includedSuggestionRelevanceTags;
if (includeSuggestionSets) {
includedElementKinds = <ElementKind>{};
includedElementNames = <String>{};
@@ -288,98 +294,101 @@ class CompletionHandler
// Now compute items in suggestion sets.
var includedSuggestionSets = <IncludedSuggestionSet>[];
if (includedElementKinds != null && unit != null) {
final declarationsTracker = server.declarationsTracker;
if (declarationsTracker != null &&
includedElementKinds != null &&
includedElementNames != null &&
includedSuggestionRelevanceTags != null) {
computeIncludedSetList(
server.declarationsTracker,
declarationsTracker,
unit,
includedSuggestionSets,
includedElementNames,
);
// Build a fast lookup for imported symbols so that we can filter out
// duplicates.
final alreadyImportedSymbols = _buildLookupOfImportedSymbols(unit);
includedSuggestionSets.forEach((includedSet) {
final library = declarationsTracker.getLibrary(includedSet.id);
if (library == null) {
return;
}
// Make a fast lookup for tag relevance.
final tagBoosts = <String, int>{};
includedSuggestionRelevanceTags!
.forEach((t) => tagBoosts[t.tag] = t.relevanceBoost);
// Only specific types of child declarations should be included.
// This list matches what's in _protocolAvailableSuggestion in
// the DAS implementation.
bool shouldIncludeChild(Declaration child) =>
child.kind == DeclarationKind.CONSTRUCTOR ||
child.kind == DeclarationKind.ENUM_CONSTANT ||
(child.kind == DeclarationKind.GETTER && child.isStatic) ||
(child.kind == DeclarationKind.FIELD && child.isStatic);
// Collect declarations and their children.
final allDeclarations = library.declarations
.followedBy(library.declarations
.expand((decl) => decl.children.where(shouldIncludeChild)))
.toList();
final setResults = allDeclarations
// Filter to only the kinds we should return.
.where((item) => includedElementKinds!
.contains(protocolElementKind(item.kind)))
.where((item) {
// Check existing imports to ensure we don't already import
// this element (this exact element from its declaring
// library, not just something with the same name). If we do
// we'll want to skip it.
final declaringUri =
item.parent?.locationLibraryUri ?? item.locationLibraryUri!;
// For enums and named constructors, only the parent enum/class is in
// the list of imported symbols so we use the parents name.
final nameKey = item.kind == DeclarationKind.ENUM_CONSTANT ||
item.kind == DeclarationKind.CONSTRUCTOR
? item.parent!.name
: item.name;
final key = _createImportedSymbolKey(nameKey, declaringUri);
final importingUris = alreadyImportedSymbols[key];
// Keep it only if there are either:
// - no URIs importing it
// - the URIs importing it include this one
return importingUris == null ||
importingUris.contains('${library.uri}');
}).map((item) => declarationToCompletionItem(
capabilities,
unit.path!,
offset,
includedSet,
library,
tagBoosts,
unit.lineInfo,
item,
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.
// https://github.com/microsoft/vscode-languageserver-node/issues/673
includeCommitCharacters:
server.clientConfiguration.previewCommitCharacters,
completeFunctionCalls:
server.clientConfiguration.completeFunctionCalls,
));
results.addAll(setResults);
});
}
// Build a fast lookup for imported symbols so that we can filter out
// duplicates.
final alreadyImportedSymbols = _buildLookupOfImportedSymbols(unit);
includedSuggestionSets.forEach((includedSet) {
final library = server.declarationsTracker.getLibrary(includedSet.id);
if (library == null) {
return;
}
// Make a fast lookup for tag relevance.
final tagBoosts = <String, int>{};
includedSuggestionRelevanceTags
.forEach((t) => tagBoosts[t.tag] = t.relevanceBoost);
// Only specific types of child declarations should be included.
// This list matches what's in _protocolAvailableSuggestion in
// the DAS implementation.
bool shouldIncludeChild(Declaration child) =>
child.kind == DeclarationKind.CONSTRUCTOR ||
child.kind == DeclarationKind.ENUM_CONSTANT ||
(child.kind == DeclarationKind.GETTER && child.isStatic) ||
(child.kind == DeclarationKind.FIELD && child.isStatic);
// Collect declarations and their children.
final allDeclarations = library.declarations
.followedBy(library.declarations
.expand((decl) => decl.children.where(shouldIncludeChild)))
.toList();
final setResults = allDeclarations
// Filter to only the kinds we should return.
.where((item) =>
includedElementKinds.contains(protocolElementKind(item.kind)))
.where((item) {
// Check existing imports to ensure we don't already import
// this element (this exact element from its declaring
// library, not just something with the same name). If we do
// we'll want to skip it.
final declaringUri = item.parent != null
? item.parent.locationLibraryUri
: item.locationLibraryUri;
// For enums and named constructors, only the parent enum/class is in
// the list of imported symbols so we use the parents name.
final nameKey = item.kind == DeclarationKind.ENUM_CONSTANT ||
item.kind == DeclarationKind.CONSTRUCTOR
? item.parent.name
: item.name;
final key = _createImportedSymbolKey(nameKey, declaringUri);
final importingUris = alreadyImportedSymbols[key];
// Keep it only if there are either:
// - no URIs importing it
// - the URIs importing it include this one
return importingUris == null ||
importingUris.contains('${library.uri}');
}).map((item) => declarationToCompletionItem(
capabilities,
unit.path,
offset,
includedSet,
library,
tagBoosts,
unit.lineInfo,
item,
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.
// https://github.com/microsoft/vscode-languageserver-node/issues/673
includeCommitCharacters:
server.clientConfiguration.previewCommitCharacters,
completeFunctionCalls:
server.clientConfiguration.completeFunctionCalls,
));
results.addAll(setResults);
});
// Perform fuzzy matching based on the identifier in front of the caret to
// reduce the size of the payload.
final fuzzyPattern = dartCompletionRequest.targetPrefix;
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
@@ -24,7 +22,7 @@ class CompletionResolveHandler
/// Used to abort previous requests in async handlers if another resolve request
/// arrives while the previous is being processed (for clients that don't send
/// cancel events).
CompletionItem _latestCompletionItem;
CompletionItem? _latestCompletionItem;
CompletionResolveHandler(LspAnalysisServer server) : super(server);
@@ -55,6 +53,13 @@ class CompletionResolveHandler
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 lineInfo = server.getLineInfo(data.file);
if (lineInfo == null) {
return error(
@@ -68,7 +73,7 @@ class CompletionResolveHandler
// 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);
var library = server.declarationsTracker?.getLibrary(data.libId);
if (library == null) {
return error(
ErrorCodes.InvalidParams,
@@ -94,16 +99,19 @@ class CompletionResolveHandler
_latestCompletionItem = item;
while (item == _latestCompletionItem && timer.elapsed < timeout) {
try {
var analysisDriver = server.getAnalysisDriver(data.file);
var session = analysisDriver.currentSession;
final analysisDriver = server.getAnalysisDriver(data.file);
final session = analysisDriver?.currentSession;
if (token.isCancellationRequested) {
// We shouldn't not get a driver/session, but if we did perhaps the file
// was removed from the analysis set so assume the request is no longer
// valid.
if (session == null || token.isCancellationRequested) {
return cancelled();
}
analyzer.LibraryElement requestedLibraryElement;
{
var result = await session.getLibraryByUri2(library.uriStr);
final result = await session.getLibraryByUri2(library.uriStr);
if (result is LibraryElementResult) {
requestedLibraryElement = result.element;
} else {
@@ -150,7 +158,7 @@ class CompletionResolveHandler
// If this completion involves editing other files, we'll need to build
// a command that the client will call to apply those edits later.
Command command;
Command? command;
if (otherFilesChanges.isNotEmpty) {
final workspaceEdit =
createPlainWorkspaceEdit(server, otherFilesChanges);
@@ -161,19 +169,19 @@ class CompletionResolveHandler
}
// Documentation is added on during resolve for LSP.
final formats =
server.clientCapabilities.completionDocumentationFormats;
final formats = clientCapabilities.completionDocumentationFormats;
final supportsInsertReplace =
server.clientCapabilities.insertReplaceCompletionRanges;
clientCapabilities.insertReplaceCompletionRanges;
final dartDoc =
analyzer.getDartDocPlainText(requestedElement.documentationComment);
final documentation = asStringOrMarkupContent(formats, dartDoc);
final documentation =
dartDoc != null ? asStringOrMarkupContent(formats, dartDoc) : null;
return success(CompletionItem(
label: item.label,
kind: item.kind,
tags: item.tags,
detail: data.displayUri != null && thisFilesChanges.isNotEmpty
detail: thisFilesChanges.isNotEmpty
? "Auto import from '${data.displayUri}'\n\n${item.detail ?? ''}"
.trim()
: item.detail,
@@ -234,13 +242,14 @@ class CompletionResolveHandler
return cancelled();
}
final description = packageDetails?.description;
return success(CompletionItem(
label: item.label,
kind: item.kind,
tags: item.tags,
detail: item.detail,
documentation: packageDetails?.description != null
? Either2<String, MarkupContent>.t1(packageDetails.description)
documentation: description != null
? Either2<String, MarkupContent>.t1(description)
: null,
deprecated: item.deprecated,
preselect: item.preselect,
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/protocol/protocol_generated.dart'
@@ -18,6 +16,7 @@ import 'package:analyzer/source/line_info.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:analyzer_plugin/src/utilities/navigation/navigation.dart';
import 'package:analyzer_plugin/utilities/navigation/navigation_dart.dart';
import 'package:collection/collection.dart';
class DefinitionHandler extends MessageHandler<TextDocumentPositionParams,
Either2<List<Location>, List<LocationLink>>>
@@ -53,9 +52,10 @@ class DefinitionHandler extends MessageHandler<TextDocumentPositionParams,
NavigationCollectorImpl(collectCodeLocations: supportsLocationLink);
final result = await server.getResolvedUnit(path);
if (result?.state == ResultState.VALID) {
final unit = result?.unit;
if (result?.state == ResultState.VALID && unit != null) {
computeDartNavigation(
server.resourceProvider, collector, result.unit, offset, 0);
server.resourceProvider, collector, unit, offset, 0);
collector.createRegions();
}
@@ -66,8 +66,14 @@ class DefinitionHandler extends MessageHandler<TextDocumentPositionParams,
@override
Future<ErrorOr<Either2<List<Location>, List<LocationLink>>>> handle(
TextDocumentPositionParams params, CancellationToken token) async {
final supportsLocationLink =
server.clientCapabilities.definitionLocationLink;
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 supportsLocationLink = clientCapabilities.definitionLocationLink;
final pos = params.position;
final path = pathOfDoc(params.textDocument);
@@ -94,20 +100,27 @@ class DefinitionHandler extends MessageHandler<TextDocumentPositionParams,
final mergedResults = merger.mergeNavigation(allResults);
final mergedTargets = mergedResults?.targets ?? [];
if (mergedResults == null) {
return success(
Either2<List<Location>, List<LocationLink>>.t1(const []),
);
}
// Convert and filter the results using the correct type of Location class
// depending on the client capabilities.
if (supportsLocationLink) {
final convertedResults = convert(
mergedTargets,
(target) => _toLocationLink(mergedResults, lineInfo, target),
).toList();
(NavigationTarget target) =>
_toLocationLink(mergedResults, lineInfo, target),
).whereNotNull().toList();
final results = _filterResults(
convertedResults,
params.textDocument.uri,
pos.line,
(element) => element.targetUri,
(element) => element.targetSelectionRange,
(LocationLink element) => element.targetUri,
(LocationLink element) => element.targetSelectionRange,
);
return success(
@@ -116,15 +129,15 @@ class DefinitionHandler extends MessageHandler<TextDocumentPositionParams,
} else {
final convertedResults = convert(
mergedTargets,
(target) => _toLocation(mergedResults, target),
).toList();
(NavigationTarget target) => _toLocation(mergedResults, target),
).whereNotNull().toList();
final results = _filterResults(
convertedResults,
params.textDocument.uri,
pos.line,
(element) => element.uri,
(element) => element.range,
(Location element) => element.uri,
(Location element) => element.range,
);
return success(
@@ -159,19 +172,24 @@ class DefinitionHandler extends MessageHandler<TextDocumentPositionParams,
return otherResults.isNotEmpty ? otherResults : results;
}
Location _toLocation(
Location? _toLocation(
AnalysisNavigationParams mergedResults, NavigationTarget target) {
final targetFilePath = mergedResults.files[target.fileIndex];
final targetLineInfo = server.getLineInfo(targetFilePath);
return navigationTargetToLocation(targetFilePath, target, targetLineInfo);
return targetLineInfo != null
? navigationTargetToLocation(targetFilePath, target, targetLineInfo)
: null;
}
LocationLink _toLocationLink(AnalysisNavigationParams mergedResults,
LocationLink? _toLocationLink(AnalysisNavigationParams mergedResults,
LineInfo sourceLineInfo, NavigationTarget target) {
final region = mergedResults.regions.first;
final targetFilePath = mergedResults.files[target.fileIndex];
final targetLineInfo = server.getLineInfo(targetFilePath);
return navigationTargetToLocationLink(
region, sourceLineInfo, targetFilePath, target, targetLineInfo);
return targetLineInfo != null
? navigationTargetToLocationLink(
region, sourceLineInfo, targetFilePath, target, targetLineInfo)
: null;
}
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/domains/analysis/occurrences.dart';
@@ -13,7 +11,7 @@ import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
import 'package:analysis_server/src/lsp/mapping.dart';
class DocumentHighlightsHandler extends MessageHandler<
TextDocumentPositionParams, List<DocumentHighlight>> {
TextDocumentPositionParams, List<DocumentHighlight>?> {
DocumentHighlightsHandler(LspAnalysisServer server) : super(server);
@override
Method get handlesMessage => Method.textDocument_documentHighlight;
@@ -23,7 +21,7 @@ class DocumentHighlightsHandler extends MessageHandler<
TextDocumentPositionParams.jsonHandler;
@override
Future<ErrorOr<List<DocumentHighlight>>> handle(
Future<ErrorOr<List<DocumentHighlight>?>> handle(
TextDocumentPositionParams params, CancellationToken token) async {
if (!isDartDocument(params.textDocument)) {
return success(const []);
@@ -36,7 +34,7 @@ class DocumentHighlightsHandler extends MessageHandler<
return offset.mapResult((requestedOffset) {
final collector = OccurrencesCollectorImpl();
addDartOccurrences(collector, unit.result.unit);
addDartOccurrences(collector, unit.result.unit!);
// Find an occurrence that has an instance that spans the position.
for (final occurrence in collector.allOccurrences) {
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/computer/computer_outline.dart';
@@ -16,7 +14,7 @@ import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/source/line_info.dart';
class DocumentSymbolHandler extends MessageHandler<DocumentSymbolParams,
Either2<List<DocumentSymbol>, List<SymbolInformation>>> {
Either2<List<DocumentSymbol>, List<SymbolInformation>>?> {
DocumentSymbolHandler(LspAnalysisServer server) : super(server);
@override
Method get handlesMessage => Method.textDocument_documentSymbol;
@@ -26,9 +24,10 @@ class DocumentSymbolHandler extends MessageHandler<DocumentSymbolParams,
DocumentSymbolParams.jsonHandler;
@override
Future<ErrorOr<Either2<List<DocumentSymbol>, List<SymbolInformation>>>>
Future<ErrorOr<Either2<List<DocumentSymbol>, List<SymbolInformation>>?>>
handle(DocumentSymbolParams params, CancellationToken token) async {
if (!isDartDocument(params.textDocument)) {
final clientCapabilities = server.clientCapabilities;
if (clientCapabilities == null || !isDartDocument(params.textDocument)) {
return success(
Either2<List<DocumentSymbol>, List<SymbolInformation>>.t2([]),
);
@@ -37,7 +36,7 @@ class DocumentSymbolHandler extends MessageHandler<DocumentSymbolParams,
final path = pathOfDoc(params.textDocument);
final unit = await path.mapResult(requireResolvedUnit);
return unit.mapResult(
(unit) => _getSymbols(server.clientCapabilities, path.result, unit));
(unit) => _getSymbols(clientCapabilities, path.result, unit));
}
DocumentSymbol _asDocumentSymbol(
@@ -45,41 +44,49 @@ class DocumentSymbolHandler extends MessageHandler<DocumentSymbolParams,
LineInfo lineInfo,
Outline outline,
) {
final codeRange = toRange(lineInfo, outline.codeOffset, outline.codeLength);
final nameLocation = outline.element.location;
final nameRange = nameLocation != null
? toRange(lineInfo, nameLocation.offset, nameLocation.length)
: null;
return DocumentSymbol(
name: toElementName(outline.element),
detail: outline.element.parameters,
kind: elementKindToSymbolKind(supportedKinds, outline.element.kind),
deprecated: outline.element.isDeprecated,
range: toRange(lineInfo, outline.codeOffset, outline.codeLength),
selectionRange: toRange(lineInfo, outline.element.location.offset,
outline.element.location.length),
range: codeRange,
selectionRange: nameRange ?? codeRange,
children: outline.children
?.map((child) => _asDocumentSymbol(supportedKinds, lineInfo, child))
?.toList(),
.toList(),
);
}
SymbolInformation _asSymbolInformation(
String containerName,
SymbolInformation? _asSymbolInformation(
String? containerName,
Set<SymbolKind> supportedKinds,
String documentUri,
LineInfo lineInfo,
Outline outline,
) {
final location = outline.element.location;
if (location == null) {
return null;
}
return SymbolInformation(
name: toElementName(outline.element),
kind: elementKindToSymbolKind(supportedKinds, outline.element.kind),
deprecated: outline.element.isDeprecated,
location: Location(
uri: documentUri,
range: toRange(lineInfo, outline.element.location.offset,
outline.element.location.length),
range: toRange(lineInfo, location.offset, location.length),
),
containerName: containerName,
);
}
ErrorOr<Either2<List<DocumentSymbol>, List<SymbolInformation>>> _getSymbols(
ErrorOr<Either2<List<DocumentSymbol>, List<SymbolInformation>>?> _getSymbols(
LspClientCapabilities capabilities,
String path,
ResolvedUnitResult unit,
@@ -90,12 +97,16 @@ class DocumentSymbolHandler extends MessageHandler<DocumentSymbolParams,
if (capabilities.hierarchicalSymbols) {
// Return a tree of DocumentSymbol only if the client shows explicit support
// for it.
final children = outline.children;
if (children == null) {
return success(null);
}
return success(
Either2<List<DocumentSymbol>, List<SymbolInformation>>.t1(
outline?.children
?.map((child) => _asDocumentSymbol(
children
.map((child) => _asDocumentSymbol(
capabilities.documentSymbolKinds, unit.lineInfo, child))
?.toList(),
.toList(),
),
);
} else {
@@ -105,20 +116,23 @@ class DocumentSymbolHandler extends MessageHandler<DocumentSymbolParams,
// Adds a symbol and it's children recursively, supplying the parent
// name as required by SymbolInformation.
void addSymbol(Outline outline, {String parentName}) {
allSymbols.add(_asSymbolInformation(
void addSymbol(Outline outline, {String? parentName}) {
final symbol = _asSymbolInformation(
parentName,
capabilities.documentSymbolKinds,
documentUri,
unit.lineInfo,
outline,
));
);
if (symbol != null) {
allSymbols.add(symbol);
}
outline.children?.forEach(
(c) => addSymbol(c, parentName: outline.element.name),
);
}
outline?.children?.forEach(addSymbol);
outline.children?.forEach(addSymbol);
return success(
Either2<List<DocumentSymbol>, List<SymbolInformation>>.t2(allSymbols),
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
@@ -18,7 +16,7 @@ import 'package:analysis_server/src/lsp/progress.dart';
/// Handles workspace/executeCommand messages by delegating to a specific handler
/// based on the command.
class ExecuteCommandHandler
extends MessageHandler<ExecuteCommandParams, Object> {
extends MessageHandler<ExecuteCommandParams, Object?> {
final Map<String, CommandHandler> commandHandlers;
ExecuteCommandHandler(LspAnalysisServer server)
: commandHandlers = {
@@ -37,7 +35,7 @@ class ExecuteCommandHandler
ExecuteCommandParams.jsonHandler;
@override
Future<ErrorOr<Object>> handle(
Future<ErrorOr<Object?>> handle(
ExecuteCommandParams params, CancellationToken cancellationToken) async {
final handler = commandHandlers[params.command];
if (handler == null) {
@@ -45,9 +43,10 @@ class ExecuteCommandHandler
'${params.command} is not a valid command identifier', null);
}
final progress = params.workDoneToken != null
? ProgressReporter.clientProvided(server, params.workDoneToken)
: server.clientCapabilities.workDoneProgress
final workDoneToken = params.workDoneToken;
final progress = workDoneToken != null
? ProgressReporter.clientProvided(server, workDoneToken)
: server.clientCapabilities?.workDoneProgress ?? false
? ProgressReporter.serverCreated(server)
: ProgressReporter.noop;
return handler.handle(params.arguments, progress, cancellationToken);
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'dart:io';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/computer/computer_folding.dart';
@@ -31,11 +29,11 @@ class FoldingHandler
return path.mapResult((path) async {
final partialResults = <List<FoldingRegion>>[];
LineInfo lineInfo;
LineInfo? lineInfo;
final unit = server.getParsedUnit(path);
if (unit?.state == ResultState.VALID) {
lineInfo = unit.lineInfo;
lineInfo = unit!.lineInfo;
final regions = DartUnitFoldingComputer(lineInfo, unit.unit).compute();
partialResults.insert(0, regions);
@@ -59,7 +57,7 @@ class FoldingHandler
notificationManager.merger.mergeFoldingRegions(partialResults);
return success(
regions.map((region) => toFoldingRange(lineInfo, region)).toList(),
regions.map((region) => toFoldingRange(lineInfo!, region)).toList(),
);
});
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
@@ -14,7 +12,7 @@ import 'package:analysis_server/src/lsp/source_edits.dart';
import 'package:analyzer/dart/analysis/results.dart';
class FormatOnTypeHandler
extends MessageHandler<DocumentOnTypeFormattingParams, List<TextEdit>> {
extends MessageHandler<DocumentOnTypeFormattingParams, List<TextEdit>?> {
FormatOnTypeHandler(LspAnalysisServer server) : super(server);
@override
Method get handlesMessage => Method.textDocument_onTypeFormatting;
@@ -23,14 +21,14 @@ class FormatOnTypeHandler
LspJsonHandler<DocumentOnTypeFormattingParams> get jsonHandler =>
DocumentOnTypeFormattingParams.jsonHandler;
ErrorOr<List<TextEdit>> formatFile(String path) {
ErrorOr<List<TextEdit>?> formatFile(String path) {
final file = server.resourceProvider.getFile(path);
if (!file.exists) {
return error(ServerErrorCodes.InvalidFilePath, 'Invalid file path', path);
}
final result = server.getParsedUnit(path);
if (result.state != ResultState.VALID || result.errors.isNotEmpty) {
if (result?.state != ResultState.VALID || result!.errors.isNotEmpty) {
return success(null);
}
@@ -39,7 +37,7 @@ class FormatOnTypeHandler
}
@override
Future<ErrorOr<List<TextEdit>>> handle(
Future<ErrorOr<List<TextEdit>?>> handle(
DocumentOnTypeFormattingParams params, CancellationToken token) async {
if (!isDartDocument(params.textDocument)) {
return success(null);
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
@@ -14,7 +12,7 @@ import 'package:analysis_server/src/lsp/source_edits.dart';
import 'package:analyzer/dart/analysis/results.dart';
class FormatRangeHandler
extends MessageHandler<DocumentRangeFormattingParams, List<TextEdit>> {
extends MessageHandler<DocumentRangeFormattingParams, List<TextEdit>?> {
FormatRangeHandler(LspAnalysisServer server) : super(server);
@override
Method get handlesMessage => Method.textDocument_rangeFormatting;
@@ -23,14 +21,14 @@ class FormatRangeHandler
LspJsonHandler<DocumentRangeFormattingParams> get jsonHandler =>
DocumentRangeFormattingParams.jsonHandler;
ErrorOr<List<TextEdit>> formatRange(String path, Range range) {
ErrorOr<List<TextEdit>?> formatRange(String path, Range range) {
final file = server.resourceProvider.getFile(path);
if (!file.exists) {
return error(ServerErrorCodes.InvalidFilePath, 'Invalid file path', path);
}
final result = server.getParsedUnit(path);
if (result.state != ResultState.VALID || result.errors.isNotEmpty) {
if (result?.state != ResultState.VALID || result!.errors.isNotEmpty) {
return success(null);
}
@@ -40,7 +38,7 @@ class FormatRangeHandler
}
@override
Future<ErrorOr<List<TextEdit>>> handle(
Future<ErrorOr<List<TextEdit>?>> handle(
DocumentRangeFormattingParams params, CancellationToken token) async {
if (!isDartDocument(params.textDocument)) {
return success(null);
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
@@ -14,7 +12,7 @@ import 'package:analysis_server/src/lsp/source_edits.dart';
import 'package:analyzer/dart/analysis/results.dart';
class FormattingHandler
extends MessageHandler<DocumentFormattingParams, List<TextEdit>> {
extends MessageHandler<DocumentFormattingParams, List<TextEdit>?> {
FormattingHandler(LspAnalysisServer server) : super(server);
@override
Method get handlesMessage => Method.textDocument_formatting;
@@ -23,14 +21,14 @@ class FormattingHandler
LspJsonHandler<DocumentFormattingParams> get jsonHandler =>
DocumentFormattingParams.jsonHandler;
ErrorOr<List<TextEdit>> formatFile(String path) {
ErrorOr<List<TextEdit>?> formatFile(String path) {
final file = server.resourceProvider.getFile(path);
if (!file.exists) {
return error(ServerErrorCodes.InvalidFilePath, 'Invalid file path', path);
}
final result = server.getParsedUnit(path);
if (result.state != ResultState.VALID || result.errors.isNotEmpty) {
if (result?.state != ResultState.VALID || result!.errors.isNotEmpty) {
return success(null);
}
@@ -39,7 +37,7 @@ class FormattingHandler
}
@override
Future<ErrorOr<List<TextEdit>>> handle(
Future<ErrorOr<List<TextEdit>?>> handle(
DocumentFormattingParams params, CancellationToken token) async {
if (!isDartDocument(params.textDocument)) {
return success(null);
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
@@ -15,7 +13,7 @@ import 'package:analysis_server/src/lsp/mapping.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/source/line_info.dart';
class HoverHandler extends MessageHandler<TextDocumentPositionParams, Hover> {
class HoverHandler extends MessageHandler<TextDocumentPositionParams, Hover?> {
HoverHandler(LspAnalysisServer server) : super(server);
@override
Method get handlesMessage => Method.textDocument_hover;
@@ -25,7 +23,7 @@ class HoverHandler extends MessageHandler<TextDocumentPositionParams, Hover> {
TextDocumentPositionParams.jsonHandler;
@override
Future<ErrorOr<Hover>> handle(
Future<ErrorOr<Hover?>> handle(
TextDocumentPositionParams params, CancellationToken token) async {
if (!isDartDocument(params.textDocument)) {
return success(null);
@@ -38,7 +36,7 @@ class HoverHandler extends MessageHandler<TextDocumentPositionParams, Hover> {
return offset.mapResult((offset) => _getHover(unit.result, offset));
}
Hover toHover(LineInfo lineInfo, HoverInformation hover) {
Hover? toHover(LineInfo lineInfo, HoverInformation? hover) {
if (hover == null) {
return null;
}
@@ -55,16 +53,16 @@ class HoverHandler extends MessageHandler<TextDocumentPositionParams, Hover> {
// Description.
if (hover.elementDescription != null) {
content.writeln('```dart');
if (hover.isDeprecated) {
if (hover.isDeprecated ?? false) {
content.write('(deprecated) ');
}
content..writeln(hover.elementDescription)..writeln('```');
}
// Source library.
if (hover.containingLibraryName != null &&
hover.containingLibraryName.isNotEmpty) {
content..writeln('*${hover.containingLibraryName}*')..writeln();
final containingLibraryName = hover.containingLibraryName;
if (containingLibraryName != null && containingLibraryName.isNotEmpty) {
content..writeln('*$containingLibraryName*')..writeln();
}
// Doc comments.
@@ -75,7 +73,7 @@ class HoverHandler extends MessageHandler<TextDocumentPositionParams, Hover> {
content.writeln(cleanDartdoc(hover.dartdoc));
}
final formats = server.clientCapabilities.hoverContentFormats;
final formats = server.clientCapabilities?.hoverContentFormats;
return Hover(
contents:
asStringOrMarkupContent(formats, content.toString().trimRight()),
@@ -83,9 +81,14 @@ class HoverHandler extends MessageHandler<TextDocumentPositionParams, Hover> {
);
}
ErrorOr<Hover> _getHover(ResolvedUnitResult unit, int offset) {
ErrorOr<Hover?> _getHover(ResolvedUnitResult unit, int offset) {
final compilationUnit = unit.unit;
if (compilationUnit == null) {
return success(null);
}
final hover = DartUnitHoverComputer(
server.getDartdocDirectiveInfoFor(unit), unit.unit, offset)
server.getDartdocDirectiveInfoFor(unit), compilationUnit, offset)
.compute();
return success(toHover(unit.lineInfo, hover));
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
@@ -11,6 +9,7 @@ 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:analysis_server/src/search/type_hierarchy.dart';
import 'package:collection/collection.dart';
class ImplementationHandler
extends MessageHandler<TextDocumentPositionParams, List<Location>> {
@@ -38,22 +37,27 @@ class ImplementationHandler
}
Future<ErrorOr<List<Location>>> _getImplementations(
String file, int offset, CancelableToken token) async {
String file, int offset, CancellationToken token) async {
final element = await server.getElementAtOffset(file, offset);
if (element == null) {
return success([]);
}
final computer = TypeHierarchyComputer(server.searchEngine, element);
if (token.isCancellationRequested) {
return cancelled();
}
final items = await computer.compute();
final items = await computer.compute();
if (items == null || items.isEmpty) {
return success([]);
}
Iterable<TypeHierarchyItem> getDescendants(TypeHierarchyItem item) => item
.subclasses
?.map((i) => items[i])
?.followedBy(item.subclasses.expand((i) => getDescendants(items[i])));
.map((i) => items[i])
.followedBy(item.subclasses.expand((i) => getDescendants(items[i])));
// [TypeHierarchyComputer] returns the whole tree, but we specifically only
// want implementations (sub-classes). Find the referenced element and then
@@ -61,8 +65,9 @@ class ImplementationHandler
var currentItem = items.firstWhere(
(item) {
final location =
item.memberElement?.location ?? item.classElement?.location;
return location.offset <= offset &&
item.memberElement?.location ?? item.classElement.location;
return location != null &&
location.offset <= offset &&
location.offset + location.length >= offset;
},
// If we didn't find an item spanning our offset, we must've been at a
@@ -70,23 +75,32 @@ class ImplementationHandler
orElse: () => items.first,
);
final isClass = currentItem.memberElement == null;
final isMember = currentItem.memberElement != null;
final locations = getDescendants(currentItem)
// Filter based on type, so when searching for members we don't include
// any intermediate classes that don't have implementations for the
// method.
.where((item) => isMember ? item.memberElement != null : true)
.map((item) {
final elementLocation =
item.memberElement?.location ?? item.classElement.location;
if (elementLocation == null) {
return null;
}
final locations = getDescendants(currentItem).where((item) {
// Filter based on type, so when searching for members we don't include
// any intermediate classes that don't have implementations for the
// method.
return isClass ? item.classElement != null : item.memberElement != null;
}).map((item) {
final elementLocation =
item.memberElement?.location ?? item.classElement?.location;
final lineInfo = server.getLineInfo(elementLocation.file);
return Location(
uri: Uri.file(elementLocation.file).toString(),
range:
toRange(lineInfo, elementLocation.offset, elementLocation.length),
);
}).toList();
final lineInfo = server.getLineInfo(elementLocation.file);
if (lineInfo == null) {
return null;
}
return Location(
uri: Uri.file(elementLocation.file).toString(),
range: toRange(
lineInfo, elementLocation.offset, elementLocation.length),
);
})
.whereNotNull()
.toList();
return success(locations);
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'dart:io';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
@@ -32,12 +30,15 @@ class InitializeMessageHandler
);
final openWorkspacePaths = <String>[];
final workspaceFolders = params.workspaceFolders;
final rootUri = params.rootUri;
final rootPath = params.rootPath;
// The onlyAnalyzeProjectsWithOpenFiles flag allows opening huge folders
// without setting them as analysis roots. Instead, analysis roots will be
// based only on the open files.
if (!server.initializationOptions.onlyAnalyzeProjectsWithOpenFiles) {
if (params.workspaceFolders != null) {
params.workspaceFolders.forEach((wf) {
if (workspaceFolders != null) {
workspaceFolders.forEach((wf) {
final uri = Uri.parse(wf.uri);
// Only file URIs are supported, but there's no way to signal this to
// the LSP client (and certainly not before initialization).
@@ -46,13 +47,13 @@ class InitializeMessageHandler
}
});
}
if (params.rootUri != null) {
final uri = Uri.parse(params.rootUri);
if (rootUri != null) {
final uri = Uri.parse(rootUri);
if (uri.isScheme('file')) {
openWorkspacePaths.add(uri.toFilePath());
}
} else if (params.rootPath != null) {
openWorkspacePaths.add(params.rootPath);
} else if (rootPath != null) {
openWorkspacePaths.add(rootPath);
}
}
@@ -61,8 +62,9 @@ class InitializeMessageHandler
openWorkspacePaths,
);
server.capabilities = server.capabilitiesComputer
.computeServerCapabilities(server.clientCapabilities);
final capabilities = server.capabilitiesComputer
.computeServerCapabilities(server.clientCapabilities!);
server.capabilities = capabilities;
var sdkVersion = Platform.version;
if (sdkVersion.contains(' ')) {
@@ -70,7 +72,7 @@ class InitializeMessageHandler
}
return success(InitializeResult(
capabilities: server.capabilities,
capabilities: capabilities,
serverInfo: InitializeResultServerInfo(
name: 'Dart SDK LSP Analysis Server',
version: sdkVersion,
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/handlers/handler_states.dart';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -17,9 +15,10 @@ import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer_plugin/src/utilities/navigation/navigation.dart';
import 'package:analyzer_plugin/utilities/navigation/navigation_dart.dart';
import 'package:collection/collection.dart';
class ReferencesHandler
extends MessageHandler<ReferenceParams, List<Location>> {
extends MessageHandler<ReferenceParams, List<Location>?> {
ReferencesHandler(LspAnalysisServer server) : super(server);
@override
Method get handlesMessage => Method.textDocument_references;
@@ -29,7 +28,7 @@ class ReferencesHandler
ReferenceParams.jsonHandler;
@override
Future<ErrorOr<List<Location>>> handle(
Future<ErrorOr<List<Location>?>> handle(
ReferenceParams params, CancellationToken token) async {
if (!isDartDocument(params.textDocument)) {
return success(const []);
@@ -50,21 +49,23 @@ class ReferencesHandler
return convert(collector.targets, (NavigationTarget target) {
final targetFilePath = collector.files[target.fileIndex];
final lineInfo = server.getLineInfo(targetFilePath);
return navigationTargetToLocation(targetFilePath, target, lineInfo);
}).toList();
return lineInfo != null
? navigationTargetToLocation(targetFilePath, target, lineInfo)
: null;
}).whereNotNull().toList();
}
Future<ErrorOr<List<Location>>> _getRefererences(String path, int offset,
Future<ErrorOr<List<Location>?>> _getRefererences(String path, int offset,
ReferenceParams params, ResolvedUnitResult unit) async {
var element = await server.getElementAtOffset(path, offset);
if (element is ImportElement) {
element = (element as ImportElement).prefix;
element = element.prefix;
}
if (element is FieldFormalParameterElement) {
element = (element as FieldFormalParameterElement).field;
element = element.field;
}
if (element is PropertyAccessorElement) {
element = (element as PropertyAccessorElement).variable;
element = element.variable;
}
if (element == null) {
return success(null);
@@ -73,16 +74,18 @@ class ReferencesHandler
final computer = ElementReferencesComputer(server.searchEngine);
final results = await computer.compute(element, false);
Location toLocation(SearchResult result) {
Location? toLocation(SearchResult result) {
final lineInfo = server.getLineInfo(result.location.file);
return searchResultToLocation(result, lineInfo);
}
final referenceResults = convert(results, toLocation).toList();
final referenceResults =
convert(results, toLocation).whereNotNull().toList();
if (params.context?.includeDeclaration == true) {
final compilationUnit = unit.unit;
if (compilationUnit != null && params.context.includeDeclaration == true) {
// Also include the definition for the symbol at this location.
referenceResults.addAll(_getDeclarations(unit.unit, offset));
referenceResults.addAll(_getDeclarations(compilationUnit, offset));
}
return success(referenceResults);
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -11,7 +9,7 @@ import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
/// A [MessageHandler] that rejects specific tpyes of messages with a given
/// error code/message.
class RejectMessageHandler extends MessageHandler<Object, void> {
class RejectMessageHandler extends MessageHandler<Object?, void> {
@override
final Method handlesMessage;
final ErrorCodes errorCode;
@@ -21,7 +19,7 @@ class RejectMessageHandler extends MessageHandler<Object, void> {
: super(server);
@override
LspJsonHandler<void> get jsonHandler => NullJsonHandler;
LspJsonHandler<Object?> get jsonHandler => NullJsonHandler;
@override
ErrorOr<void> handle(void _, CancellationToken token) {
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart';
@@ -13,7 +11,7 @@ import 'package:analysis_server/src/lsp/mapping.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
class PrepareRenameHandler
extends MessageHandler<TextDocumentPositionParams, RangeAndPlaceholder> {
extends MessageHandler<TextDocumentPositionParams, RangeAndPlaceholder?> {
PrepareRenameHandler(LspAnalysisServer server) : super(server);
@override
Method get handlesMessage => Method.textDocument_prepareRename;
@@ -23,7 +21,7 @@ class PrepareRenameHandler
TextDocumentPositionParams.jsonHandler;
@override
Future<ErrorOr<RangeAndPlaceholder>> handle(
Future<ErrorOr<RangeAndPlaceholder?>> handle(
TextDocumentPositionParams params, CancellationToken token) async {
if (!isDartDocument(params.textDocument)) {
return success(null);
@@ -43,6 +41,10 @@ class PrepareRenameHandler
final refactorDetails =
RenameRefactoring.getElementToRename(node, element);
if (refactorDetails == null) {
return success(null);
}
final refactoring = RenameRefactoring.create(
server.refactoringWorkspace, unit.result, refactorDetails.element);
if (refactoring == null) {
@@ -53,7 +55,7 @@ class PrepareRenameHandler
final initStatus = await refactoring.checkInitialConditions();
if (initStatus.hasFatalError) {
return error(
ServerErrorCodes.RenameNotValid, initStatus.problem.message, null);
ServerErrorCodes.RenameNotValid, initStatus.problem!.message, null);
}
return success(RangeAndPlaceholder(
@@ -72,7 +74,7 @@ class PrepareRenameHandler
}
}
class RenameHandler extends MessageHandler<RenameParams, WorkspaceEdit> {
class RenameHandler extends MessageHandler<RenameParams, WorkspaceEdit?> {
RenameHandler(LspAnalysisServer server) : super(server);
@override
@@ -82,7 +84,7 @@ class RenameHandler extends MessageHandler<RenameParams, WorkspaceEdit> {
LspJsonHandler<RenameParams> get jsonHandler => RenameParams.jsonHandler;
@override
Future<ErrorOr<WorkspaceEdit>> handle(
Future<ErrorOr<WorkspaceEdit?>> handle(
RenameParams params, CancellationToken token) async {
if (!isDartDocument(params.textDocument)) {
return success(null);
@@ -116,6 +118,10 @@ class RenameHandler extends MessageHandler<RenameParams, WorkspaceEdit> {
final refactorDetails =
RenameRefactoring.getElementToRename(node, element);
if (refactorDetails == null) {
return success(null);
}
final refactoring = RenameRefactoring.create(
server.refactoringWorkspace, unit.result, refactorDetails.element);
if (refactoring == null) {
@@ -135,7 +141,7 @@ class RenameHandler extends MessageHandler<RenameParams, WorkspaceEdit> {
}
if (initStatus.hasFatalError) {
return error(
ServerErrorCodes.RenameNotValid, initStatus.problem.message, null);
ServerErrorCodes.RenameNotValid, initStatus.problem!.message, null);
}
// Check the name is valid.
@@ -143,7 +149,7 @@ class RenameHandler extends MessageHandler<RenameParams, WorkspaceEdit> {
final optionsStatus = refactoring.checkNewName();
if (optionsStatus.hasError) {
return error(ServerErrorCodes.RenameNotValid,
optionsStatus.problem.message, null);
optionsStatus.problem!.message, null);
}
// Final validation.
@@ -152,13 +158,13 @@ class RenameHandler extends MessageHandler<RenameParams, WorkspaceEdit> {
return cancelled();
}
if (finalStatus.hasFatalError) {
return error(
ServerErrorCodes.RenameNotValid, finalStatus.problem.message, null);
return error(ServerErrorCodes.RenameNotValid,
finalStatus.problem!.message, null);
} else if (finalStatus.hasError || finalStatus.hasWarning) {
// Ask the user whether to proceed with the rename.
final userChoice = await server.showUserPrompt(
MessageType.Warning,
finalStatus.message,
finalStatus.message!,
[
MessageActionItem(title: UserPromptActions.renameAnyway),
MessageActionItem(title: UserPromptActions.cancel),
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'dart:async';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
@@ -18,7 +16,7 @@ import 'package:analyzer/source/source_range.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
abstract class AbstractSemanticTokensHandler<T>
extends MessageHandler<T, SemanticTokens>
extends MessageHandler<T, SemanticTokens?>
with LspPluginRequestHandlerMixin {
AbstractSemanticTokensHandler(LspAnalysisServer server) : super(server);
@@ -28,17 +26,18 @@ abstract class AbstractSemanticTokensHandler<T>
}
Future<List<SemanticTokenInfo>> getServerResult(
String path, SourceRange range) async {
String path, SourceRange? range) async {
final result = await server.getResolvedUnit(path);
if (result?.state == ResultState.VALID) {
final computer = DartUnitHighlightsComputer(result.unit, range: range);
final unit = result?.unit;
if (result?.state == ResultState.VALID && unit != null) {
final computer = DartUnitHighlightsComputer(unit, range: range);
return computer.computeSemanticTokens();
}
return [];
}
Iterable<SemanticTokenInfo> _filter(
Iterable<SemanticTokenInfo> tokens, SourceRange range) {
Iterable<SemanticTokenInfo> tokens, SourceRange? range) {
if (range == null) {
return tokens;
}
@@ -48,9 +47,9 @@ abstract class AbstractSemanticTokensHandler<T>
token.offset > range.end));
}
Future<ErrorOr<SemanticTokens>> _handleImpl(
Future<ErrorOr<SemanticTokens?>> _handleImpl(
TextDocumentIdentifier textDocument, CancellationToken token,
{Range range}) async {
{Range? range}) async {
final path = pathOfDoc(textDocument);
return path.mapResult((path) async {
@@ -61,7 +60,7 @@ abstract class AbstractSemanticTokensHandler<T>
return success(null);
}
return toSourceRange(lineInfo, range).mapResult((range) async {
return toSourceRangeNullable(lineInfo, range).mapResult((range) async {
final serverTokens = await getServerResult(path, range);
final pluginHighlightRegions =
getPluginResults(path).expand((results) => results).toList();
@@ -125,7 +124,7 @@ class SemanticTokensFullHandler
SemanticTokensParams.jsonHandler;
@override
Future<ErrorOr<SemanticTokens>> handle(
Future<ErrorOr<SemanticTokens?>> handle(
SemanticTokensParams params, CancellationToken token) =>
_handleImpl(params.textDocument, token);
}
@@ -142,7 +141,7 @@ class SemanticTokensRangeHandler
SemanticTokensRangeParams.jsonHandler;
@override
Future<ErrorOr<SemanticTokens>> handle(
Future<ErrorOr<SemanticTokens?>> handle(
SemanticTokensRangeParams params, CancellationToken token) =>
_handleImpl(params.textDocument, token, range: params.range);
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/handlers/handler_states.dart';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/computer/computer_signature.dart';
@@ -12,7 +10,7 @@ import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
import 'package:analysis_server/src/lsp/mapping.dart';
class SignatureHelpHandler
extends MessageHandler<SignatureHelpParams, SignatureHelp> {
extends MessageHandler<SignatureHelpParams, SignatureHelp?> {
SignatureHelpHandler(LspAnalysisServer server) : super(server);
@override
Method get handlesMessage => Method.textDocument_signatureHelp;
@@ -22,12 +20,19 @@ class SignatureHelpHandler
SignatureHelpParams.jsonHandler;
@override
Future<ErrorOr<SignatureHelp>> handle(
Future<ErrorOr<SignatureHelp?>> handle(
SignatureHelpParams params, CancellationToken token) async {
if (!isDartDocument(params.textDocument)) {
return success(null);
}
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');
}
// If triggered automatically by pressing the trigger character, we will
// only provide results if the character we typed was the one that actually
// starts the argument list. This is to avoid popping open signature help
@@ -49,7 +54,7 @@ class SignatureHelpHandler
return offset.mapResult((offset) {
final computer = DartUnitSignatureComputer(
server.getDartdocDirectiveInfoFor(unit.result),
unit.result.unit,
unit.result.unit!,
offset);
if (!computer.offsetIsValid) {
return success(null); // No error, just no valid hover.
@@ -63,14 +68,11 @@ class SignatureHelpHandler
// argument list.
// The ArgumentList's offset is before the paren, but the request offset
// will be after.
if (autoTriggered &&
computer.argumentList != null &&
offset != computer.argumentList.offset + 1) {
if (autoTriggered && offset != computer.argumentList.offset + 1) {
return success(null);
}
final formats =
server.clientCapabilities.signatureHelpDocumentationFormats;
final formats = clientCapabilities.signatureHelpDocumentationFormats;
return success(toSignatureHelp(formats, signature));
});
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'dart:async';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
@@ -48,7 +46,7 @@ class FailureStateMessageHandler extends ServerStateMessageHandler {
FailureStateMessageHandler(LspAnalysisServer server) : super(server);
@override
FutureOr<ErrorOr<Object>> handleUnknownMessage(IncomingMessage message) {
FutureOr<ErrorOr<Object?>> handleUnknownMessage(IncomingMessage message) {
return error(
ErrorCodes.InternalError,
'An unrecoverable error occurred and the server cannot process messages',
@@ -126,7 +124,7 @@ class InitializingStateMessageHandler extends ServerStateMessageHandler {
}
@override
ErrorOr<void> handleUnknownMessage(IncomingMessage message) {
ErrorOr<Object?> handleUnknownMessage(IncomingMessage message) {
// Silently drop non-requests.
if (message is! RequestMessage) {
server.instrumentationService
@@ -146,7 +144,7 @@ class ShuttingDownStateMessageHandler extends ServerStateMessageHandler {
}
@override
FutureOr<ErrorOr<Object>> handleUnknownMessage(IncomingMessage message) {
FutureOr<ErrorOr<Object?>> handleUnknownMessage(IncomingMessage message) {
// Silently drop non-requests.
if (message is! RequestMessage) {
server.instrumentationService
@@ -166,7 +164,7 @@ class UninitializedStateMessageHandler extends ServerStateMessageHandler {
}
@override
FutureOr<ErrorOr<Object>> handleUnknownMessage(IncomingMessage message) {
FutureOr<ErrorOr<Object?>> handleUnknownMessage(IncomingMessage message) {
// Silently drop non-requests.
if (message is! RequestMessage) {
server.instrumentationService
@@ -2,7 +2,7 @@
// 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.
// @dart = 2.9
import 'dart:async';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
@@ -23,14 +23,15 @@ class TextDocumentChangeHandler
DidChangeTextDocumentParams.jsonHandler;
@override
ErrorOr<Null> handle(
FutureOr<ErrorOr<Null>> handle(
DidChangeTextDocumentParams params, CancellationToken token) {
final path = pathOfDoc(params.textDocument);
return path.mapResult((path) => _changeFile(path, params));
}
ErrorOr<Null> _changeFile(String path, DidChangeTextDocumentParams params) {
String oldContents;
FutureOr<ErrorOr<Null>> _changeFile(
String path, DidChangeTextDocumentParams params) {
String? oldContents;
if (server.resourceProvider.hasOverlay(path)) {
oldContents = server.resourceProvider.getFile(path).readAsStringSync();
}
@@ -66,7 +67,7 @@ class TextDocumentCloseHandler
DidCloseTextDocumentParams.jsonHandler;
@override
ErrorOr<Null> handle(
FutureOr<ErrorOr<Null>> handle(
DidCloseTextDocumentParams params, CancellationToken token) {
final path = pathOfDoc(params.textDocument);
return path.mapResult((path) {
@@ -91,7 +92,7 @@ class TextDocumentOpenHandler
DidOpenTextDocumentParams.jsonHandler;
@override
ErrorOr<Null> handle(
FutureOr<ErrorOr<Null>> handle(
DidOpenTextDocumentParams params, CancellationToken token) {
final doc = params.textDocument;
final path = pathOfDocItem(doc);
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -11,7 +9,8 @@ import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
import 'package:analysis_server/src/lsp/mapping.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
class WillRenameFilesHandler extends MessageHandler<RenameFilesParams, void> {
class WillRenameFilesHandler
extends MessageHandler<RenameFilesParams, WorkspaceEdit?> {
WillRenameFilesHandler(LspAnalysisServer server) : super(server);
@override
Method get handlesMessage => Method.workspace_willRenameFiles;
@@ -21,9 +20,9 @@ class WillRenameFilesHandler extends MessageHandler<RenameFilesParams, void> {
RenameFilesParams.jsonHandler;
@override
Future<ErrorOr<WorkspaceEdit>> handle(
Future<ErrorOr<WorkspaceEdit?>> handle(
RenameFilesParams params, CancellationToken token) async {
final files = params?.files ?? [];
final files = params.files;
// For performance reasons, only single-file rename/moves are currently supported.
if (files.length > 1 || files.any((f) => !f.oldUri.endsWith('.dart'))) {
return success(null);
@@ -36,7 +35,7 @@ class WillRenameFilesHandler extends MessageHandler<RenameFilesParams, void> {
newPath.mapResult((newPath) => _renameFile(oldPath, newPath)));
}
Future<ErrorOr<WorkspaceEdit>> _renameFile(
Future<ErrorOr<WorkspaceEdit?>> _renameFile(
String oldPath, String newPath) async {
final resolvedUnit = await server.getResolvedUnit(oldPath);
if (resolvedUnit == null) {
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -24,15 +22,25 @@ class WorkspaceSymbolHandler
@override
Future<ErrorOr<List<SymbolInformation>>> handle(
WorkspaceSymbolParams params, 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');
}
// Respond to empty queries with an empty list. The spec says this should
// be non-empty, however VS Code's client sends empty requests (but then
// appears to not render the results we supply anyway).
final query = params?.query ?? '';
// TODO(dantup): The spec has been updated to allow empty queries. Clients
// may expect a full list in this case, though we may choose not to send
// it on performance grounds until they type a filter.
final query = params.query;
if (query == '') {
return success([]);
}
final supportedSymbolKinds = server.clientCapabilities.workspaceSymbolKinds;
final supportedSymbolKinds = clientCapabilities.workspaceSymbolKinds;
// Convert the string input into a case-insensitive regex that has wildcards
// between every character and at start/end to allow for fuzzy matching.
@@ -45,7 +53,7 @@ class WorkspaceSymbolHandler
var remainingResults = 500;
final filePathsHashSet = <String>{};
final tracker = server.declarationsTracker;
final tracker = server.declarationsTracker!;
final declarations = search.WorkspaceSymbols(tracker).declarations(
regex,
remainingResults,
@@ -89,10 +97,9 @@ class WorkspaceSymbolHandler
range: range,
);
final hasParameters =
declaration.parameters != null && declaration.parameters.isNotEmpty;
final nameSuffix =
hasParameters ? (declaration.parameters == '()' ? '()' : '(…)') : '';
final parameters = declaration.parameters;
final hasParameters = parameters != null && parameters.isNotEmpty;
final nameSuffix = hasParameters ? (parameters == '()' ? '()' : '(…)') : '';
return SymbolInformation(
name: '${declaration.name}$nameSuffix',
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'dart:async';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
@@ -46,21 +44,22 @@ abstract class CancellationToken {
}
abstract class CommandHandler<P, R> with Handler<P, R> {
CommandHandler(LspAnalysisServer server) {
this.server = server;
}
@override
final LspAnalysisServer server;
Future<ErrorOr<void>> handle(List<dynamic> arguments,
CommandHandler(this.server);
Future<ErrorOr<Object?>> handle(List<dynamic>? arguments,
ProgressReporter progress, CancellationToken cancellationToken);
}
mixin Handler<P, R> {
LspAnalysisServer server;
final fileModifiedError = error<R>(ErrorCodes.ContentModified,
'Document was modified before operation completed', null);
bool fileHasBeenModified(String path, int clientVersion) {
LspAnalysisServer get server;
bool fileHasBeenModified(String path, num? clientVersion) {
final serverDocIdentifier = server.getVersionedDocumentIdentifier(path);
return clientVersion != null &&
clientVersion != serverDocIdentifier.version;
@@ -81,7 +80,7 @@ mixin Handler<P, R> {
if (result?.state != ResultState.VALID) {
return error(ServerErrorCodes.InvalidFilePath, 'Invalid file path', path);
}
return success(result);
return success(result!);
}
ErrorOr<ParsedUnitResult> requireUnresolvedUnit(String path) {
@@ -89,7 +88,7 @@ mixin Handler<P, R> {
if (result?.state != ResultState.VALID) {
return error(ServerErrorCodes.InvalidFilePath, 'Invalid file path', path);
}
return success(result);
return success(result!);
}
}
@@ -103,7 +102,7 @@ mixin LspPluginRequestHandlerMixin<T extends AbstractAnalysisServer>
final driver = server.getAnalysisDriver(path);
final pluginFutures = server.pluginManager.broadcastRequest(
params,
contextRoot: driver.analysisContext.contextRoot,
contextRoot: driver?.analysisContext?.contextRoot,
);
return waitForResponses(pluginFutures,
@@ -116,9 +115,10 @@ mixin LspPluginRequestHandlerMixin<T extends AbstractAnalysisServer>
/// Clients may not extend, implement or mix-in this class.
abstract class MessageHandler<P, R>
with Handler<P, R>, RequestHandlerMixin<LspAnalysisServer> {
MessageHandler(LspAnalysisServer server) {
this.server = server;
}
@override
final LspAnalysisServer server;
MessageHandler(this.server);
/// The method that this handler can handle.
Method get handlesMessage;
@@ -169,7 +169,7 @@ abstract class ServerStateMessageHandler {
/// Handle the given [message]. If the [message] is a [RequestMessage], then the
/// return value will be sent back in a [ResponseMessage].
/// [NotificationMessage]s are not expected to return results.
FutureOr<ErrorOr<Object>> handleMessage(IncomingMessage message) async {
FutureOr<ErrorOr<Object?>> handleMessage(IncomingMessage message) async {
final handler = _messageHandlers[message.method];
if (handler == null) {
return handleUnknownMessage(message);
@@ -197,7 +197,7 @@ abstract class ServerStateMessageHandler {
}
}
FutureOr<ErrorOr<Object>> handleUnknownMessage(IncomingMessage message) {
FutureOr<ErrorOr<Object?>> handleUnknownMessage(IncomingMessage message) {
// If it's an optional *Notification* we can ignore it (return success).
// Otherwise respond with failure. Optional Requests must still be responded
// to so they don't leave open requests on the client.
@@ -207,11 +207,6 @@ abstract class ServerStateMessageHandler {
}
void registerHandler(MessageHandler handler) {
assert(
handler.handlesMessage != null,
'Unable to register handler ${handler.runtimeType} because it does '
'not declare which messages it can handle');
_messageHandlers[handler.handlesMessage] = handler;
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'dart:async';
import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart';
@@ -59,11 +57,11 @@ import 'package:watcher/watcher.dart';
/// them.
class LspAnalysisServer extends AbstractAnalysisServer {
/// The capabilities of the LSP client. Will be null prior to initialization.
LspClientCapabilities _clientCapabilities;
LspClientCapabilities? _clientCapabilities;
/// Initialization options provided by the LSP client. Allows opting in/out of
/// specific server functionality. Will be null prior to initialization.
LspInitializationOptions _initializationOptions;
LspInitializationOptions? _initializationOptions;
/// Configuration for the workspace from the client. This is similar to
/// initializationOptions but can be updated dynamically rather than set
@@ -76,7 +74,7 @@ class LspAnalysisServer extends AbstractAnalysisServer {
/// The workspace for rename refactorings. Should be accessed through the
/// refactoringWorkspace getter to be automatically created (lazily).
RefactoringWorkspace _refactoringWorkspace;
RefactoringWorkspace? _refactoringWorkspace;
/// The versions of each document known to the server (keyed by path), used to
/// send back to the client for server-initiated edits so that the client can
@@ -87,7 +85,7 @@ class LspAnalysisServer extends AbstractAnalysisServer {
/// not known.
final Map<String, VersionedTextDocumentIdentifier> documentVersions = {};
ServerStateMessageHandler messageHandler;
late ServerStateMessageHandler messageHandler;
int nextRequestId = 1;
@@ -95,8 +93,8 @@ class LspAnalysisServer extends AbstractAnalysisServer {
/// Capabilities of the server. Will be null prior to initialization as
/// the server capabilities depend on the client capabilities.
ServerCapabilities capabilities;
ServerCapabilitiesComputer capabilitiesComputer;
ServerCapabilities? capabilities;
late ServerCapabilitiesComputer capabilitiesComputer;
LspPerformance performanceStats = LspPerformance();
@@ -104,13 +102,13 @@ class LspAnalysisServer extends AbstractAnalysisServer {
/// automatically.
bool willExit = false;
StreamSubscription _pluginChangeSubscription;
StreamSubscription? _pluginChangeSubscription;
/// The current workspace folders provided by the client. Used as analysis roots.
final _workspaceFolders = <String>{};
/// A progress reporter for analysis status.
ProgressReporter analyzingProgressReporter;
ProgressReporter? analyzingProgressReporter;
/// The number of times contexts have been created/recreated.
@visibleForTesting
@@ -125,8 +123,8 @@ class LspAnalysisServer extends AbstractAnalysisServer {
DartSdkManager sdkManager,
CrashReportingAttachmentsBuilder crashReportingAttachmentsBuilder,
InstrumentationService instrumentationService, {
http.Client httpClient,
DiagnosticServer diagnosticServer,
http.Client? httpClient,
DiagnosticServer? diagnosticServer,
// Disable to avoid using this in unit tests.
bool enableBazelWatcher = false,
}) : super(
@@ -157,16 +155,18 @@ class LspAnalysisServer extends AbstractAnalysisServer {
}
/// The capabilities of the LSP client. Will be null prior to initialization.
LspClientCapabilities get clientCapabilities => _clientCapabilities;
LspClientCapabilities? get clientCapabilities => _clientCapabilities;
Future<void> get exited => channel.closed;
/// Initialization options provided by the LSP client. Allows opting in/out of
/// specific server functionality. Will be null prior to initialization.
LspInitializationOptions get initializationOptions => _initializationOptions;
LspInitializationOptions get initializationOptions =>
_initializationOptions as LspInitializationOptions;
@override
LspNotificationManager get notificationManager => super.notificationManager;
LspNotificationManager get notificationManager =>
super.notificationManager as LspNotificationManager;
@override
set pluginManager(PluginManager value) {
@@ -202,7 +202,7 @@ class LspAnalysisServer extends AbstractAnalysisServer {
/// Fetches configuration from the client (if supported) and then sends
/// register/unregister requests for any supported/enabled dynamic registrations.
Future<void> fetchClientConfigurationAndPerformDynamicRegistration() async {
if (clientCapabilities.configuration) {
if (clientCapabilities?.configuration ?? false) {
// Fetch all configuration we care about from the client. This is just
// "dart" for now, but in future this may be extended to include
// others (for example "flutter").
@@ -243,8 +243,8 @@ class LspAnalysisServer extends AbstractAnalysisServer {
/// Return the LineInfo for the file with the given [path]. The file is
/// analyzed in one of the analysis drivers to which the file was added,
/// otherwise in the first driver, otherwise `null` is returned.
LineInfo getLineInfo(String path) {
return getAnalysisDriver(path)?.getFileSync(path)?.lineInfo;
LineInfo? getLineInfo(String path) {
return getAnalysisDriver(path)?.getFileSync(path).lineInfo;
}
/// Gets the version of a document known to the server, returning a
@@ -263,16 +263,22 @@ class LspAnalysisServer extends AbstractAnalysisServer {
_initializationOptions = LspInitializationOptions(initializationOptions);
performanceAfterStartup = ServerPerformance();
performance = performanceAfterStartup;
performance = performanceAfterStartup!;
}
/// Handles a response from the client by invoking the completer that the
/// outbound request created.
void handleClientResponse(ResponseMessage message) {
// The ID from the client is an Either2<num, String>, though it's not valid
// for it to be a string because it should match a request we sent to the
// client (and we always use numeric IDs for outgoing requests).
message.id.map(
// The ID from the client is an Either2<num, String>?, though it's not valid
// for it to be a null or a string because it should match a request we sent
// to the client (and we always use numeric IDs for outgoing requests).
final id = message.id;
if (id == null) {
showErrorMessageToUser('Unexpected response with no ID!');
return;
}
id.map(
(id) {
// It's possible that even if we got a numeric ID that it's not valid.
// If it's not in our completers list (which is a list of the
@@ -366,7 +372,7 @@ class LspAnalysisServer extends AbstractAnalysisServer {
exceptions.add(ServerException(
message,
exception,
stackTrace is StackTrace ? stackTrace : null,
stackTrace is StackTrace ? stackTrace : StackTrace.current,
false,
));
@@ -399,8 +405,8 @@ class LspAnalysisServer extends AbstractAnalysisServer {
///
/// If the result of applying the edits is already known, [newContent] can be
/// set to avoid doing that calculation twice.
void onOverlayUpdated(String path, Iterable<plugin.SourceEdit> edits,
{String newContent}) {
void onOverlayUpdated(String path, List<plugin.SourceEdit> edits,
{String? newContent}) {
assert(resourceProvider.hasOverlay(path));
if (newContent == null) {
final oldContent = resourceProvider.getFile(path).readAsStringSync();
@@ -538,7 +544,7 @@ class LspAnalysisServer extends AbstractAnalysisServer {
// Send old custom notifications to clients that do not support $/progress.
// TODO(dantup): Remove this custom notification (and related classes) when
// it's unlikely to be in use by any clients.
if (clientCapabilities.workDoneProgress != true) {
if (clientCapabilities?.workDoneProgress != true) {
channel.sendNotification(NotificationMessage(
method: CustomMethods.analyzerStatus,
params: AnalyzerStatusParams(isAnalyzing: status.isAnalyzing),
@@ -555,7 +561,7 @@ class LspAnalysisServer extends AbstractAnalysisServer {
if (analyzingProgressReporter != null) {
// Do not null this out until after end completes, otherwise we may try
// to create a new token before it's really completed.
await analyzingProgressReporter.end();
await analyzingProgressReporter?.end();
analyzingProgressReporter = null;
}
}
@@ -634,8 +640,8 @@ class LspAnalysisServer extends AbstractAnalysisServer {
// TODO(dantup): This is currently case-sensitive!
_workspaceFolders
..addAll(addedPaths ?? const [])
..removeAll(removedPaths ?? const []);
..addAll(addedPaths)
..removeAll(removedPaths);
_refreshAnalysisRoots();
}
@@ -802,25 +808,35 @@ class LspServerContextManagerCallbacks extends ContextManagerCallbacks {
@override
void listenAnalysisDriver(nd.AnalysisDriver analysisDriver) {
analysisServer.declarationsTracker
?.addContext(analysisDriver.analysisContext);
// TODO(dantup): Is this required, or covered by
// addContextsToDeclarationsTracker? The original server does not appear to
// have an equivalent call.
final analysisContext = analysisDriver.analysisContext;
if (analysisContext != null) {
analysisServer.declarationsTracker?.addContext(analysisContext);
}
analysisDriver.results.listen((result) {
var path = result.path;
if (path == null) {
// This shouldn't occur - result.path is marked with a TODO to become
// non-nullable.
return;
}
filesToFlush.add(path);
if (analysisServer.isAnalyzed(path)) {
final serverErrors = protocol.doAnalysisError_listFromEngine(result);
recordAnalysisErrors(result.path, serverErrors);
recordAnalysisErrors(path, serverErrors);
}
if (result.unit != null) {
final unit = result.unit;
if (unit != null) {
if (analysisServer.shouldSendClosingLabelsFor(path)) {
final labels =
DartUnitClosingLabelsComputer(result.lineInfo, result.unit)
.compute()
.map((l) => toClosingLabel(result.lineInfo, l))
.toList();
final labels = DartUnitClosingLabelsComputer(result.lineInfo, unit)
.compute()
.map((l) => toClosingLabel(result.lineInfo, l))
.toList();
analysisServer.publishClosingLabels(result.path, labels);
analysisServer.publishClosingLabels(path, labels);
}
if (analysisServer.shouldSendOutlineFor(path)) {
final outline = DartUnitOutlineComputer(
@@ -828,12 +844,12 @@ class LspServerContextManagerCallbacks extends ContextManagerCallbacks {
withBasicFlutter: true,
).compute();
final lspOutline = toOutline(result.lineInfo, outline);
analysisServer.publishOutline(result.path, lspOutline);
analysisServer.publishOutline(path, lspOutline);
}
if (analysisServer.shouldSendFlutterOutlineFor(path)) {
final outline = FlutterOutlineComputer(result).compute();
final lspOutline = toFlutterOutline(result.lineInfo, outline);
analysisServer.publishFlutterOutline(result.path, lspOutline);
analysisServer.publishFlutterOutline(path, lspOutline);
}
}
});
@@ -1,7 +1,7 @@
// Copyright (c) 2018, 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.
//
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+189 -193
View File
@@ -2,12 +2,11 @@
// 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.
// @dart = 2.9
import 'dart:math';
import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart'
as lsp;
import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart' as lsp;
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
@@ -32,7 +31,7 @@ import 'package:analyzer/src/services/available_declarations.dart';
import 'package:analyzer/src/services/available_declarations.dart' as dec;
import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
import 'package:analyzer_plugin/utilities/pair.dart';
import 'package:meta/meta.dart';
import 'package:collection/collection.dart';
const languageSourceName = 'dart';
@@ -51,11 +50,7 @@ final diagnosticTagsForErrorCode = <String, List<lsp.DiagnosticTag>>{
};
lsp.Either2<String, lsp.MarkupContent> asStringOrMarkupContent(
Set<lsp.MarkupKind> preferredFormats, String content) {
if (content == null) {
return null;
}
Set<lsp.MarkupKind>? preferredFormats, String content) {
return preferredFormats == null
? lsp.Either2<String, lsp.MarkupContent>.t1(content)
: lsp.Either2<String, lsp.MarkupContent>.t2(
@@ -64,8 +59,8 @@ lsp.Either2<String, lsp.MarkupContent> asStringOrMarkupContent(
/// Builds an LSP snippet string with supplied ranges as tabstops.
String buildSnippetStringWithTabStops(
String text,
List<int> offsetLengthPairs,
String? text,
List<int>? offsetLengthPairs,
) {
text ??= '';
offsetLengthPairs ??= const [];
@@ -119,11 +114,13 @@ String buildSnippetStringWithTabStops(
lsp.WorkspaceEdit createPlainWorkspaceEdit(
lsp.LspAnalysisServer server, List<server.SourceFileEdit> edits) {
return toWorkspaceEdit(
server.clientCapabilities,
// Client capabilities are always available after initialization.
server.clientCapabilities!,
edits
.map((e) => FileEditInformation(
server.getVersionedDocumentIdentifier(e.file),
server.getLineInfo(e.file),
// We should never produce edits for a file with no LineInfo.
server.getLineInfo(e.file)!,
e.edits,
// fileStamp == 1 is used by the server to indicate the file needs creating.
newFile: e.fileStamp == -1,
@@ -143,7 +140,7 @@ lsp.WorkspaceEdit createWorkspaceEdit(
// In order to return snippets, we must ensure we are only modifying a single
// existing file with a single edit and that there is a linked edit group with
// only one position and no suggestions.
if (!server.clientCapabilities.experimentalSnippetTextEdit ||
if (!server.clientCapabilities!.experimentalSnippetTextEdit ||
change.edits.length != 1 ||
change.edits.first.fileStamp == -1 || // new file
change.edits.first.edits.length != 1 ||
@@ -164,11 +161,12 @@ lsp.WorkspaceEdit createWorkspaceEdit(
}
return toWorkspaceEdit(
server.clientCapabilities,
server.clientCapabilities!,
change.edits
.map((e) => FileEditInformation(
server.getVersionedDocumentIdentifier(e.file),
server.getLineInfo(e.file),
// We should never produce edits for a file with no LineInfo.
server.getLineInfo(e.file)!,
e.edits,
selectionOffsetRelative: selectionOffset - edit.offset,
selectionLength: selectionLength,
@@ -177,7 +175,7 @@ lsp.WorkspaceEdit createWorkspaceEdit(
.toList());
}
lsp.CompletionItemKind declarationKindToCompletionItemKind(
lsp.CompletionItemKind? declarationKindToCompletionItemKind(
Set<lsp.CompletionItemKind> supportedCompletionKinds,
dec.DeclarationKind kind,
) {
@@ -210,12 +208,12 @@ lsp.CompletionItemKind declarationKindToCompletionItemKind(
}
}
return getKindPreferences().firstWhere(isSupported, orElse: () => null);
return getKindPreferences().firstWhereOrNull(isSupported);
}
lsp.SymbolKind declarationKindToSymbolKind(
Set<lsp.SymbolKind> supportedSymbolKinds,
server.DeclarationKind kind,
server.DeclarationKind? kind,
) {
bool isSupported(lsp.SymbolKind kind) => supportedSymbolKinds.contains(kind);
@@ -274,26 +272,25 @@ lsp.CompletionItem declarationToCompletionItem(
int replacementOffset,
int insertLength,
int replacementLength, {
@required bool includeCommitCharacters,
@required bool completeFunctionCalls,
required bool includeCommitCharacters,
required bool completeFunctionCalls,
}) {
final supportsSnippets = capabilities.completionSnippets;
final parent = declaration.parent;
String completion;
switch (declaration.kind) {
case DeclarationKind.ENUM_CONSTANT:
completion = '${declaration.parent.name}.${declaration.name}';
completion = '${parent!.name}.${declaration.name}';
break;
case DeclarationKind.GETTER:
case DeclarationKind.FIELD:
completion = declaration.parent != null &&
declaration.parent.name != null &&
declaration.parent.name.isNotEmpty
? '${declaration.parent.name}.${declaration.name}'
completion = parent != null && parent.name.isNotEmpty
? '${parent.name}.${declaration.name}'
: declaration.name;
break;
case DeclarationKind.CONSTRUCTOR:
completion = declaration.parent.name;
completion = parent!.name;
if (declaration.name.isNotEmpty) {
completion += '.${declaration.name}';
}
@@ -347,10 +344,8 @@ lsp.CompletionItem declarationToCompletionItem(
capabilities.completionItemKinds, declaration.kind);
var relevanceBoost = 0;
if (declaration.relevanceTags != null) {
declaration.relevanceTags.forEach(
(t) => relevanceBoost = max(relevanceBoost, tagBoosts[t] ?? 0));
}
declaration.relevanceTags
.forEach((t) => relevanceBoost = max(relevanceBoost, tagBoosts[t] ?? 0));
final itemRelevance = includedSuggestionSet.relevance + relevanceBoost;
// Because we potentially send thousands of these items, we should minimise
@@ -392,14 +387,14 @@ lsp.CompletionItem declarationToCompletionItem(
file: file,
offset: offset,
libId: includedSuggestionSet.id,
displayUri: includedSuggestionSet.displayUri ?? library.uri?.toString(),
displayUri: includedSuggestionSet.displayUri ?? library.uri.toString(),
rOffset: replacementOffset,
iLength: insertLength,
rLength: replacementLength),
);
}
lsp.CompletionItemKind elementKindToCompletionItemKind(
lsp.CompletionItemKind? elementKindToCompletionItemKind(
Set<lsp.CompletionItemKind> supportedCompletionKinds,
server.ElementKind kind,
) {
@@ -461,12 +456,12 @@ lsp.CompletionItemKind elementKindToCompletionItemKind(
}
}
return getKindPreferences().firstWhere(isSupported, orElse: () => null);
return getKindPreferences().firstWhereOrNull(isSupported);
}
lsp.SymbolKind elementKindToSymbolKind(
Set<lsp.SymbolKind> supportedSymbolKinds,
server.ElementKind kind,
server.ElementKind? kind,
) {
bool isSupported(lsp.SymbolKind kind) => supportedSymbolKinds.contains(kind);
@@ -538,20 +533,21 @@ lsp.SymbolKind elementKindToSymbolKind(
.firstWhere(isSupported, orElse: () => lsp.SymbolKind.Obj);
}
String getCompletionDetail(
String? getCompletionDetail(
server.CompletionSuggestion suggestion,
lsp.CompletionItemKind completionKind,
lsp.CompletionItemKind? completionKind,
bool supportsDeprecated,
) {
final hasElement = suggestion.element != null;
final hasParameters = hasElement &&
suggestion.element.parameters != null &&
suggestion.element.parameters.isNotEmpty;
final hasReturnType = hasElement &&
suggestion.element.returnType != null &&
suggestion.element.returnType.isNotEmpty;
final hasParameterType =
suggestion.parameterType != null && suggestion.parameterType.isNotEmpty;
final element = suggestion.element;
final hasElement = element != null;
final parameters = element?.parameters;
final returnType = element?.returnType;
final parameterType = suggestion.parameterType;
final hasParameters =
hasElement && parameters != null && parameters.isNotEmpty;
final hasReturnType =
hasElement && returnType != null && returnType.isNotEmpty;
final hasParameterType = parameterType != null && parameterType.isNotEmpty;
final prefix =
supportsDeprecated || !suggestion.isDeprecated ? '' : '(Deprecated) ';
@@ -562,36 +558,34 @@ String getCompletionDetail(
// To avoid this, always show only the return type, whether it's a getter
// or a setter.
return prefix +
(suggestion.element.kind == server.ElementKind.GETTER
? suggestion.element.returnType
(element?.kind == server.ElementKind.GETTER
? (returnType ?? '')
// Don't assume setters always have parameters
// See https://github.com/dart-lang/sdk/issues/27747
: suggestion.element.parameters != null &&
suggestion.element.parameters.isNotEmpty
: parameters != null && parameters.isNotEmpty
// Extract the type part from '(MyType value)`
? suggestion.element.parameters.substring(
1, suggestion.element.parameters.lastIndexOf(' '))
? parameters.substring(1, parameters.lastIndexOf(' '))
: '');
} else if (hasParameters && hasReturnType) {
return '$prefix${suggestion.element.parameters}${suggestion.element.returnType}';
return '$prefix$parameters$returnType';
} else if (hasReturnType) {
return '$prefix${suggestion.element.returnType}';
return '$prefix$returnType';
} else if (hasParameterType) {
return '$prefix${suggestion.parameterType}';
return '$prefix$parameterType';
} else {
return prefix.isNotEmpty ? prefix : null;
}
}
String getDeclarationCompletionDetail(
String? getDeclarationCompletionDetail(
dec.Declaration declaration,
lsp.CompletionItemKind completionKind,
lsp.CompletionItemKind? completionKind,
bool supportsDeprecated,
) {
final hasParameters =
declaration.parameters != null && declaration.parameters.isNotEmpty;
final hasReturnType =
declaration.returnType != null && declaration.returnType.isNotEmpty;
final parameters = declaration.parameters;
final hasParameters = parameters != null && parameters.isNotEmpty;
final returnType = declaration.returnType;
final hasReturnType = returnType != null && returnType.isNotEmpty;
final prefix =
supportsDeprecated || !declaration.isDeprecated ? '' : '(Deprecated) ';
@@ -603,15 +597,15 @@ String getDeclarationCompletionDetail(
// or a setter.
var suffix = '';
if (declaration.kind == dec.DeclarationKind.GETTER) {
suffix = declaration.returnType;
suffix = declaration.returnType ?? '';
} else {
// Don't assume setters always have parameters
// See https://github.com/dart-lang/sdk/issues/27747
if (declaration.parameters != null && declaration.parameters.isNotEmpty) {
if (parameters != null && parameters.isNotEmpty) {
// Extract the type part from `(MyType value)`, if there is a type.
var spaceIndex = declaration.parameters.lastIndexOf(' ');
var spaceIndex = parameters.lastIndexOf(' ');
if (spaceIndex > 0) {
suffix = declaration.parameters.substring(1, spaceIndex);
suffix = parameters.substring(1, spaceIndex);
}
}
}
@@ -625,51 +619,45 @@ String getDeclarationCompletionDetail(
}
}
List<lsp.DiagnosticTag> getDiagnosticTags(
Set<lsp.DiagnosticTag> supportedTags, plugin.AnalysisError error) {
List<lsp.DiagnosticTag>? getDiagnosticTags(
Set<lsp.DiagnosticTag>? supportedTags, plugin.AnalysisError error) {
if (supportedTags == null) {
return null;
}
final tags = diagnosticTagsForErrorCode[error.code]
?.where(supportedTags.contains)
?.toList();
.toList();
return tags != null && tags.isNotEmpty ? tags : null;
}
bool isDartDocument(lsp.TextDocumentIdentifier doc) =>
doc?.uri?.endsWith('.dart');
bool isDartDocument(lsp.TextDocumentIdentifier? doc) =>
doc?.uri.endsWith('.dart') ?? false;
lsp.Location navigationTargetToLocation(
String targetFilePath,
server.NavigationTarget target,
server.LineInfo targetLineInfo,
) {
if (targetLineInfo == null) {
return null;
}
return lsp.Location(
uri: Uri.file(targetFilePath).toString(),
range: toRange(targetLineInfo, target.offset, target.length),
);
}
lsp.LocationLink navigationTargetToLocationLink(
lsp.LocationLink? navigationTargetToLocationLink(
server.NavigationRegion region,
server.LineInfo regionLineInfo,
String targetFilePath,
server.NavigationTarget target,
server.LineInfo targetLineInfo,
) {
if (regionLineInfo == null || targetLineInfo == null) {
return null;
}
final nameRange = toRange(targetLineInfo, target.offset, target.length);
final codeRange = target.codeOffset != null && target.codeLength != null
? toRange(targetLineInfo, target.codeOffset, target.codeLength)
final codeOffset = target.codeOffset;
final codeLength = target.codeLength;
final codeRange = codeOffset != null && codeLength != null
? toRange(targetLineInfo, codeOffset, codeLength)
: nameRange;
return lsp.LocationLink(
@@ -682,21 +670,21 @@ lsp.LocationLink navigationTargetToLocationLink(
/// Returns the file system path for a TextDocumentIdentifier.
ErrorOr<String> pathOfDoc(lsp.TextDocumentIdentifier doc) =>
pathOfUri(Uri.tryParse(doc?.uri));
pathOfUri(Uri.tryParse(doc.uri));
/// Returns the file system path for a TextDocumentItem.
ErrorOr<String> pathOfDocItem(lsp.TextDocumentItem doc) =>
pathOfUri(Uri.tryParse(doc?.uri));
pathOfUri(Uri.tryParse(doc.uri));
/// Returns the file system path for a file URI.
ErrorOr<String> pathOfUri(Uri uri) {
ErrorOr<String> pathOfUri(Uri? uri) {
if (uri == null) {
return ErrorOr<String>.error(ResponseError(
code: lsp.ServerErrorCodes.InvalidFilePath,
message: 'Document URI was not supplied',
));
}
final isValidFileUri = uri?.isScheme('file') ?? false;
final isValidFileUri = uri.isScheme('file');
if (!isValidFileUri) {
return ErrorOr<String>.error(ResponseError(
code: lsp.ServerErrorCodes.InvalidFilePath,
@@ -719,13 +707,15 @@ ErrorOr<String> pathOfUri(Uri uri) {
lsp.Diagnostic pluginToDiagnostic(
server.LineInfo Function(String) getLineInfo,
plugin.AnalysisError error, {
@required Set<lsp.DiagnosticTag> supportedTags,
required Set<lsp.DiagnosticTag>? supportedTags,
}) {
List<lsp.DiagnosticRelatedInformation> relatedInformation;
if (error.contextMessages != null && error.contextMessages.isNotEmpty) {
relatedInformation = error.contextMessages
List<lsp.DiagnosticRelatedInformation>? relatedInformation;
final contextMessages = error.contextMessages;
if (contextMessages != null && contextMessages.isNotEmpty) {
relatedInformation = contextMessages
.map((message) =>
pluginToDiagnosticRelatedInformation(getLineInfo, message))
.whereNotNull()
.toList();
}
@@ -746,11 +736,16 @@ lsp.Diagnostic pluginToDiagnostic(
);
}
lsp.DiagnosticRelatedInformation pluginToDiagnosticRelatedInformation(
server.LineInfo Function(String) getLineInfo,
lsp.DiagnosticRelatedInformation? pluginToDiagnosticRelatedInformation(
server.LineInfo? Function(String) getLineInfo,
plugin.DiagnosticMessage message) {
var file = message.location.file;
var lineInfo = getLineInfo(file);
final file = message.location.file;
final lineInfo = getLineInfo(file);
// We shouldn't get context messages for something we can't get a LineInfo for
// but if we did, it's better to omit the context than fail to send the errors.
if (lineInfo == null) {
return null;
}
return lsp.DiagnosticRelatedInformation(
location: lsp.Location(
uri: Uri.file(file).toString(),
@@ -781,8 +776,8 @@ lsp.DiagnosticSeverity pluginToDiagnosticSeverity(
}
}
lsp.Location searchResultToLocation(
server.SearchResult result, server.LineInfo lineInfo) {
lsp.Location? searchResultToLocation(
server.SearchResult result, server.LineInfo? lineInfo) {
final location = result.location;
if (lineInfo == null) {
@@ -795,7 +790,7 @@ lsp.Location searchResultToLocation(
);
}
lsp.CompletionItemKind suggestionKindToCompletionItemKind(
lsp.CompletionItemKind? suggestionKindToCompletionItemKind(
Set<lsp.CompletionItemKind> supportedCompletionKinds,
server.CompletionSuggestionKind kind,
String label,
@@ -840,7 +835,7 @@ lsp.CompletionItemKind suggestionKindToCompletionItemKind(
}
}
return getKindPreferences().firstWhere(isSupported, orElse: () => null);
return getKindPreferences().firstWhereOrNull(isSupported);
}
lsp.ClosingLabel toClosingLabel(
@@ -849,7 +844,7 @@ lsp.ClosingLabel toClosingLabel(
range: toRange(lineInfo, label.offset, label.length),
label: label.label);
lsp.CodeActionKind toCodeActionKind(String id, lsp.CodeActionKind fallback) {
lsp.CodeActionKind toCodeActionKind(String? id, lsp.CodeActionKind fallback) {
if (id == null) {
return fallback;
}
@@ -872,9 +867,9 @@ lsp.CompletionItem toCompletionItem(
int replacementOffset,
int insertLength,
int replacementLength, {
@required bool includeCommitCharacters,
@required bool completeFunctionCalls,
Object resolutionData,
required bool includeCommitCharacters,
required bool completeFunctionCalls,
CompletionItemResolutionInfo? resolutionData,
}) {
// Build separate display and filter labels. Displayed labels may have additional
// info appended (for example '(...)' on callables) that should not be included
@@ -917,9 +912,10 @@ lsp.CompletionItem toCompletionItem(
final supportsAsIsInsertMode =
capabilities.completionInsertTextModes.contains(InsertTextMode.asIs);
final completionKind = suggestion.element != null
final element = suggestion.element;
final completionKind = element != null
? elementKindToCompletionItemKind(
capabilities.completionItemKinds, suggestion.element.kind)
capabilities.completionItemKinds, element.kind)
: suggestionKindToCompletionItemKind(
capabilities.completionItemKinds, suggestion.kind, label);
@@ -938,6 +934,7 @@ lsp.CompletionItem toCompletionItem(
final insertText = insertTextInfo.first;
final insertTextFormat = insertTextInfo.last;
final isMultilineCompletion = insertText.contains('\n');
final cleanedDoc = cleanDartdoc(suggestion.docComplete);
// Because we potentially send thousands of these items, we should minimise
// the generated JSON as much as possible - for example using nulls in place
@@ -954,8 +951,9 @@ lsp.CompletionItem toCompletionItem(
data: resolutionData,
detail: getCompletionDetail(suggestion, completionKind,
supportsCompletionDeprecatedFlag || supportsDeprecatedTag),
documentation:
asStringOrMarkupContent(formats, cleanDartdoc(suggestion.docComplete)),
documentation: cleanedDoc != null
? asStringOrMarkupContent(formats, cleanedDoc)
: null,
deprecated: supportsCompletionDeprecatedFlag && suggestion.isDeprecated
? true
: null,
@@ -997,27 +995,28 @@ lsp.CompletionItem toCompletionItem(
lsp.Diagnostic toDiagnostic(
server.ResolvedUnitResult result,
server.AnalysisError error, {
@required Set<lsp.DiagnosticTag> supportedTags,
server.ErrorSeverity errorSeverity,
required Set<lsp.DiagnosticTag> supportedTags,
}) =>
pluginToDiagnostic((_) => result.lineInfo,
server.newAnalysisError_fromEngine(result, error),
supportedTags: supportedTags);
lsp.Element toElement(server.LineInfo lineInfo, server.Element element) =>
lsp.Element(
range: element.location != null
? toRange(lineInfo, element.location.offset, element.location.length)
: null,
name: toElementName(element),
kind: element.kind.name,
parameters: element.parameters,
typeParameters: element.typeParameters,
returnType: element.returnType,
);
lsp.Element toElement(server.LineInfo lineInfo, server.Element element) {
final location = element.location;
return lsp.Element(
range: location != null
? toRange(lineInfo, location.offset, location.length)
: null,
name: toElementName(element),
kind: element.kind.name,
parameters: element.parameters,
typeParameters: element.typeParameters,
returnType: element.returnType,
);
}
String toElementName(server.Element element) {
return element.name != null && element.name != ''
return element.name.isNotEmpty
? element.name
: (element.kind == server.ElementKind.EXTENSION
? '<unnamed extension>'
@@ -1025,37 +1024,40 @@ String toElementName(server.Element element) {
}
lsp.FlutterOutline toFlutterOutline(
server.LineInfo lineInfo, server.FlutterOutline outline) =>
lsp.FlutterOutline(
kind: outline.kind.name,
label: outline.label,
className: outline.className,
variableName: outline.variableName,
attributes: outline.attributes != null
? outline.attributes
.map(
(attribute) => toFlutterOutlineAttribute(lineInfo, attribute))
.toList()
: null,
dartElement: outline.dartElement != null
? toElement(lineInfo, outline.dartElement)
: null,
range: toRange(lineInfo, outline.offset, outline.length),
codeRange: toRange(lineInfo, outline.codeOffset, outline.codeLength),
children: outline.children != null
? outline.children.map((c) => toFlutterOutline(lineInfo, c)).toList()
: null,
);
server.LineInfo lineInfo, server.FlutterOutline outline) {
final attributes = outline.attributes;
final dartElement = outline.dartElement;
final children = outline.children;
return lsp.FlutterOutline(
kind: outline.kind.name,
label: outline.label,
className: outline.className,
variableName: outline.variableName,
attributes: attributes != null
? attributes
.map((attribute) => toFlutterOutlineAttribute(lineInfo, attribute))
.toList()
: null,
dartElement: dartElement != null ? toElement(lineInfo, dartElement) : null,
range: toRange(lineInfo, outline.offset, outline.length),
codeRange: toRange(lineInfo, outline.codeOffset, outline.codeLength),
children: children != null
? children.map((c) => toFlutterOutline(lineInfo, c)).toList()
: null,
);
}
lsp.FlutterOutlineAttribute toFlutterOutlineAttribute(
server.LineInfo lineInfo, server.FlutterOutlineAttribute attribute) =>
lsp.FlutterOutlineAttribute(
name: attribute.name,
label: attribute.label,
valueRange: attribute.valueLocation != null
? toRange(lineInfo, attribute.valueLocation.offset,
attribute.valueLocation.length)
: null);
server.LineInfo lineInfo, server.FlutterOutlineAttribute attribute) {
final valueLocation = attribute.valueLocation;
return lsp.FlutterOutlineAttribute(
name: attribute.name,
label: attribute.label,
valueRange: valueLocation != null
? toRange(lineInfo, valueLocation.offset, valueLocation.length)
: null);
}
lsp.FoldingRange toFoldingRange(
server.LineInfo lineInfo, server.FoldingRegion region) {
@@ -1068,7 +1070,7 @@ lsp.FoldingRange toFoldingRange(
kind: toFoldingRangeKind(region.kind));
}
lsp.FoldingRangeKind toFoldingRangeKind(server.FoldingKind kind) {
lsp.FoldingRangeKind? toFoldingRangeKind(server.FoldingKind kind) {
switch (kind) {
case server.FoldingKind.COMMENT:
case server.FoldingKind.DOCUMENTATION_COMMENT:
@@ -1123,15 +1125,17 @@ ErrorOr<int> toOffset(
lineInfo.getOffsetOfLine(pos.line) + pos.character);
}
lsp.Outline toOutline(server.LineInfo lineInfo, server.Outline outline) =>
lsp.Outline(
element: toElement(lineInfo, outline.element),
range: toRange(lineInfo, outline.offset, outline.length),
codeRange: toRange(lineInfo, outline.codeOffset, outline.codeLength),
children: outline.children != null
? outline.children.map((c) => toOutline(lineInfo, c)).toList()
: null,
);
lsp.Outline toOutline(server.LineInfo lineInfo, server.Outline outline) {
final children = outline.children;
return lsp.Outline(
element: toElement(lineInfo, outline.element),
range: toRange(lineInfo, outline.offset, outline.length),
codeRange: toRange(lineInfo, outline.codeOffset, outline.codeLength),
children: children != null
? children.map((c) => toOutline(lineInfo, c)).toList()
: null,
);
}
lsp.Position toPosition(server.CharacterLocation location) {
// LSP is zero-based, but analysis server is 1-based.
@@ -1140,8 +1144,8 @@ lsp.Position toPosition(server.CharacterLocation location) {
}
lsp.Range toRange(server.LineInfo lineInfo, int offset, int length) {
server.CharacterLocation start = lineInfo.getLocation(offset);
server.CharacterLocation end = lineInfo.getLocation(offset + length);
final start = lineInfo.getLocation(offset) as server.CharacterLocation;
final end = lineInfo.getLocation(offset + length) as server.CharacterLocation;
return lsp.Range(
start: toPosition(start),
@@ -1149,7 +1153,7 @@ lsp.Range toRange(server.LineInfo lineInfo, int offset, int length) {
);
}
lsp.SignatureHelp toSignatureHelp(Set<lsp.MarkupKind> preferredFormats,
lsp.SignatureHelp toSignatureHelp(Set<lsp.MarkupKind>? preferredFormats,
server.AnalysisGetSignatureResult signature) {
// For now, we only support returning one (though we may wish to use named
// args. etc. to provide one for each possible "next" option when the cursor
@@ -1199,13 +1203,15 @@ lsp.SignatureHelp toSignatureHelp(Set<lsp.MarkupKind> preferredFormats,
return lsp.ParameterInformation(label: getParamLabel(param));
}
final cleanDoc = cleanDartdoc(signature.dartdoc);
final cleanedDoc = cleanDartdoc(signature.dartdoc);
return lsp.SignatureHelp(
signatures: [
lsp.SignatureInformation(
label: getSignatureLabel(signature),
documentation: asStringOrMarkupContent(preferredFormats, cleanDoc),
documentation: cleanedDoc != null
? asStringOrMarkupContent(preferredFormats, cleanedDoc)
: null,
parameters: signature.parameters.map(toParameterInfo).toList(),
),
],
@@ -1227,8 +1233,7 @@ lsp.SnippetTextEdit toSnippetTextEdit(
server.LineInfo lineInfo,
server.SourceEdit edit,
int selectionOffsetRelative,
int selectionLength) {
assert(selectionOffsetRelative != null);
int? selectionLength) {
return lsp.SnippetTextEdit(
insertTextFormat: lsp.InsertTextFormat.Snippet,
range: toRange(lineInfo, edit.offset, edit.length),
@@ -1239,27 +1244,27 @@ lsp.SnippetTextEdit toSnippetTextEdit(
ErrorOr<server.SourceRange> toSourceRange(
server.LineInfo lineInfo, Range range) {
if (range == null) {
return success(null);
}
// If there is a range, convert to offsets because that's what
// the tokens are computed using initially.
final start = toOffset(lineInfo, range.start);
final end = toOffset(lineInfo, range.end);
if (start?.isError ?? false) {
if (start.isError) {
return failure(start);
}
if (end?.isError ?? false) {
if (end.isError) {
return failure(end);
}
final startOffset = start?.result;
final endOffset = end?.result;
final startOffset = start.result;
final endOffset = end.result;
return success(server.SourceRange(startOffset, endOffset - startOffset));
}
ErrorOr<server.SourceRange?> toSourceRangeNullable(
server.LineInfo lineInfo, Range? range) =>
range != null ? toSourceRange(lineInfo, range) : success(null);
lsp.TextDocumentEdit toTextDocumentEdit(
LspClientCapabilities capabilities, FileEditInformation edit) {
return lsp.TextDocumentEdit(
@@ -1276,8 +1281,8 @@ Either3<lsp.SnippetTextEdit, lsp.AnnotatedTextEdit, lsp.TextEdit>
LspClientCapabilities capabilities,
server.LineInfo lineInfo,
server.SourceEdit edit, {
int selectionOffsetRelative,
int selectionLength,
int? selectionOffsetRelative,
int? selectionLength,
}) {
if (!capabilities.experimentalSnippetTextEdit ||
selectionOffsetRelative == null) {
@@ -1348,15 +1353,6 @@ Map<String, List<lsp.TextEdit>> toWorkspaceEditChanges(
lsp.MarkupContent _asMarkup(
Set<lsp.MarkupKind> preferredFormats, String content) {
// It's not valid to call this function with a null format, as null formats
// do not support MarkupContent. [asStringOrMarkupContent] is probably the
// better choice.
assert(preferredFormats != null);
if (content == null) {
return null;
}
if (preferredFormats.isEmpty) {
preferredFormats.add(lsp.MarkupKind.Markdown);
}
@@ -1373,16 +1369,16 @@ lsp.MarkupContent _asMarkup(
}
Pair<String, lsp.InsertTextFormat> _buildInsertText({
@required bool supportsSnippets,
@required bool includeCommitCharacters,
@required bool completeFunctionCalls,
@required bool isCallable,
@required bool isInvocation,
@required String defaultArgumentListString,
@required List<int> defaultArgumentListTextRanges,
@required String completion,
@required int selectionOffset,
@required int selectionLength,
required bool supportsSnippets,
required bool includeCommitCharacters,
required bool completeFunctionCalls,
required bool isCallable,
required bool isInvocation,
required String? defaultArgumentListString,
required List<int>? defaultArgumentListTextRanges,
required String completion,
required int selectionOffset,
required int selectionLength,
}) {
var insertText = completion;
var insertTextFormat = lsp.InsertTextFormat.PlainText;
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/channel/lsp_channel.dart';
@@ -20,7 +18,8 @@ class LspNotificationManager extends AbstractNotificationManager {
/// The analysis server, used to fetch LineInfo in order to map plugin
/// data structures to LSP structures.
LspAnalysisServer server;
late LspAnalysisServer
server; // Set externally immediately after construction
LspNotificationManager(this.channel, Context pathContext)
: super(pathContext);
@@ -31,9 +30,10 @@ class LspNotificationManager extends AbstractNotificationManager {
String filePath, List<protocol.AnalysisError> errors) {
final diagnostics = errors
.map((error) => pluginToDiagnostic(
server.getLineInfo,
// We should never errors for a file we can't get a LineInfo for
(path) => server.getLineInfo(path)!,
error,
supportedTags: server.clientCapabilities.diagnosticTags,
supportedTags: server.clientCapabilities?.diagnosticTags,
))
.toList();
+13 -14
View File
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'dart:async';
import 'dart:math';
@@ -27,13 +25,13 @@ abstract class ProgressReporter {
///
/// If [token] is not supplied, a random identifier will be used.
factory ProgressReporter.serverCreated(LspAnalysisServer server,
[Either2<num, String> token]) =>
[Either2<num, String>? token]) =>
_ServerCreatedProgressReporter(server, token);
ProgressReporter._();
// TODO(dantup): Add support for cancellable progress notifications.
FutureOr<void> begin(String title, {String message});
FutureOr<void> begin(String title, {String? message});
FutureOr<void> end([String message]);
}
@@ -41,25 +39,25 @@ abstract class ProgressReporter {
class _NoopProgressReporter extends ProgressReporter {
_NoopProgressReporter() : super._();
@override
void begin(String title, {String message}) {}
void begin(String title, {String? message}) {}
@override
void end([String message]) {}
void end([String? message]) {}
}
class _ServerCreatedProgressReporter extends _TokenProgressReporter {
static final _random = Random();
Future<bool> _tokenBeginRequest;
Future<bool>? _tokenBeginRequest;
_ServerCreatedProgressReporter(
LspAnalysisServer server,
Either2<num, String> token,
Either2<num, String>? token,
) : super(
server,
token ?? Either2<num, String>.t2(_randomTokenIdentifier()),
);
@override
Future<void> begin(String title, {String message}) async {
Future<void> begin(String? title, {String? message}) async {
assert(_tokenBeginRequest == null,
'Begin should not be called more than once');
@@ -81,12 +79,13 @@ class _ServerCreatedProgressReporter extends _TokenProgressReporter {
}
@override
Future<void> end([String message]) async {
Future<void> end([String? message]) async {
// Only end the token after both create/begin have completed, and return
// a Future to indicate that has happened to callers know when it's safe
// to re-use the token identifier.
if (_tokenBeginRequest != null) {
final didBegin = await _tokenBeginRequest;
final beginRequest = _tokenBeginRequest;
if (beginRequest != null) {
final didBegin = await beginRequest;
if (didBegin) {
super.end(message);
}
@@ -109,14 +108,14 @@ class _TokenProgressReporter extends ProgressReporter {
_TokenProgressReporter(this._server, this._token) : super._();
@override
void begin(String title, {String message}) {
void begin(String? title, {String? message}) {
_needsEnd = true;
_sendNotification(
WorkDoneProgressBegin(title: title ?? 'Working…', message: message));
}
@override
void end([String message]) {
void end([String? message]) {
if (!_needsEnd) return;
_needsEnd = false;
_sendNotification(WorkDoneProgressEnd(message: message));
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
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';
@@ -133,9 +131,7 @@ class ServerCapabilitiesComputer {
ServerCapabilities computeServerCapabilities(
LspClientCapabilities clientCapabilities) {
final codeActionLiteralSupport = clientCapabilities.literalCodeActions;
final renameOptionsSupport = clientCapabilities.renameValidation;
final enableFormatter = _server.clientConfiguration.enableSdkFormatter;
final previewCommitCharacters =
_server.clientConfiguration.previewCommitCharacters;
@@ -204,7 +200,7 @@ class ServerCapabilitiesComputer {
// `textDocument.codeAction.codeActionLiteralSupport`."
codeActionProvider: dynamicRegistrations.codeActions
? null
: codeActionLiteralSupport != null
: codeActionLiteralSupport
? Either2<bool, CodeActionOptions>.t2(CodeActionOptions(
codeActionKinds: DartCodeActionKind.serverSupportedKinds,
))
@@ -322,17 +318,17 @@ class ServerCapabilitiesComputer {
_server.clientConfiguration.previewCommitCharacters;
/// Helper for creating registrations with IDs.
void register(bool condition, Method method, [ToJsonable options]) {
void register(bool condition, Method method, [ToJsonable? options]) {
if (condition == true) {
registrations.add(Registration(
id: (_lastRegistrationId++).toString(),
method: method.toJson(),
method: method.toString(),
registerOptions: options));
}
}
final dynamicRegistrations =
ClientDynamicRegistrations(_server.clientCapabilities.raw);
ClientDynamicRegistrations(_server.clientCapabilities!.raw);
register(
dynamicRegistrations.textSync,
@@ -524,11 +520,12 @@ class ServerCapabilitiesComputer {
RegistrationParams(registrations: registrationsToAdd),
);
if (registrationResponse.error != null) {
final error = registrationResponse.error;
if (error != null) {
_server.logErrorToClient(
'Failed to register capabilities with client: '
'(${registrationResponse.error.code}) '
'${registrationResponse.error.message}',
'(${error.code}) '
'${error.message}',
);
}
}
@@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/mapping.dart';
@@ -12,6 +10,7 @@ import 'package:analysis_server/src/protocol_server.dart' as server
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
@@ -71,17 +70,17 @@ ErrorOr<Pair<String, List<plugin.SourceEdit>>> applyAndConvertEditsToServer(
},
);
// If any change fails, immediately return the error.
if (result?.isError ?? false) {
if (result != null && result.isError) {
return ErrorOr.error(result.error);
}
}
return ErrorOr.success(Pair(newContent, serverEdits));
}
ErrorOr<List<TextEdit>> generateEditsForFormatting(
ErrorOr<List<TextEdit>?> generateEditsForFormatting(
ParsedUnitResult result,
int lineLength, {
Range range,
Range? range,
}) {
final unformattedSource = result.content;
@@ -112,7 +111,8 @@ ErrorOr<List<TextEdit>> generateEditsForFormatting(
List<TextEdit> _generateFullEdit(
LineInfo lineInfo, String unformattedSource, String formattedSource) {
final end = lineInfo.getLocation(unformattedSource.length);
final end =
lineInfo.getLocation(unformattedSource.length) as CharacterLocation;
return [
TextEdit(
range:
@@ -133,17 +133,17 @@ List<TextEdit> _generateFullEdit(
ErrorOr<List<TextEdit>> _generateMinimalEdits(
ParsedUnitResult result,
String formatted, {
Range range,
Range? range,
}) {
final unformatted = result.content;
final lineInfo = result.lineInfo;
final rangeStart = range != null ? toOffset(lineInfo, range.start) : null;
final rangeEnd = range != null ? toOffset(lineInfo, range.end) : null;
if (rangeStart?.isError ?? false) {
if (rangeStart != null && rangeStart.isError) {
return failure(rangeStart);
}
if (rangeEnd?.isError ?? false) {
if (rangeEnd != null && rangeEnd.isError) {
return failure(rangeEnd);
}
@@ -217,8 +217,9 @@ ErrorOr<List<TextEdit>> _generateMinimalEdits(
// edits in the same set.
edits.add(TextEdit(
range: Range(
start: toPosition(lineInfo.getLocation(startOffset)),
end: toPosition(lineInfo.getLocation(endOffset)),
start:
toPosition(lineInfo.getLocation(startOffset) as CharacterLocation),
end: toPosition(lineInfo.getLocation(endOffset) as CharacterLocation),
),
newText: newText,
));
@@ -276,21 +277,22 @@ ErrorOr<List<TextEdit>> _generateMinimalEdits(
/// Iterates over a token stream returning all tokens including comments.
Iterable<Token> _iterateAllTokens(Token token) sync* {
while (token.type != TokenType.EOF) {
var commentToken = token.precedingComments;
Token? commentToken = token.precedingComments;
while (commentToken != null) {
yield commentToken;
commentToken = commentToken.next;
}
yield token;
token = token.next;
token = token.next!;
}
}
/// Parse and return the first of the given Dart source, `null` if code cannot
/// be parsed.
Token _parse(String s, FeatureSet featureSet) {
Token? _parse(String s, FeatureSet featureSet) {
try {
var scanner = Scanner(null, CharSequenceReader(s), null)
var scanner = Scanner(_SourceMock.instance, CharSequenceReader(s),
AnalysisErrorListener.NULL_LISTENER)
..configureFeatures(
featureSetForOverriding: featureSet,
featureSet: featureSet,
@@ -310,11 +312,18 @@ class FileEditInformation {
final bool newFile;
/// The selection offset, relative to the edit.
final int selectionOffsetRelative;
final int selectionLength;
final int? selectionOffsetRelative;
final int? selectionLength;
FileEditInformation(this.doc, this.lineInfo, this.edits,
{this.newFile = false,
this.selectionOffsetRelative,
this.selectionLength});
}
class _SourceMock implements Source {
static final Source instance = _SourceMock();
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
@@ -17,9 +17,6 @@ import 'package:analyzer/src/generated/source.dart';
Future<void> scheduleImplementedNotification(
AnalysisServer server, Iterable<String> files) async {
var searchEngine = server.searchEngine;
if (searchEngine == null) {
return;
}
for (var file in files) {
var unit = server.getCachedResolvedUnit(file)?.unit;
var unitElement = unit?.declaredElement;
@@ -133,7 +133,7 @@ String _getTypeCheckFailureMessage(TypeBase type) {
}
bool _isSimpleType(TypeBase type) {
const literals = ['num', 'String', 'bool'];
const literals = ['num', 'String', 'bool', 'int'];
return type is Type && literals.contains(type.dartType);
}
@@ -202,7 +202,7 @@ List<AstNode> getCustomClasses() {
}
final customTypes = <AstNode>[
interface('DartDiagnosticServer', [field('port', type: 'number')]),
interface('DartDiagnosticServer', [field('port', type: 'int')]),
interface('AnalyzerStatusParams', [field('isAnalyzing', type: 'boolean')]),
interface('PublishClosingLabelsParams', [
field('uri', type: 'string'),
@@ -255,7 +255,7 @@ List<AstNode> getCustomClasses() {
'CompletionItemResolutionInfo',
[
field('file', type: 'string'),
field('offset', type: 'number'),
field('offset', type: 'int'),
],
),
interface(
@@ -263,11 +263,11 @@ List<AstNode> getCustomClasses() {
[
// These fields have short-ish names because they're on the payload
// for all suggestion-set backed completions.
field('libId', type: 'number'),
field('libId', type: 'int'),
field('displayUri', type: 'string'),
field('rOffset', type: 'number'), // replacementOffset
field('iLength', type: 'number'), // insertLength
field('rLength', type: 'number'), // replacementLength
field('rOffset', type: 'int'), // replacementOffset
field('iLength', type: 'int'), // insertLength
field('rLength', type: 'int'), // replacementLength
],
baseType: 'CompletionItemResolutionInfo',
),
@@ -118,6 +118,10 @@ String? getImprovedType(String interfaceName, String? fieldName) {
'ParameterInformation': {
'label': 'String',
},
'Position': {
'character': 'int',
'line': 'int',
},
'ProgressParams': {
'value': 'object',
},
@@ -46,7 +46,7 @@ TypeBase typeOfLiteral(TokenType tokenType) {
final typeName = tokenType == TokenType.STRING
? 'string'
: tokenType == TokenType.NUMBER
? 'number'
? 'int' // all literal numeric values in LSP spec are ints
: throw 'Unknown literal type $tokenType';
return Type.identifier(typeName);
}