[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:
committed by
commit-bot@chromium.org
parent
543d653ca8
commit
77466f2b83
@@ -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';
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user