[Analyzer] Handle parsing v3.16 LSP Spec
Change-Id: I6afd5c32673ba580cdf6691bdfa521766f65c3b0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/158392 Commit-Queue: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
4adebc6d2a
commit
4525525a9d
File diff suppressed because it is too large
Load Diff
@@ -78,17 +78,18 @@ abstract class Commands {
|
||||
}
|
||||
|
||||
abstract class CustomMethods {
|
||||
static const DiagnosticServer = Method('dart/diagnosticServer');
|
||||
static const Reanalyze = Method('dart/reanalyze');
|
||||
static const PublishClosingLabels =
|
||||
static const diagnosticServer = Method('dart/diagnosticServer');
|
||||
static const reanalyze = Method('dart/reanalyze');
|
||||
static const publishClosingLabels =
|
||||
Method('dart/textDocument/publishClosingLabels');
|
||||
static const PublishOutline = Method('dart/textDocument/publishOutline');
|
||||
static const PublishFlutterOutline =
|
||||
static const publishOutline = Method('dart/textDocument/publishOutline');
|
||||
static const publishFlutterOutline =
|
||||
Method('dart/textDocument/publishFlutterOutline');
|
||||
static const Super = Method('dart/textDocument/super');
|
||||
static const super_ = Method('dart/textDocument/super');
|
||||
|
||||
// TODO(dantup): Remove custom AnalyzerStatus status method soon as no clients
|
||||
// should be relying on it and we now support proper $/progress events.
|
||||
static const AnalyzerStatus = Method(r'$/analyzerStatus');
|
||||
static const analyzerStatus = Method(r'$/analyzerStatus');
|
||||
}
|
||||
|
||||
/// CodeActionKinds supported by the server that are not declared in the LSP spec.
|
||||
|
||||
@@ -28,7 +28,7 @@ abstract class SimpleEditCommandHandler
|
||||
}
|
||||
|
||||
Future<ErrorOr<void>> sendSourceEditsToClient(
|
||||
VersionedTextDocumentIdentifier docIdentifier,
|
||||
OptionalVersionedTextDocumentIdentifier docIdentifier,
|
||||
CompilationUnit unit,
|
||||
List<SourceEdit> edits) async {
|
||||
// If there are no edits to apply, just complete the command without going
|
||||
|
||||
@@ -13,7 +13,7 @@ class DiagnosticServerHandler
|
||||
extends MessageHandler<void, DartDiagnosticServer> {
|
||||
DiagnosticServerHandler(LspAnalysisServer server) : super(server);
|
||||
@override
|
||||
Method get handlesMessage => CustomMethods.DiagnosticServer;
|
||||
Method get handlesMessage => CustomMethods.diagnosticServer;
|
||||
|
||||
@override
|
||||
LspJsonHandler<void> get jsonHandler => NullJsonHandler;
|
||||
|
||||
@@ -11,7 +11,7 @@ import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
|
||||
class ReanalyzeHandler extends MessageHandler<void, void> {
|
||||
ReanalyzeHandler(LspAnalysisServer server) : super(server);
|
||||
@override
|
||||
Method get handlesMessage => CustomMethods.Reanalyze;
|
||||
Method get handlesMessage => CustomMethods.reanalyze;
|
||||
|
||||
@override
|
||||
LspJsonHandler<void> get jsonHandler => NullJsonHandler;
|
||||
|
||||
@@ -14,7 +14,7 @@ class SuperHandler
|
||||
extends MessageHandler<TextDocumentPositionParams, Location> {
|
||||
SuperHandler(LspAnalysisServer server) : super(server);
|
||||
@override
|
||||
Method get handlesMessage => CustomMethods.Super;
|
||||
Method get handlesMessage => CustomMethods.super_;
|
||||
|
||||
@override
|
||||
LspJsonHandler<TextDocumentPositionParams> get jsonHandler =>
|
||||
|
||||
@@ -87,6 +87,7 @@ class RenameHandler extends MessageHandler<RenameParams, WorkspaceEdit> {
|
||||
}
|
||||
|
||||
final pos = params.position;
|
||||
final textDocument = params.textDocument;
|
||||
final path = pathOfDoc(params.textDocument);
|
||||
// If the client provided us a version doc identifier, we'll use it to ensure
|
||||
// we're not computing a rename for an old document. If not, we'll just assume
|
||||
@@ -94,9 +95,12 @@ class RenameHandler extends MessageHandler<RenameParams, WorkspaceEdit> {
|
||||
// and then use it to verify the document hadn't changed again before we
|
||||
// send the edits.
|
||||
final docIdentifier = await path.mapResult((path) => success(
|
||||
params.textDocument is VersionedTextDocumentIdentifier
|
||||
? params.textDocument as VersionedTextDocumentIdentifier
|
||||
: server.getVersionedDocumentIdentifier(path)));
|
||||
textDocument is OptionalVersionedTextDocumentIdentifier
|
||||
? textDocument
|
||||
: textDocument is VersionedTextDocumentIdentifier
|
||||
? OptionalVersionedTextDocumentIdentifier(
|
||||
uri: textDocument.uri, version: textDocument.version)
|
||||
: server.getVersionedDocumentIdentifier(path)));
|
||||
|
||||
final unit = await path.mapResult(requireResolvedUnit);
|
||||
final offset = await unit.mapResult((unit) => toOffset(unit.lineInfo, pos));
|
||||
|
||||
@@ -118,7 +118,7 @@ class TextDocumentOpenHandler
|
||||
final doc = params.textDocument;
|
||||
final path = pathOfDocItem(doc);
|
||||
return path.mapResult((path) {
|
||||
// We don't get a VersionedTextDocumentIdentifier with a didOpen but we
|
||||
// We don't get a OptionalVersionedTextDocumentIdentifier with a didOpen but we
|
||||
// do get the necessary info to create one.
|
||||
server.documentVersions[path] = VersionedTextDocumentIdentifier(
|
||||
version: params.textDocument.version,
|
||||
|
||||
@@ -248,11 +248,13 @@ class LspAnalysisServer extends AbstractAnalysisServer {
|
||||
}
|
||||
|
||||
/// Gets the version of a document known to the server, returning a
|
||||
/// [VersionedTextDocumentIdentifier] with a version of `null` if the document
|
||||
/// [OptionalVersionedTextDocumentIdentifier] with a version of `null` if the document
|
||||
/// version is not known.
|
||||
VersionedTextDocumentIdentifier getVersionedDocumentIdentifier(String path) {
|
||||
return documentVersions[path] ??
|
||||
VersionedTextDocumentIdentifier(uri: Uri.file(path).toString());
|
||||
OptionalVersionedTextDocumentIdentifier getVersionedDocumentIdentifier(
|
||||
String path) {
|
||||
return OptionalVersionedTextDocumentIdentifier(
|
||||
uri: Uri.file(path).toString(),
|
||||
version: documentVersions[path]?.version);
|
||||
}
|
||||
|
||||
void handleClientConnection(
|
||||
@@ -424,7 +426,7 @@ class LspAnalysisServer extends AbstractAnalysisServer {
|
||||
final params = PublishClosingLabelsParams(
|
||||
uri: Uri.file(path).toString(), labels: labels);
|
||||
final message = NotificationMessage(
|
||||
method: CustomMethods.PublishClosingLabels,
|
||||
method: CustomMethods.publishClosingLabels,
|
||||
params: params,
|
||||
jsonrpc: jsonRpcVersion,
|
||||
);
|
||||
@@ -446,7 +448,7 @@ class LspAnalysisServer extends AbstractAnalysisServer {
|
||||
final params = PublishFlutterOutlineParams(
|
||||
uri: Uri.file(path).toString(), outline: outline);
|
||||
final message = NotificationMessage(
|
||||
method: CustomMethods.PublishFlutterOutline,
|
||||
method: CustomMethods.publishFlutterOutline,
|
||||
params: params,
|
||||
jsonrpc: jsonRpcVersion,
|
||||
);
|
||||
@@ -457,7 +459,7 @@ class LspAnalysisServer extends AbstractAnalysisServer {
|
||||
final params =
|
||||
PublishOutlineParams(uri: Uri.file(path).toString(), outline: outline);
|
||||
final message = NotificationMessage(
|
||||
method: CustomMethods.PublishOutline,
|
||||
method: CustomMethods.publishOutline,
|
||||
params: params,
|
||||
jsonrpc: jsonRpcVersion,
|
||||
);
|
||||
@@ -552,7 +554,7 @@ class LspAnalysisServer extends AbstractAnalysisServer {
|
||||
// it's unlikely to be in use by any clients.
|
||||
if (clientCapabilities.window?.workDoneProgress != true) {
|
||||
channel.sendNotification(NotificationMessage(
|
||||
method: CustomMethods.AnalyzerStatus,
|
||||
method: CustomMethods.analyzerStatus,
|
||||
params: AnalyzerStatusParams(isAnalyzing: status.isAnalyzing),
|
||||
jsonrpc: jsonRpcVersion,
|
||||
));
|
||||
|
||||
@@ -1211,7 +1211,10 @@ lsp.SignatureHelp toSignatureHelp(List<lsp.MarkupKind> preferredFormats,
|
||||
lsp.TextDocumentEdit toTextDocumentEdit(FileEditInformation edit) {
|
||||
return lsp.TextDocumentEdit(
|
||||
textDocument: edit.doc,
|
||||
edits: edit.edits.map((e) => toTextEdit(edit.lineInfo, e)).toList(),
|
||||
edits: edit.edits
|
||||
.map((e) => Either2<TextEdit, AnnotatedTextEdit>.t1(
|
||||
toTextEdit(edit.lineInfo, e)))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ class ClientDynamicRegistrations {
|
||||
/// All dynamic registrations supported by the Dart LSP server.
|
||||
///
|
||||
/// Anything listed here and supported by the client will not send a static
|
||||
/// registration but intead dynamically register (usually only for a subset of
|
||||
/// registration but instead dynamically register (usually only for a subset of
|
||||
/// files such as for .dart/pubspec.yaml/etc).
|
||||
///
|
||||
/// When adding new capabilities that will be registered dynamically, the
|
||||
@@ -124,7 +124,8 @@ class ServerCapabilitiesComputer {
|
||||
return ServerCapabilities(
|
||||
textDocumentSync: dynamicRegistrations.textSync
|
||||
? null
|
||||
: Either2<TextDocumentSyncOptions, num>.t1(TextDocumentSyncOptions(
|
||||
: Either2<TextDocumentSyncOptions, TextDocumentSyncKind>.t1(
|
||||
TextDocumentSyncOptions(
|
||||
// The open/close and sync kind flags are registered dynamically if the
|
||||
// client supports them, so these static registrations are based on whether
|
||||
// the client supports dynamic registration.
|
||||
|
||||
@@ -302,7 +302,7 @@ Token _parse(String s, FeatureSet featureSet) {
|
||||
/// Helper class that bundles up all information required when converting server
|
||||
/// SourceEdits into LSP-compatible WorkspaceEdits.
|
||||
class FileEditInformation {
|
||||
final VersionedTextDocumentIdentifier doc;
|
||||
final OptionalVersionedTextDocumentIdentifier doc;
|
||||
final LineInfo lineInfo;
|
||||
final List<server.SourceEdit> edits;
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ class InitializationTest extends AbstractLspAnalysisServerTest {
|
||||
emptyTextDocumentClientCapabilities))),
|
||||
);
|
||||
|
||||
// Because we support dynamic registration for synchronisation, we won't send
|
||||
// Because we support dynamic registration for synchronization, we won't send
|
||||
// static registrations for them.
|
||||
// https://github.com/dart-lang/sdk/issues/38490
|
||||
final initResult = InitializeResult.fromJson(initResponse.result);
|
||||
@@ -53,7 +53,7 @@ class InitializationTest extends AbstractLspAnalysisServerTest {
|
||||
expect(initResult.capabilities, isNotNull);
|
||||
expect(initResult.capabilities.textDocumentSync, isNull);
|
||||
|
||||
// Should container Hover, DidOpen, DidClose, DidChange.
|
||||
// Should contain Hover, DidOpen, DidClose, DidChange.
|
||||
expect(registrations, hasLength(4));
|
||||
final hover =
|
||||
registrationOptionsFor(registrations, Method.textDocument_hover);
|
||||
|
||||
@@ -565,13 +565,16 @@ mixin LspAnalysisServerTestMixin implements ClientCapabilitiesHelperMixin {
|
||||
});
|
||||
}
|
||||
|
||||
String applyTextEdit(String content, TextEdit change) {
|
||||
final startPos = change.range.start;
|
||||
final endPos = change.range.end;
|
||||
String applyTextEdit(
|
||||
String content, Either2<TextEdit, AnnotatedTextEdit> change) {
|
||||
// Both sites of the union can cast to TextEdit.
|
||||
final edit = change.map((e) => e, (e) => e);
|
||||
final startPos = edit.range.start;
|
||||
final endPos = edit.range.end;
|
||||
final lineInfo = LineInfo.fromContent(content);
|
||||
final start = lineInfo.getOffsetOfLine(startPos.line) + startPos.character;
|
||||
final end = lineInfo.getOffsetOfLine(endPos.line) + endPos.character;
|
||||
return content.replaceRange(start, end, change.newText);
|
||||
return content.replaceRange(start, end, edit.newText);
|
||||
}
|
||||
|
||||
String applyTextEdits(String oldContent, List<TextEdit> changes) {
|
||||
@@ -626,7 +629,8 @@ mixin LspAnalysisServerTestMixin implements ClientCapabilitiesHelperMixin {
|
||||
);
|
||||
|
||||
for (final change in sortedChanges) {
|
||||
newContent = applyTextEdit(newContent, change);
|
||||
newContent = applyTextEdit(
|
||||
newContent, Either2<TextEdit, AnnotatedTextEdit>.t1(change));
|
||||
}
|
||||
|
||||
return newContent;
|
||||
@@ -702,7 +706,7 @@ mixin LspAnalysisServerTestMixin implements ClientCapabilitiesHelperMixin {
|
||||
final path = Uri.parse(edit.textDocument.uri).toFilePath();
|
||||
final expectedVersion = expectedVersions[path];
|
||||
|
||||
if (edit.textDocument is VersionedTextDocumentIdentifier) {
|
||||
if (edit.textDocument is OptionalVersionedTextDocumentIdentifier) {
|
||||
expect(edit.textDocument.version, equals(expectedVersion));
|
||||
} else {
|
||||
throw 'Document identifier for $path was not versioned (expected version $expectedVersion)';
|
||||
@@ -901,7 +905,7 @@ mixin LspAnalysisServerTestMixin implements ClientCapabilitiesHelperMixin {
|
||||
|
||||
Future<DartDiagnosticServer> getDiagnosticServer() {
|
||||
final request = makeRequest(
|
||||
CustomMethods.DiagnosticServer,
|
||||
CustomMethods.diagnosticServer,
|
||||
null,
|
||||
);
|
||||
return expectSuccessfulResponseTo(request, DartDiagnosticServer.fromJson);
|
||||
@@ -1009,7 +1013,7 @@ mixin LspAnalysisServerTestMixin implements ClientCapabilitiesHelperMixin {
|
||||
Position pos,
|
||||
) {
|
||||
final request = makeRequest(
|
||||
CustomMethods.Super,
|
||||
CustomMethods.super_,
|
||||
TextDocumentPositionParams(
|
||||
textDocument: TextDocumentIdentifier(uri: uri.toString()),
|
||||
position: pos,
|
||||
@@ -1428,10 +1432,10 @@ mixin LspAnalysisServerTestMixin implements ClientCapabilitiesHelperMixin {
|
||||
Future<void> waitForAnalysisStatus(bool analyzing) async {
|
||||
await serverToClient.firstWhere((message) {
|
||||
if (message is NotificationMessage) {
|
||||
if (message.method == CustomMethods.AnalyzerStatus) {
|
||||
if (message.method == CustomMethods.analyzerStatus) {
|
||||
if (_clientCapabilities.window?.workDoneProgress == true) {
|
||||
throw Exception(
|
||||
'Recieved ${CustomMethods.AnalyzerStatus} notification '
|
||||
'Recieved ${CustomMethods.analyzerStatus} notification '
|
||||
'but client supports workDoneProgress');
|
||||
}
|
||||
|
||||
@@ -1440,7 +1444,7 @@ mixin LspAnalysisServerTestMixin implements ClientCapabilitiesHelperMixin {
|
||||
} else if (message.method == Method.progress) {
|
||||
if (_clientCapabilities.window?.workDoneProgress != true) {
|
||||
throw Exception(
|
||||
'Recieved ${CustomMethods.AnalyzerStatus} notification '
|
||||
'Recieved ${CustomMethods.analyzerStatus} notification '
|
||||
'but client supports workDoneProgress');
|
||||
}
|
||||
|
||||
@@ -1473,7 +1477,7 @@ mixin LspAnalysisServerTestMixin implements ClientCapabilitiesHelperMixin {
|
||||
PublishClosingLabelsParams closingLabelsParams;
|
||||
await serverToClient.firstWhere((message) {
|
||||
if (message is NotificationMessage &&
|
||||
message.method == CustomMethods.PublishClosingLabels) {
|
||||
message.method == CustomMethods.publishClosingLabels) {
|
||||
closingLabelsParams =
|
||||
PublishClosingLabelsParams.fromJson(message.params);
|
||||
|
||||
@@ -1501,7 +1505,7 @@ mixin LspAnalysisServerTestMixin implements ClientCapabilitiesHelperMixin {
|
||||
PublishFlutterOutlineParams outlineParams;
|
||||
await serverToClient.firstWhere((message) {
|
||||
if (message is NotificationMessage &&
|
||||
message.method == CustomMethods.PublishFlutterOutline) {
|
||||
message.method == CustomMethods.publishFlutterOutline) {
|
||||
outlineParams = PublishFlutterOutlineParams.fromJson(message.params);
|
||||
|
||||
return outlineParams.uri == uri.toString();
|
||||
@@ -1515,7 +1519,7 @@ mixin LspAnalysisServerTestMixin implements ClientCapabilitiesHelperMixin {
|
||||
PublishOutlineParams outlineParams;
|
||||
await serverToClient.firstWhere((message) {
|
||||
if (message is NotificationMessage &&
|
||||
message.method == CustomMethods.PublishOutline) {
|
||||
message.method == CustomMethods.publishOutline) {
|
||||
outlineParams = PublishOutlineParams.fromJson(message.params);
|
||||
|
||||
return outlineParams.uri == uri.toString();
|
||||
|
||||
@@ -167,7 +167,7 @@ void main() {
|
||||
// Value whether expected to parse
|
||||
const testTraceValues = {
|
||||
'off': true,
|
||||
'messages': true,
|
||||
'message': true,
|
||||
'verbose': true,
|
||||
null: true,
|
||||
'invalid': false,
|
||||
|
||||
@@ -68,7 +68,7 @@ final Uri specLicenseUri = Uri.parse(
|
||||
/// The URI of the version of the spec to generate from. This should be periodically updated as
|
||||
/// there's no longer a stable URI for the latest published version.
|
||||
final Uri specUri = Uri.parse(
|
||||
'https://raw.githubusercontent.com/microsoft/language-server-protocol/gh-pages/_specifications/specification-3-15.md');
|
||||
'https://raw.githubusercontent.com/microsoft/language-server-protocol/gh-pages/_specifications/specification-3-16.md');
|
||||
|
||||
/// Pattern to extract inline types from the `result: {xx, yy }` notes in the spec.
|
||||
/// Doesn't parse past full stops as some of these have english sentences tagged on
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ final _methodNamesPattern = RegExp(
|
||||
r'''_(?:Notification|Request):?_:?(?:\r?\n)+\* method: ['`](.*?)[`'],?\r?\n''',
|
||||
multiLine: true);
|
||||
final _typeScriptBlockPattern =
|
||||
RegExp(r'\B```typescript([\S\s]*?)\n```', multiLine: true);
|
||||
RegExp(r'\B```typescript([\S\s]*?)\n\s*```', multiLine: true);
|
||||
|
||||
List<String> extractMethodNames(String spec) {
|
||||
return _methodNamesPattern
|
||||
|
||||
@@ -76,6 +76,7 @@ String getImprovedType(String interfaceName, String fieldName) {
|
||||
'Diagnostic': {
|
||||
'severity': 'DiagnosticSeverity',
|
||||
'code': 'String',
|
||||
'data': 'object',
|
||||
},
|
||||
'TextDocumentSyncOptions': {
|
||||
'change': 'TextDocumentSyncKind',
|
||||
@@ -89,6 +90,10 @@ String getImprovedType(String interfaceName, String fieldName) {
|
||||
'CompletionItem': {
|
||||
'kind': 'CompletionItemKind',
|
||||
'data': 'CompletionItemResolutionInfo',
|
||||
'textEdit': 'TextEdit',
|
||||
},
|
||||
'CallHierarchyItem': {
|
||||
'data': 'object',
|
||||
},
|
||||
'DocumentHighlight': {
|
||||
'kind': 'DocumentHighlightKind',
|
||||
|
||||
@@ -287,6 +287,9 @@ class Parser {
|
||||
/// Ensures the next token is [type] and moves to the next, throwing [message]
|
||||
/// if not.
|
||||
Token _consume(TokenType type, String message) {
|
||||
// Skip over any inline comments when looking for a specific token.
|
||||
_match([TokenType.COMMENT]);
|
||||
|
||||
if (_check(type)) {
|
||||
return _advance();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user