[analysis_server] Switch to LSP v3.17 spec + regenerate types

Change-Id: I6e1b79f3e814c44784dbf37d859ae46d303db2dc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/244243
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Danny Tuppeny 2022-05-10 18:08:35 +00:00 committed by Commit Bot
parent 063ee76dc7
commit 6b6a199806
13 changed files with 18341 additions and 4349 deletions

File diff suppressed because it is too large Load diff

View file

@ -71,7 +71,7 @@ abstract class SimpleEditCommandHandler
// sent - and may have failed to apply - was related to this command
// execution).
// We need to fromJson to convert the JSON map to the real types.
final editResponseResult = ApplyWorkspaceEditResponse.fromJson(
final editResponseResult = ApplyWorkspaceEditResult.fromJson(
editResponse.result as Map<String, Object?>);
if (editResponseResult.applied) {
return success(null);

View file

@ -2,7 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart'
hide TypeHierarchyItem;
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';

View file

@ -101,7 +101,7 @@ abstract class AbstractCodeActionsTest extends AbstractLspAnalysisServerTest {
ApplyWorkspaceEditParams? editParams;
final commandResponse = await handleExpectedRequest<Object?,
ApplyWorkspaceEditParams, ApplyWorkspaceEditResponse>(
ApplyWorkspaceEditParams, ApplyWorkspaceEditResult>(
Method.workspace_applyEdit,
ApplyWorkspaceEditParams.fromJson,
() => executeCommand(command, workDoneToken: workDoneToken),
@ -109,7 +109,7 @@ abstract class AbstractCodeActionsTest extends AbstractLspAnalysisServerTest {
// When the server sends the edit back, just keep a copy and say we
// applied successfully (it'll be verified below).
editParams = edit;
return ApplyWorkspaceEditResponse(applied: true);
return ApplyWorkspaceEditResult(applied: true);
},
);
// Successful edits return an empty success() response.

View file

@ -192,7 +192,7 @@ void newMethod() {
final params = ApplyWorkspaceEditParams.fromJson(
request.params as Map<String, Object?>);
edit = params.edit;
respondTo(request, ApplyWorkspaceEditResponse(applied: true));
respondTo(request, ApplyWorkspaceEditResult(applied: true));
}
});

View file

@ -322,14 +322,14 @@ class SortMembersSourceCodeActionsTest extends AbstractCodeActionsTest {
);
final commandResponse = handleExpectedRequest<Object?,
ApplyWorkspaceEditParams, ApplyWorkspaceEditResponse>(
ApplyWorkspaceEditParams, ApplyWorkspaceEditResult>(
Method.workspace_applyEdit,
ApplyWorkspaceEditParams.fromJson,
() => executeCommand(command),
// Claim that we failed tpo apply the edits. This is what the client
// would do if the edits provided were for an old version of the
// document.
handler: (edit) => ApplyWorkspaceEditResponse(
handler: (edit) => ApplyWorkspaceEditResult(
applied: false, failureReason: 'Document changed'),
);

View file

@ -2169,7 +2169,7 @@ void f() {
// Execute the associated command (which will handle edits in other files).
ApplyWorkspaceEditParams? editParams;
final commandResponse = await handleExpectedRequest<Object?,
ApplyWorkspaceEditParams, ApplyWorkspaceEditResponse>(
ApplyWorkspaceEditParams, ApplyWorkspaceEditResult>(
Method.workspace_applyEdit,
ApplyWorkspaceEditParams.fromJson,
() => executeCommand(resolved.command!),
@ -2177,7 +2177,7 @@ void f() {
// When the server sends the edit back, just keep a copy and say we
// applied successfully (it'll be verified below).
editParams = edit;
return ApplyWorkspaceEditResponse(applied: true);
return ApplyWorkspaceEditResult(applied: true);
},
);
// Successful edits return an empty success() response.

View file

@ -6,7 +6,6 @@ import 'dart:async';
import 'dart:convert';
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' as lsp;
import 'package:analysis_server/src/lsp/channel/lsp_channel.dart';
@ -40,12 +39,12 @@ class MockLspServerChannel implements LspServerCommunicationChannel {
// `window/showMessage`.
_serverToClient.stream.listen((message) {
if (message is lsp.NotificationMessage &&
message.method == Method.window_showMessage) {
message.method == lsp.Method.window_showMessage) {
final params = message.params;
if (params is lsp.ShowMessageParams) {
if (params.type == MessageType.Error) {
if (params.type == lsp.MessageType.Error) {
shownErrors.add(params);
} else if (params.type == MessageType.Warning) {
} else if (params.type == lsp.MessageType.Warning) {
shownWarnings.add(params);
}
}
@ -170,13 +169,7 @@ class MockLspServerChannel implements LspServerCommunicationChannel {
}) async {
final response = await _serverToClient.stream.firstWhere((message) =>
(message is lsp.ResponseMessage && message.id == request.id) ||
(throwOnError &&
message is lsp.NotificationMessage &&
message.method == Method.window_showMessage &&
lsp.ShowMessageParams.fromJson(
message.params as Map<String, Object?>)
.type ==
MessageType.Error));
(throwOnError && _isShowErrorMessageNotification(message)));
if (response is lsp.ResponseMessage) {
return response;
@ -195,4 +188,19 @@ class MockLspServerChannel implements LspServerCommunicationChannel {
return constructor(
jsonDecode(jsonEncode(message.toJson())) as Map<String, Object?>);
}
/// Checks whether [message] is a `window/showMessage` notification with a
/// type of [lsp.MessageType.Error].
bool _isShowErrorMessageNotification(lsp.Message message) {
if (message is! lsp.NotificationMessage) {
return false;
}
if (message.method != lsp.Method.window_showMessage) {
return false;
}
final params = lsp.ShowMessageParams.fromJson(
message.params as Map<String, Object?>,
);
return params.type == lsp.MessageType.Error;
}
}

View file

@ -69,7 +69,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-16.md');
'https://raw.githubusercontent.com/microsoft/language-server-protocol/gh-pages/_specifications/lsp/3.17/specification.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
@ -90,7 +90,7 @@ To regenerate the generated code, run the script in
download the latest version of the specification before regenerating the
code, run the same script with an argument of "--download".''',
licenseResp.body,
specResp.body
await _fetchIncludes(specResp.body, specUri),
];
await File(localSpecPath).writeAsString(text.join('\n\n---\n\n'));
}
@ -203,6 +203,16 @@ List<AstNode> getCustomClasses() {
}
final customTypes = <AstNode>[
TypeAlias(
null,
Token.identifier('LSPAny'),
Type.Any,
),
TypeAlias(
null,
Token.identifier('LSPObject'),
Type.Any,
),
interface('DartDiagnosticServer', [field('port', type: 'int')]),
interface('AnalyzerStatusParams', [field('isAnalyzing', type: 'boolean')]),
interface('PublishClosingLabelsParams', [
@ -370,7 +380,8 @@ bool shouldIncludeScriptBlock(String input) {
// Skip over some typescript blocks that are known sample code and not part
// of the LSP spec.
if (input.trim() == r"export const EOL: string[] = ['\n', '\r\n', '\r'];" ||
input.startsWith('textDocument.codeAction.resolveSupport =')) {
input.startsWith('textDocument.codeAction.resolveSupport =') ||
input.startsWith('textDocument.inlayHint.resolveSupport =')) {
return false;
}
@ -416,3 +427,23 @@ AstNode withCustomFields(AstNode node) {
[...node.members, ...customFields],
);
}
/// Fetches and in-lines any includes that appear in [spec] in the form
/// `{% include_relative types/uri.md %}`.
Future<String> _fetchIncludes(String spec, Uri baseUri) async {
final pattern = RegExp(r'{% include_relative ([\w\-.\/]+.md) %}');
final includeStrings = <String, String>{};
for (final match in pattern.allMatches(spec)) {
final relativeUri = match.group(1)!;
final fullUri = baseUri.resolve(relativeUri);
final response = await http.get(fullUri);
if (response.statusCode != 200) {
throw 'Faild to fetch $fullUri (${response.statusCode} ${response.reasonPhrase})';
}
includeStrings[relativeUri] = response.body;
}
return spec.replaceAllMapped(
pattern,
(match) => includeStrings[match.group(1)!]!,
);
}

File diff suppressed because it is too large Load diff

View file

@ -2,9 +2,8 @@
// 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.
final _methodNamesPattern = RegExp(
r'''_(?:Notification|Request):?_:?(?:\r?\n)+\* method: ['`](.*?)[`'],?\r?\n''',
multiLine: true);
final _methodNamesPattern =
RegExp(r'''\* method: ['`](.*?)[`'],?\r?\n''', multiLine: true);
final _typeScriptBlockPattern =
RegExp(r'\B```typescript([\S\s]*?)\n\s*```', multiLine: true);

View file

@ -145,7 +145,7 @@ List<String> getSpecialBaseTypes(Interface interface) {
/// Removes types that are in the spec that we don't want to emit.
bool includeTypeDefinitionInOutput(AstNode node) {
// These types are not used for v3.0 (Feb 2017) and by dropping them we don't
// InitializeError is not used for v3.0 (Feb 2017) and by dropping it we don't
// have to handle any cases where both a namespace and interfaces are declared
// with the same name.
return node.name != 'InitializeError' &&

View file

@ -27,7 +27,11 @@ final _keywords = const <String, TokenType>{
final _validIdentifierCharacters = RegExp('[a-zA-Z0-9_]');
bool isAnyType(TypeBase t) =>
t is Type && (t.name == 'any' || t.name == 'object');
t is Type &&
(t.name == 'any' ||
t.name == 'LSPAny' ||
t.name == 'object' ||
t.name == 'LSPObject');
bool isLiteralType(TypeBase t) => t is LiteralType;
@ -251,6 +255,8 @@ class Parser {
if (_nodes.isEmpty) {
while (!_isAtEnd) {
_nodes.add(_topLevel());
// Consume any trailing semicolons.
_match([TokenType.SEMI_COLON]);
}
}
return _nodes;