[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 // sent - and may have failed to apply - was related to this command
// execution). // execution).
// We need to fromJson to convert the JSON map to the real types. // 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?>); editResponse.result as Map<String, Object?>);
if (editResponseResult.applied) { if (editResponseResult.applied) {
return success(null); return success(null);

View file

@ -2,7 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a // 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. // 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/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/protocol/protocol_generated.dart'; import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart'; import 'package:analysis_server/src/lsp/handlers/handlers.dart';

View file

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

View file

@ -192,7 +192,7 @@ void newMethod() {
final params = ApplyWorkspaceEditParams.fromJson( final params = ApplyWorkspaceEditParams.fromJson(
request.params as Map<String, Object?>); request.params as Map<String, Object?>);
edit = params.edit; 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?, final commandResponse = handleExpectedRequest<Object?,
ApplyWorkspaceEditParams, ApplyWorkspaceEditResponse>( ApplyWorkspaceEditParams, ApplyWorkspaceEditResult>(
Method.workspace_applyEdit, Method.workspace_applyEdit,
ApplyWorkspaceEditParams.fromJson, ApplyWorkspaceEditParams.fromJson,
() => executeCommand(command), () => executeCommand(command),
// Claim that we failed tpo apply the edits. This is what the client // 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 // would do if the edits provided were for an old version of the
// document. // document.
handler: (edit) => ApplyWorkspaceEditResponse( handler: (edit) => ApplyWorkspaceEditResult(
applied: false, failureReason: 'Document changed'), applied: false, failureReason: 'Document changed'),
); );

View file

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

View file

@ -6,7 +6,6 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart' as lsp; 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/lsp_protocol/protocol_special.dart' as lsp;
import 'package:analysis_server/src/lsp/channel/lsp_channel.dart'; import 'package:analysis_server/src/lsp/channel/lsp_channel.dart';
@ -40,12 +39,12 @@ class MockLspServerChannel implements LspServerCommunicationChannel {
// `window/showMessage`. // `window/showMessage`.
_serverToClient.stream.listen((message) { _serverToClient.stream.listen((message) {
if (message is lsp.NotificationMessage && if (message is lsp.NotificationMessage &&
message.method == Method.window_showMessage) { message.method == lsp.Method.window_showMessage) {
final params = message.params; final params = message.params;
if (params is lsp.ShowMessageParams) { if (params is lsp.ShowMessageParams) {
if (params.type == MessageType.Error) { if (params.type == lsp.MessageType.Error) {
shownErrors.add(params); shownErrors.add(params);
} else if (params.type == MessageType.Warning) { } else if (params.type == lsp.MessageType.Warning) {
shownWarnings.add(params); shownWarnings.add(params);
} }
} }
@ -170,13 +169,7 @@ class MockLspServerChannel implements LspServerCommunicationChannel {
}) async { }) async {
final response = await _serverToClient.stream.firstWhere((message) => final response = await _serverToClient.stream.firstWhere((message) =>
(message is lsp.ResponseMessage && message.id == request.id) || (message is lsp.ResponseMessage && message.id == request.id) ||
(throwOnError && (throwOnError && _isShowErrorMessageNotification(message)));
message is lsp.NotificationMessage &&
message.method == Method.window_showMessage &&
lsp.ShowMessageParams.fromJson(
message.params as Map<String, Object?>)
.type ==
MessageType.Error));
if (response is lsp.ResponseMessage) { if (response is lsp.ResponseMessage) {
return response; return response;
@ -195,4 +188,19 @@ class MockLspServerChannel implements LspServerCommunicationChannel {
return constructor( return constructor(
jsonDecode(jsonEncode(message.toJson())) as Map<String, Object?>); 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 /// 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. /// there's no longer a stable URI for the latest published version.
final Uri specUri = Uri.parse( 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. /// 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 /// 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 download the latest version of the specification before regenerating the
code, run the same script with an argument of "--download".''', code, run the same script with an argument of "--download".''',
licenseResp.body, licenseResp.body,
specResp.body await _fetchIncludes(specResp.body, specUri),
]; ];
await File(localSpecPath).writeAsString(text.join('\n\n---\n\n')); await File(localSpecPath).writeAsString(text.join('\n\n---\n\n'));
} }
@ -203,6 +203,16 @@ List<AstNode> getCustomClasses() {
} }
final customTypes = <AstNode>[ final customTypes = <AstNode>[
TypeAlias(
null,
Token.identifier('LSPAny'),
Type.Any,
),
TypeAlias(
null,
Token.identifier('LSPObject'),
Type.Any,
),
interface('DartDiagnosticServer', [field('port', type: 'int')]), interface('DartDiagnosticServer', [field('port', type: 'int')]),
interface('AnalyzerStatusParams', [field('isAnalyzing', type: 'boolean')]), interface('AnalyzerStatusParams', [field('isAnalyzing', type: 'boolean')]),
interface('PublishClosingLabelsParams', [ interface('PublishClosingLabelsParams', [
@ -370,7 +380,8 @@ bool shouldIncludeScriptBlock(String input) {
// Skip over some typescript blocks that are known sample code and not part // Skip over some typescript blocks that are known sample code and not part
// of the LSP spec. // of the LSP spec.
if (input.trim() == r"export const EOL: string[] = ['\n', '\r\n', '\r'];" || 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; return false;
} }
@ -416,3 +427,23 @@ AstNode withCustomFields(AstNode node) {
[...node.members, ...customFields], [...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 // 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. // BSD-style license that can be found in the LICENSE file.
final _methodNamesPattern = RegExp( final _methodNamesPattern =
r'''_(?:Notification|Request):?_:?(?:\r?\n)+\* method: ['`](.*?)[`'],?\r?\n''', RegExp(r'''\* method: ['`](.*?)[`'],?\r?\n''', multiLine: true);
multiLine: true);
final _typeScriptBlockPattern = final _typeScriptBlockPattern =
RegExp(r'\B```typescript([\S\s]*?)\n\s*```', multiLine: true); 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. /// Removes types that are in the spec that we don't want to emit.
bool includeTypeDefinitionInOutput(AstNode node) { 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 // have to handle any cases where both a namespace and interfaces are declared
// with the same name. // with the same name.
return node.name != 'InitializeError' && return node.name != 'InitializeError' &&

View file

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