LLVM: lib/Support/LSP/Transport.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

14#include

15#include

16#include <system_error>

17#include

18

19using namespace llvm;

21

22

23

24

25

26namespace {

27

28

29

30

31class Reply {

32public:

33 Reply(const llvm::json::Value &Id, StringRef Method, JSONTransport &Transport,

34 std::mutex &TransportOutputMutex);

35 Reply(Reply &&Other);

36 Reply &operator=(Reply &&) = delete;

37 Reply(const Reply &) = delete;

38 Reply &operator=(const Reply &) = delete;

39

40 void operator()(llvm::Expectedllvm::json::Value Reply);

41

42private:

43 std::string Method;

44 std::atomic Replied = {false};

45 llvm::json::Value Id;

46 JSONTransport *Transport;

47 std::mutex &TransportOutputMutex;

48};

49}

50

52 JSONTransport &Transport, std::mutex &TransportOutputMutex)

54 TransportOutputMutex(TransportOutputMutex) {}

55

56Reply::Reply(Reply &&Other)

59 TransportOutputMutex(Other.TransportOutputMutex) {

60 Other.Transport = nullptr;

61}

62

64 if (Replied.exchange(true)) {

66 assert(false && "must reply to each call only once!");

67 return;

68 }

69 assert(Transport && "expected valid transport to reply to");

70

71 std::lock_guardstd::mutex TransportLock(TransportOutputMutex);

72 if (Reply) {

74 Transport->reply(std::move(Id), std::move(Reply));

75 } else {

78 Transport->reply(std::move(Id), std::move(Error));

79 }

80}

81

82

83

84

85

88

90 return false;

91 if (Method == "$cancel") {

92

93 } else {

94 auto It = NotificationHandlers.find(Method);

95 if (It != NotificationHandlers.end())

96 It->second(std::move(Value));

97 }

98 return true;

99}

100

104

105 Reply Reply(Id, Method, Transport, TransportOutputMutex);

106

107 auto It = MethodHandlers.find(Method);

108 if (It != MethodHandlers.end()) {

109 It->second(std::move(Params), std::move(Reply));

110 } else {

113 }

114 return true;

115}

116

119

120

121 ResponseHandlerTy ResponseHandler;

122 {

123 std::lock_guardstd::mutex responseHandlersLock(ResponseHandlersMutex);

124 auto It = ResponseHandlers.find(debugString(Id));

125 if (It != ResponseHandlers.end()) {

126 ResponseHandler = std::move(It->second);

127 ResponseHandlers.erase(It);

128 }

129 }

130

131

132 if (ResponseHandler.second) {

133 Logger::info("--> reply:{0}({1})", ResponseHandler.first, Id);

134 ResponseHandler.second(std::move(Id), std::move(Result));

135 } else {

137 "received a reply with ID {0}, but there was no such outgoing request",

138 Id);

139 if (!Result)

141 }

142 return true;

143}

144

145

146

147

148

149

151 std::string Message;

154 Message = LspError.message;

155 Code = LspError.code;

157 };

160

162 {"message", std::move(Message)},

163 {"code", int64_t(Code)},

164 };

165}

166

167

169 StringRef Msg = O.getString("message").value_or("Unspecified error");

170 if (std::optional<int64_t> Code = O.getInteger("code"))

173 Msg.str());

174}

175

178 {"jsonrpc", "2.0"},

180 {"params", std::move(Params)},

181 });

182}

186 {"jsonrpc", "2.0"},

187 {"id", std::move(Id)},

189 {"params", std::move(Params)},

190 });

191}

194 if (Result) {

196 {"jsonrpc", "2.0"},

197 {"id", std::move(Id)},

198 {"result", std::move(*Result)},

199 });

200 }

201

203 {"jsonrpc", "2.0"},

204 {"id", std::move(Id)},

205 {"error", encodeError(Result.takeError())},

206 });

207}

208

210 std::string Json;

211 while (!In->isEndOfInput()) {

212 if (In->hasError()) {

214 std::error_code(errno, std::system_category()));

215 }

216

217 if (succeeded(In->readMessage(Json))) {

219 if (!handleMessage(std::move(*Doc), Handler))

221 } else {

223 }

224 }

225 }

227}

228

232 os << llvm::formatv(PrettyOutput ? "{0:2}\n" : "{0}", Msg);

233 Out << "Content-Length: " << OutputBuffer.size() << "\r\n\r\n"

235 Out.flush();

237}

238

241

244 Object->getString("jsonrpc") != std::optional("2.0"))

245 return false;

246

247

248 std::optionalllvm::json::Value Id;

250 Id = std::move(*I);

251 std::optional Method = Object->getString("method");

252

253

255 if (!Id)

256 return false;

257 if (auto *Err = Object->getObject("error"))

259

262 Result = std::move(*R);

263 return Handler.onReply(std::move(*Id), std::move(Result));

264 }

265

266

269 Params = std::move(*P);

270

271 if (Id)

272 return Handler.onCall(*Method, std::move(Params), std::move(*Id));

274}

275

276

277

279

280

281 static constexpr int BufSize = 128;

282 size_t Size = 0;

284 for (;;) {

286 if (!std::fgets(&Out[Size], BufSize, In))

288

289 clearerr(In);

290

291

292

293 size_t Read = std::strlen(&Out[Size]);

294 if (Read > 0 && Out[Size + Read - 1] == '\n') {

297 }

299 }

300}

301

302

303

304

305LogicalResult

307

308

309 unsigned long long ContentLength = 0;

311 while (true) {

314

315

319 } else if (!LineRef.trim().empty()) {

320

321 continue;

322 } else {

323

324 break;

325 }

326 }

327

328

329 if (ContentLength == 0 || ContentLength > 1 << 30)

331

332 Json.resize(ContentLength);

333 for (size_t Pos = 0, Read; Pos < ContentLength; Pos += Read) {

334 Read = std::fread(&Json[Pos], 1, ContentLength - Pos, In);

335 if (Read == 0)

337

338

339

340 clearerr(In);

342 }

344}

345

346

347

348

349

350

351

354 Json.clear();

359

360 if (LineRef == "// -----")

361 break;

362 continue;

363 }

364

365 Json += Line;

366 }

367

368 return failure(ferror(In));

369}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

AMDGPU Mark last scratch load

This file defines the SmallString class.

static llvm::json::Object encodeError(llvm::Error Error)

Encode the given error as a JSON object.

Definition Transport.cpp:150

LogicalResult readLine(std::FILE *In, SmallVectorImpl< char > &Out)

Tries to read a line up to and including .

Definition Transport.cpp:278

llvm::Error decodeError(const llvm::json::Object &O)

Decode the given JSON object into an error.

Definition Transport.cpp:168

Lightweight error class with error context and mandatory checking.

static ErrorSuccess success()

Create a success value.

Tagged union holding either a T or a Error.

Error takeError()

Take ownership of the stored error.

SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

void resize_for_overwrite(size_type N)

Like resize, but T is POD, the new values won't be initialized.

StringRef - Represent a constant reference to a string, i.e.

std::string str() const

str - Get the contents as an std::string.

bool starts_with(StringRef Prefix) const

Check if this string starts with the given Prefix.

constexpr bool empty() const

empty - Check if the string is empty.

bool consume_front(StringRef Prefix)

Returns true if this StringRef has the given prefix and removes that prefix.

StringRef trim(char Char) const

Return string with consecutive Char characters starting from the left and right removed.

An Object is a JSON object, which maps strings to heterogenous JSON values.

A Value is an JSON value of unknown type.

const json::Object * getAsObject() const

LLVM_ABI_FOR_TEST LogicalResult readStandardMessage(std::string &Json) final

Definition Transport.cpp:306

bool hasError() const final

LLVM_ABI_FOR_TEST LogicalResult readDelimitedMessage(std::string &Json) final

For lit tests we support a simplified syntax:

Definition Transport.cpp:353

A transport class that performs the JSON-RPC communication with the LSP client.

LLVM_ABI_FOR_TEST void reply(llvm::json::Value Id, llvm::Expected< llvm::json::Value > Result)

Definition Transport.cpp:192

LLVM_ABI_FOR_TEST llvm::Error run(MessageHandler &Handler)

Start executing the JSON-RPC transport.

Definition Transport.cpp:209

LLVM_ABI_FOR_TEST void notify(StringRef Method, llvm::json::Value Params)

The following methods are used to send a message to the LSP client.

Definition Transport.cpp:176

LLVM_ABI_FOR_TEST void call(StringRef Method, llvm::json::Value Params, llvm::json::Value Id)

Definition Transport.cpp:183

This class models an LSP error as an llvm::Error.

static void error(const char *Fmt, Ts &&...Vals)

static void debug(const char *Fmt, Ts &&...Vals)

Initiate a log message at various severity levels.

static void info(const char *Fmt, Ts &&...Vals)

A handler used to process the incoming transport messages.

bool onNotify(StringRef Method, llvm::json::Value Value)

Definition Transport.cpp:86

bool onCall(StringRef Method, llvm::json::Value Params, llvm::json::Value Id)

Definition Transport.cpp:101

bool onReply(llvm::json::Value Id, llvm::Expected< llvm::json::Value > Result)

Definition Transport.cpp:117

A raw_ostream that writes to an SmallVector or SmallString.

LLVM_ABI llvm::Expected< Value > parse(llvm::StringRef JSON)

Parses the provided JSON source, or returns a ParseError.

This is an optimization pass for GlobalISel generic memory operations.

bool succeeded(LogicalResult Result)

Utility function that returns true if the provided LogicalResult corresponds to a success value.

bool failed(LogicalResult Result)

Utility function that returns true if the provided LogicalResult corresponds to a failure value.

LLVM_ABI std::error_code inconvertibleErrorCode()

The value returned by this function can be returned from convertToErrorCode for Error values where no...

Error handleErrors(Error E, HandlerTs &&... Hs)

Pass the ErrorInfo(s) contained in E to their respective handlers.

LogicalResult failure(bool IsFailure=true)

Utility function to generate a LogicalResult.

auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)

static std::string debugString(T &&Op)

Error make_error(ArgTs &&... Args)

Make a Error instance representing failure using the given error info type.

std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)

OutputIt move(R &&Range, OutputIt Out)

Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.

LLVM_ABI bool getAsUnsignedInteger(StringRef Str, unsigned Radix, unsigned long long &Result)

Helper functions for StringRef::getAsInteger.

LLVM_ABI Error errorCodeToError(std::error_code EC)

Helper for converting an std::error_code to a Error.

void consumeError(Error Err)

Consume a Error without doing anything.

Implement std::hash so that hash_code can be used in STL containers.

This class represents an efficient way to signal success or failure.