From 341b60796a372841fea233c370af38178ca2839c Mon Sep 17 00:00:00 2001 From: Danny Tuppeny Date: Thu, 16 Jun 2022 16:11:21 +0000 Subject: [PATCH] [analysis_server] Generate typedefs for LSP params/result unions Many params/result types are defined as unions without names in the spec. This gives them names so the handlers will be able to use names instead of the full EitherX type. Change-Id: I3f96b48e5e70c86814724edc3fec4fc7f76534de Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/248801 Commit-Queue: Brian Wilkerson Reviewed-by: Brian Wilkerson --- .../lib/lsp_protocol/protocol_generated.dart | 227 ++++++++++++++++++ .../test/lsp/server_abstract.dart | 2 +- .../tool/lsp_spec/meta_model.dart | 1 + .../tool/lsp_spec/meta_model_reader.dart | 61 +++++ 4 files changed, 290 insertions(+), 1 deletion(-) diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart index 9e005043f2c..04d9334fbdc 100644 --- a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart +++ b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart @@ -16,6 +16,18 @@ import 'package:analysis_server/src/protocol/protocol_internal.dart'; const jsonEncoder = JsonEncoder.withIndent(' '); +/// Result for a request to resolve the incoming calls for a given +/// `CallHierarchyItem`. +/// +/// @since 3.16.0 +typedef CallHierarchyIncomingCallsResult = List?; + +/// Result for a request to resolve the outgoing calls for a given +/// `CallHierarchyItem`. +/// +/// @since 3.16.0 +typedef CallHierarchyOutgoingCallsResult = List?; + /// An identifier to refer to a change annotation stored with a workspace edit. typedef ChangeAnnotationIdentifier = String; @@ -119,11 +131,61 @@ typedef PrepareRenameResult = Either3; typedef ProgressToken = Either2; +/// Result for a request to provide commands for the given text document and +/// range. +typedef TextDocumentCodeActionResult = List>?; + +/// Result for a request to provide code lens for the given text document. +typedef TextDocumentCodeLensResult = List?; + +/// Result for request to request completion at a given text document position. +/// The request's parameter is of type TextDocumentPosition the response is of +/// type [CompletionItem[]](#CompletionItem) or CompletionList or a Thenable +/// that resolves to such. +/// +/// The request can delay the computation of the `detail` and `documentation` +/// properties to the `completionItem/resolve` request. However, properties that +/// are needed for the initial sorting and filtering, like `sortText`, +/// `filterText`, `insertText`, and `textEdit`, must not be changed during +/// resolve. +typedef TextDocumentCompletionResult + = Either2>?; + /// An event describing a change to a text document. If only a text is provided /// it is considered to be the full content of the document. typedef TextDocumentContentChangeEvent = Either2; +/// Result for a request to resolve the type definition locations of a symbol at +/// a given text document position. The request's parameter is of type +/// TextDocumentPositionParams the response is of type Declaration or a typed +/// array of DeclarationLink or a Thenable that resolves to such. +typedef TextDocumentDeclarationResult + = Either2>?; + +/// Result for a request to resolve the definition location of a symbol at a +/// given text document position. The request's parameter is of type +/// TextDocumentPosition the response is of either type Definition or a typed +/// array of DefinitionLink or a Thenable that resolves to such. +typedef TextDocumentDefinitionResult + = Either2>?; + +/// Result for request to resolve a DocumentHighlight for a given text document +/// position. The request's parameter is of type TextDocumentPosition the +/// request response is of type [DocumentHighlight[]] (#DocumentHighlight) or a +/// Thenable that resolves to such. +typedef TextDocumentDocumentHighlightResult = List?; + +/// Result for a request to provide document links +typedef TextDocumentDocumentLinkResult = List?; + +/// Result for a request to list all symbols found in a given text document. The +/// request's parameter is of type TextDocumentIdentifier the response is of +/// type [SymbolInformation[]](#SymbolInformation) or a Thenable that resolves +/// to such. +typedef TextDocumentDocumentSymbolResult + = Either2, List>?; + /// A document filter denotes a document by different properties like the /// language, the scheme of its resource, or a glob-pattern that is applied to /// the path. @@ -148,6 +210,131 @@ typedef TextDocumentContentChangeEvent typedef TextDocumentFilter = Either3; +/// Result for a request to provide folding ranges in a document. The request's +/// parameter is of type FoldingRangeParams, the response is of type +/// FoldingRangeList or a Thenable that resolves to such. +typedef TextDocumentFoldingRangeResult = List?; + +/// Result for a request to to format a whole document. +typedef TextDocumentFormattingResult = List?; + +/// Result for request to request hover information at a given text document +/// position. The request's parameter is of type TextDocumentPosition the +/// response is of type Hover or a Thenable that resolves to such. +typedef TextDocumentHoverResult = Hover?; + +/// Result for a request to resolve the implementation locations of a symbol at +/// a given text document position. The request's parameter is of type +/// TextDocumentPositionParams the response is of type Definition or a Thenable +/// that resolves to such. +typedef TextDocumentImplementationResult + = Either2>?; + +/// Result for a request to provide inlay hints in a document. The request's +/// parameter is of type InlayHintsParams, the response is of type +/// [InlayHint[]](#InlayHint[]) or a Thenable that resolves to such. +/// +/// @since 3.17.0 +typedef TextDocumentInlayHintResult = List?; + +/// Result for a request to provide inline values in a document. The request's +/// parameter is of type InlineValueParams, the response is of type +/// [InlineValue[]](#InlineValue[]) or a Thenable that resolves to such. +/// +/// @since 3.17.0 +typedef TextDocumentInlineValueResult = List?; + +/// Result for a request to provide ranges that can be edited together. +/// +/// @since 3.16.0 +typedef TextDocumentLinkedEditingRangeResult = LinkedEditingRanges?; + +/// Result for a request to get the moniker of a symbol at a given text document +/// position. The request parameter is of type TextDocumentPositionParams. The +/// response is of type [Moniker[]](#Moniker[]) or `null`. +typedef TextDocumentMonikerResult = List?; + +/// Result for a request to format a document on type. +typedef TextDocumentOnTypeFormattingResult = List?; + +/// Result for a request to result a `CallHierarchyItem` in a document at a +/// given position. Can be used as an input to an incoming or outgoing call +/// hierarchy. +/// +/// @since 3.16.0 +typedef TextDocumentPrepareCallHierarchyResult = List?; + +/// Result for a request to test and perform the setup necessary for a rename. +/// +/// @since 3.16 - support for default behavior +typedef TextDocumentPrepareRenameResult = PrepareRenameResult?; + +/// Result for a request to result a `TypeHierarchyItem` in a document at a +/// given position. Can be used as an input to a subtypes or supertypes type +/// hierarchy. +/// +/// @since 3.17.0 +typedef TextDocumentPrepareTypeHierarchyResult = List?; + +/// Result for a request to to format a range in a document. +typedef TextDocumentRangeFormattingResult = List?; + +/// Result for a request to resolve project-wide references for the symbol +/// denoted by the given text document position. The request's parameter is of +/// type ReferenceParams the response is of type [Location[]](#Location) or a +/// Thenable that resolves to such. +typedef TextDocumentReferencesResult = List?; + +/// Result for a request to rename a symbol. +typedef TextDocumentRenameResult = WorkspaceEdit?; + +/// Result for a request to provide selection ranges in a document. The +/// request's parameter is of type SelectionRangeParams, the response is of type +/// [SelectionRange[]](#SelectionRange[]) or a Thenable that resolves to such. +typedef TextDocumentSelectionRangeResult = List?; + +/// Result for @since 3.16.0 +typedef TextDocumentSemanticTokensFullDeltaResult + = Either2?; + +/// Result for @since 3.16.0 +typedef TextDocumentSemanticTokensFullResult = SemanticTokens?; + +/// Result for @since 3.16.0 +typedef TextDocumentSemanticTokensRangeResult = SemanticTokens?; +typedef TextDocumentSignatureHelpResult = SignatureHelp?; + +/// Result for a request to resolve the type definition locations of a symbol at +/// a given text document position. The request's parameter is of type +/// TextDocumentPositioParams the response is of type Definition or a Thenable +/// that resolves to such. +typedef TextDocumentTypeDefinitionResult + = Either2>?; + +/// Result for a document will save request is sent from the client to the +/// server before the document is actually saved. The request can return an +/// array of TextEdits which will be applied to the text document before it is +/// saved. Please note that clients might drop results if computing the text +/// edits took too long or if a server constantly fails on this request. This is +/// done to keep the save fast and reliable. +typedef TextDocumentWillSaveWaitUntilResult = List?; + +/// Result for a request to resolve the subtypes for a given +/// `TypeHierarchyItem`. +/// +/// @since 3.17.0 +typedef TypeHierarchySubtypesResult = List?; + +/// Result for a request to resolve the supertypes for a given +/// `TypeHierarchyItem`. +/// +/// @since 3.17.0 +typedef TypeHierarchySupertypesResult = List?; + +/// Result for the show message request is sent from the server to the client to +/// show a message and a set of options actions to the user. +typedef WindowShowMessageRequestResult = MessageActionItem?; + /// A workspace diagnostic document report. /// /// @since 3.17.0 @@ -155,6 +342,46 @@ typedef WorkspaceDocumentDiagnosticReport = Either2< WorkspaceFullDocumentDiagnosticReport, WorkspaceUnchangedDocumentDiagnosticReport>; +/// Result for a request send from the client to the server to execute a +/// command. The request might return a workspace edit which the client will +/// apply to the workspace. +typedef WorkspaceExecuteCommandResult = LSPAny?; + +/// Result for a request to list project-wide symbols matching the query string +/// given by the WorkspaceSymbolParams. The response is of type +/// [SymbolInformation[]](#SymbolInformation) or a Thenable that resolves to +/// such. +/// +/// @since 3.17.0 - support for WorkspaceSymbol in the returned data. Clients +/// need to advertise support for WorkspaceSymbols via the client capability +/// `workspace.symbol.resolveSupport`. +typedef WorkspaceSymbolResult + = Either2, List>?; + +/// Result for the will create files request is sent from the client to the +/// server before files are actually created as long as the creation is +/// triggered from within the client. +/// +/// @since 3.16.0 +typedef WorkspaceWillCreateFilesResult = WorkspaceEdit?; + +/// Result for the did delete files notification is sent from the client to the +/// server when files were deleted from within the client. +/// +/// @since 3.16.0 +typedef WorkspaceWillDeleteFilesResult = WorkspaceEdit?; + +/// Result for the will rename files request is sent from the client to the +/// server before files are actually renamed as long as the rename is triggered +/// from within the client. +/// +/// @since 3.16.0 +typedef WorkspaceWillRenameFilesResult = WorkspaceEdit?; + +/// Result for the `workspace/workspaceFolders` is sent from the server to the +/// client to fetch the open workspace folders. +typedef WorkspaceWorkspaceFoldersResult = List?; + /// A special text edit with an additional change annotation. /// /// @since 3.16.0. diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart index b3f677fa356..27998105f1c 100644 --- a/pkg/analysis_server/test/lsp/server_abstract.dart +++ b/pkg/analysis_server/test/lsp/server_abstract.dart @@ -1753,7 +1753,7 @@ mixin LspAnalysisServerTestMixin implements ClientCapabilitiesHelperMixin { Future sendDidChangeConfiguration() { final request = makeRequest( Method.workspace_didChangeConfiguration, - DidChangeConfigurationParams(settings: {}), + DidChangeConfigurationParams(), ); return sendRequestToServer(request); } diff --git a/pkg/analysis_server/tool/lsp_spec/meta_model.dart b/pkg/analysis_server/tool/lsp_spec/meta_model.dart index 20aadea15a3..827307966ec 100644 --- a/pkg/analysis_server/tool/lsp_spec/meta_model.dart +++ b/pkg/analysis_server/tool/lsp_spec/meta_model.dart @@ -226,6 +226,7 @@ class TypeAlias extends LspEntity { /// Renames will be followed when generating code, but other aliases may be /// created as `typedef`s. final bool isRename; + TypeAlias({ required super.name, super.comment, diff --git a/pkg/analysis_server/tool/lsp_spec/meta_model_reader.dart b/pkg/analysis_server/tool/lsp_spec/meta_model_reader.dart index 3be39a9961d..aa11e78fc9b 100644 --- a/pkg/analysis_server/tool/lsp_spec/meta_model_reader.dart +++ b/pkg/analysis_server/tool/lsp_spec/meta_model_reader.dart @@ -49,6 +49,12 @@ class LspMetaModelReader { ...?typeAliases?.map(_readTypeAlias), ].forEach(_addType); + // Requests and notifications may have inline union types as their + // params/result. We can create TypeAliases for those using sensible + // names to simplify their use in the handlers. + requests?.forEach(_readRequest); + notifications?.forEach(_readNotification); + final methodsEnum = _createMethodNamesEnum(methodNames); if (methodsEnum != null) { _addType(methodsEnum); @@ -94,6 +100,32 @@ class LspMetaModelReader { ); } + /// Creates a type alias for a top-level union, such as those used for + /// request parameters/results that don't have named types in the spec. + void _createUnionAlias(String name, dynamic model, String? documentation) { + if (model == null) { + return; + } + + // We don't currently support reading the two top-level intersection types. + // These can just be skipped because the types we're generating here are + // just for convenience (to produce better names for use in handlers rather + // than referencing `EitherX` everywhere). + if (model['kind'] == 'and') { + return; + } + + final type = _extractType(name, '', model); + if (type is UnionType) { + _addType(TypeAlias( + name: name, + comment: documentation, + baseType: type, + isRename: false, + )); + } + } + Constant _extractEnumValue(TypeBase parentType, dynamic model) { final name = model['name'] as String; return Constant( @@ -257,6 +289,35 @@ class LspMetaModelReader { ); } + void _readNotification(dynamic model) { + final method = model['method'] as String; + final namePrefix = method.split('/').map(capitalize).join(); + final documentation = model['documentation'] as String?; + + final paramsDoc = documentation != null + ? 'Parameters for ${_camelCase(documentation)}' + : null; + + _createUnionAlias('${namePrefix}Params', model['params'], paramsDoc); + } + + void _readRequest(dynamic model) { + final method = model['method'] as String; + final namePrefix = method.split('/').map(capitalize).join(); + final documentation = model['documentation'] as String?; + + final paramsDoc = documentation != null + ? 'Parameters for ${_camelCase(documentation)}' + : null; + + final resultDoc = documentation != null + ? 'Result for ${_camelCase(documentation)}' + : null; + + _createUnionAlias('${namePrefix}Params', model['params'], paramsDoc); + _createUnionAlias('${namePrefix}Result', model['result'], resultDoc); + } + LspEntity _readStructure(dynamic model) { final name = model['name'] as String; return Interface(