LLVM 22.0.0git
Transport.h
Go to the documentation of this file.
1//===--- Transport.h - Sending and Receiving LSP messages -------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// The language server protocol is usually implemented by writing messages as
10// JSON-RPC over the stdin/stdout of a subprocess. This file contains a JSON
11// transport interface that handles this communication.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_SUPPORT_LSP_TRANSPORT_H
16#define LLVM_SUPPORT_LSP_TRANSPORT_H
17
19#include "llvm/ADT/StringMap.h"
20#include "llvm/ADT/StringRef.h"
22#include "llvm/Support/JSON.h"
26#include <memory>
27
28namespace llvm {
29// Simple helper function that returns a string as printed from a op.
30template <typename T> static std::string debugString(T &&Op) {
31 std::string InstrStr;
32 llvm::raw_string_ostream Os(InstrStr);
33 Os << Op;
34 return Os.str();
35}
36namespace lsp {
37class MessageHandler;
38
39//===----------------------------------------------------------------------===//
40// JSONTransport
41//===----------------------------------------------------------------------===//
42
43/// The encoding style of the JSON-RPC messages (both input and output).
45 /// Encoding per the LSP specification, with mandatory Content-Length header.
47 /// Messages are delimited by a '// -----' line. Comment lines start with //.
49};
50
51/// An abstract class used by the JSONTransport to read JSON message.
53public:
55 : Style(Style) {}
56 virtual ~JSONTransportInput() = default;
57
58 virtual bool hasError() const = 0;
59 virtual bool isEndOfInput() const = 0;
60
61 /// Read in a message from the input stream.
62 LogicalResult readMessage(std::string &Json) {
64 : readStandardMessage(Json);
65 }
66 virtual LogicalResult readDelimitedMessage(std::string &Json) = 0;
67 virtual LogicalResult readStandardMessage(std::string &Json) = 0;
68
69private:
70 /// The JSON stream style to use.
71 JSONStreamStyle Style;
72};
73
74/// Concrete implementation of the JSONTransportInput that reads from a file.
76public:
78 std::FILE *In, JSONStreamStyle Style = JSONStreamStyle::Standard)
79 : JSONTransportInput(Style), In(In) {}
80
81 bool hasError() const final { return ferror(In); }
82 bool isEndOfInput() const final { return feof(In); }
83
84 LogicalResult readDelimitedMessage(std::string &Json) final;
85 LogicalResult readStandardMessage(std::string &Json) final;
86
87private:
88 std::FILE *In;
89};
90
91/// A transport class that performs the JSON-RPC communication with the LSP
92/// client.
94public:
95 JSONTransport(std::unique_ptr<JSONTransportInput> In, raw_ostream &Out,
96 bool PrettyOutput = false)
97 : In(std::move(In)), Out(Out), PrettyOutput(PrettyOutput) {}
98
99 JSONTransport(std::FILE *In, raw_ostream &Out,
101 bool PrettyOutput = false)
102 : In(std::make_unique<JSONTransportInputOverFile>(In, Style)), Out(Out),
103 PrettyOutput(PrettyOutput) {}
104
105 /// The following methods are used to send a message to the LSP client.
109
110 /// Start executing the JSON-RPC transport.
112
113private:
114 /// Dispatches the given incoming json message to the message handler.
115 bool handleMessage(llvm::json::Value Msg, MessageHandler &Handler);
116 /// Writes the given message to the output stream.
117 void sendMessage(llvm::json::Value Msg);
118
119private:
120 /// The input to read a message from.
121 std::unique_ptr<JSONTransportInput> In;
123 /// The output file stream.
124 raw_ostream &Out;
125 /// If the output JSON should be formatted for easier readability.
126 bool PrettyOutput;
127};
128
129//===----------------------------------------------------------------------===//
130// MessageHandler
131//===----------------------------------------------------------------------===//
132
133/// A Callback<T> is a void function that accepts Expected<T>. This is
134/// accepted by functions that logically return T.
135template <typename T>
137
138/// An OutgoingNotification<T> is a function used for outgoing notifications
139/// send to the client.
140template <typename T>
142
143/// An OutgoingRequest<T> is a function used for outgoing requests to send to
144/// the client.
145template <typename T>
147 llvm::unique_function<void(const T &, llvm::json::Value Id)>;
148
149/// An `OutgoingRequestCallback` is invoked when an outgoing request to the
150/// client receives a response in turn. It is passed the original request's ID,
151/// as well as the response result.
152template <typename T>
154 std::function<void(llvm::json::Value, llvm::Expected<T>)>;
155
156/// A handler used to process the incoming transport messages.
158public:
159 MessageHandler(JSONTransport &Transport) : Transport(Transport) {}
160
164
165 template <typename T>
167 StringRef PayloadName, StringRef PayloadKind) {
168 T Result;
170 if (fromJSON(Raw, Result, Root))
171 return std::move(Result);
172
173 // Dump the relevant parts of the broken message.
174 std::string Context;
175 llvm::raw_string_ostream Os(Context);
176 Root.printErrorContext(Raw, Os);
177
178 // Report the error (e.g. to the client).
180 llvm::formatv("failed to decode {0} {1}: {2}", PayloadName, PayloadKind,
181 fmt_consume(Root.getError())),
183 }
184
185 template <typename Param, typename Result, typename ThisT>
186 void method(llvm::StringLiteral Method, ThisT *ThisPtr,
187 void (ThisT::*Handler)(const Param &, Callback<Result>)) {
188 MethodHandlers[Method] = [Method, Handler,
189 ThisPtr](llvm::json::Value RawParams,
192 parse<Param>(RawParams, Method, "request");
193 if (!Parameter)
194 return Reply(Parameter.takeError());
195 (ThisPtr->*Handler)(*Parameter, std::move(Reply));
196 };
197 }
198
199 template <typename Param, typename ThisT>
201 void (ThisT::*Handler)(const Param &)) {
202 NotificationHandlers[Method] = [Method, Handler,
203 ThisPtr](llvm::json::Value RawParams) {
205 parse<Param>(RawParams, Method, "notification");
206 if (!Parameter) {
208 Parameter.takeError(), [](const LSPError &LspError) {
209 Logger::error("JSON parsing error: {0}",
210 LspError.message.c_str());
211 }));
212 }
213 (ThisPtr->*Handler)(*Parameter);
214 };
215 }
216
217 /// Create an OutgoingNotification object used for the given method.
218 template <typename T>
220 return [&, Method](const T &Params) {
221 std::lock_guard<std::mutex> TransportLock(TransportOutputMutex);
222 Logger::info("--> {0}", Method);
223 Transport.notify(Method, llvm::json::Value(Params));
224 };
225 }
226
227 /// Create an OutgoingRequest function that, when called, sends a request with
228 /// the given method via the transport. Should the outgoing request be
229 /// met with a response, the result JSON is parsed and the response callback
230 /// is invoked.
231 template <typename Param, typename Result>
235 return [&, Method, Callback](const Param &Parameter, llvm::json::Value Id) {
236 auto CallbackWrapper = [Method, Callback = std::move(Callback)](
239 if (!Value)
240 return Callback(std::move(Id), Value.takeError());
241
242 std::string ResponseName = llvm::formatv("reply:{0}({1})", Method, Id);
244 parse<Result>(*Value, ResponseName, "response");
245 if (!ParseResult)
246 return Callback(std::move(Id), ParseResult.takeError());
247
248 return Callback(std::move(Id), *ParseResult);
249 };
250
251 {
252 std::lock_guard<std::mutex> Lock(ResponseHandlersMutex);
253 ResponseHandlers.insert(
254 {debugString(Id), std::make_pair(Method.str(), CallbackWrapper)});
255 }
256
257 std::lock_guard<std::mutex> TransportLock(TransportOutputMutex);
258 Logger::info("--> {0}({1})", Method, Id);
259 Transport.call(Method, llvm::json::Value(Parameter), Id);
260 };
261 }
262
263private:
264 template <typename HandlerT>
266
267 HandlerMap<void(llvm::json::Value)> NotificationHandlers;
269 MethodHandlers;
270
271 /// A pair of (1) the original request's method name, and (2) the callback
272 /// function to be invoked for responses.
273 using ResponseHandlerTy =
274 std::pair<std::string, OutgoingRequestCallback<llvm::json::Value>>;
275 /// A mapping from request/response ID to response handler.
276 llvm::StringMap<ResponseHandlerTy> ResponseHandlers;
277 /// Mutex to guard insertion into the response handler map.
278 std::mutex ResponseHandlersMutex;
279
280 JSONTransport &Transport;
281
282 /// Mutex to guard sending output messages to the transport.
283 std::mutex TransportOutputMutex;
284};
285
286} // namespace lsp
287} // namespace llvm
288
289#endif
aarch64 promote const
This file defines the StringMap class.
This file provides a collection of function (or more generally, callable) type erasure utilities supp...
This file supports working with JSON data.
#define T
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
Tagged union holding either a T or a Error.
Definition Error.h:485
This class represents success/failure for parsing-like operations that find it important to chain tog...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition StringRef.h:862
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition StringMap.h:133
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
The root is the trivial Path to the root value.
Definition JSON.h:713
LLVM_ABI void printErrorContext(const Value &, llvm::raw_ostream &) const
Print the root value with the error shown inline as a comment.
Definition JSON.cpp:300
LLVM_ABI Error getError() const
Returns the last error reported, or else a generic error.
Definition JSON.cpp:219
A Value is an JSON value of unknown type.
Definition JSON.h:290
Concrete implementation of the JSONTransportInput that reads from a file.
Definition Transport.h:75
LogicalResult readStandardMessage(std::string &Json) final
JSONTransportInputOverFile(std::FILE *In, JSONStreamStyle Style=JSONStreamStyle::Standard)
Definition Transport.h:77
LogicalResult readDelimitedMessage(std::string &Json) final
For lit tests we support a simplified syntax:
virtual bool hasError() const =0
virtual bool isEndOfInput() const =0
virtual LogicalResult readDelimitedMessage(std::string &Json)=0
LogicalResult readMessage(std::string &Json)
Read in a message from the input stream.
Definition Transport.h:62
virtual ~JSONTransportInput()=default
virtual LogicalResult readStandardMessage(std::string &Json)=0
JSONTransportInput(JSONStreamStyle Style=JSONStreamStyle::Standard)
Definition Transport.h:54
A transport class that performs the JSON-RPC communication with the LSP client.
Definition Transport.h:93
void reply(llvm::json::Value Id, llvm::Expected< llvm::json::Value > Result)
llvm::Error run(MessageHandler &Handler)
Start executing the JSON-RPC transport.
void notify(StringRef Method, llvm::json::Value Params)
The following methods are used to send a message to the LSP client.
JSONTransport(std::unique_ptr< JSONTransportInput > In, raw_ostream &Out, bool PrettyOutput=false)
Definition Transport.h:95
void call(StringRef Method, llvm::json::Value Params, llvm::json::Value Id)
JSONTransport(std::FILE *In, raw_ostream &Out, JSONStreamStyle Style=JSONStreamStyle::Standard, bool PrettyOutput=false)
Definition Transport.h:99
This class models an LSP error as an llvm::Error.
Definition Protocol.h:79
static void info(const char *Fmt, Ts &&...Vals)
Definition Logging.h:35
A handler used to process the incoming transport messages.
Definition Transport.h:157
OutgoingRequest< Param > outgoingRequest(llvm::StringLiteral Method, OutgoingRequestCallback< Result > Callback)
Create an OutgoingRequest function that, when called, sends a request with the given method via the t...
Definition Transport.h:233
void notification(llvm::StringLiteral Method, ThisT *ThisPtr, void(ThisT::*Handler)(const Param &))
Definition Transport.h:200
OutgoingNotification< T > outgoingNotification(llvm::StringLiteral Method)
Create an OutgoingNotification object used for the given method.
Definition Transport.h:219
bool onNotify(StringRef Method, llvm::json::Value Value)
Definition Transport.cpp:86
void method(llvm::StringLiteral Method, ThisT *ThisPtr, void(ThisT::*Handler)(const Param &, Callback< Result >))
Definition Transport.h:186
MessageHandler(JSONTransport &Transport)
Definition Transport.h:159
static llvm::Expected< T > parse(const llvm::json::Value &Raw, StringRef PayloadName, StringRef PayloadKind)
Definition Transport.h:166
bool onCall(StringRef Method, llvm::json::Value Params, llvm::json::Value Id)
bool onReply(llvm::json::Value Id, llvm::Expected< llvm::json::Value > Result)
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
A raw_ostream that writes to an std::string.
std::string & str()
Returns the string's reference.
unique_function is a type-erasing functor similar to std::function.
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition Transport.h:136
llvm::unique_function< void(const T &, llvm::json::Value Id)> OutgoingRequest
An OutgoingRequest<T> is a function used for outgoing requests to send to the client.
Definition Transport.h:146
@ Parameter
An inlay hint that is for a parameter.
Definition Protocol.h:1105
std::function< void(llvm::json::Value, llvm::Expected< T >)> OutgoingRequestCallback
An OutgoingRequestCallback is invoked when an outgoing request to the client receives a response in t...
Definition Transport.h:153
bool fromJSON(const llvm::json::Value &value, URIForFile &result, llvm::json::Path path)
Definition Protocol.cpp:242
JSONStreamStyle
The encoding style of the JSON-RPC messages (both input and output).
Definition Transport.h:44
@ Standard
Encoding per the LSP specification, with mandatory Content-Length header.
Definition Transport.h:46
@ Delimited
Messages are delimited by a '// --—' line. Comment lines start with //.
Definition Transport.h:48
llvm::unique_function< void(const T &)> OutgoingNotification
An OutgoingNotification<T> is a function used for outgoing notifications send to the client.
Definition Transport.h:141
This is an optimization pass for GlobalISel generic memory operations.
support::detail::ErrorAdapter fmt_consume(Error &&Item)
Error handleErrors(Error E, HandlerTs &&... Hs)
Pass the ErrorInfo(s) contained in E to their respective handlers.
Definition Error.h:967
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
static std::string debugString(T &&Op)
Definition Transport.h:30
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
DWARFExpression::Operation Op
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1849
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1083
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:851
This class represents an efficient way to signal success or failure.