diff options
Diffstat (limited to 'clang-tools-extra/clangd/JSONRPCDispatcher.cpp')
-rw-r--r-- | clang-tools-extra/clangd/JSONRPCDispatcher.cpp | 126 |
1 files changed, 78 insertions, 48 deletions
diff --git a/clang-tools-extra/clangd/JSONRPCDispatcher.cpp b/clang-tools-extra/clangd/JSONRPCDispatcher.cpp index 69ba2e186d2..e9a203d77f2 100644 --- a/clang-tools-extra/clangd/JSONRPCDispatcher.cpp +++ b/clang-tools-extra/clangd/JSONRPCDispatcher.cpp @@ -19,6 +19,12 @@ using namespace clang; using namespace clangd; +namespace { +static Key<std::unique_ptr<trace::Span>> RequestSpan; +static Key<json::Expr> RequestID; +static Key<JSONOutput *> RequestOut; +} // namespace + void JSONOutput::writeMessage(const json::Expr &Message) { std::string S; llvm::raw_string_ostream OS(S); @@ -38,7 +44,7 @@ void JSONOutput::writeMessage(const json::Expr &Message) { Outs.flush(); } -void JSONOutput::log(const Twine &Message) { +void JSONOutput::log(const Context &Ctx, const Twine &Message) { trace::log(Message); std::lock_guard<std::mutex> Guard(StreamMutex); Logs << Message << '\n'; @@ -53,46 +59,56 @@ void JSONOutput::mirrorInput(const Twine &Message) { InputMirror->flush(); } -void RequestContext::reply(json::Expr &&Result) { +void clangd::reply(const Context &Ctx, json::Expr &&Result) { + auto ID = Ctx.get(RequestID); if (!ID) { - Out.log("Attempted to reply to a notification!"); + log(Ctx, "Attempted to reply to a notification!"); return; } - SPAN_ATTACH(tracer(), "Reply", Result); - Out.writeMessage(json::obj{ - {"jsonrpc", "2.0"}, - {"id", *ID}, - {"result", std::move(Result)}, - }); + + if (auto *Span = Ctx.get(RequestSpan)) + SPAN_ATTACH(**Span, "Reply", Result); + + Ctx.getExisting(RequestOut) + ->writeMessage(json::obj{ + {"jsonrpc", "2.0"}, + {"id", *ID}, + {"result", std::move(Result)}, + }); } -void RequestContext::replyError(ErrorCode code, - const llvm::StringRef &Message) { - Out.log("Error " + Twine(static_cast<int>(code)) + ": " + Message); - SPAN_ATTACH(tracer(), "Error", - (json::obj{{"code", static_cast<int>(code)}, - {"message", Message.str()}})); - if (ID) { - Out.writeMessage(json::obj{ - {"jsonrpc", "2.0"}, - {"id", *ID}, - {"error", - json::obj{{"code", static_cast<int>(code)}, {"message", Message}}}, - }); +void clangd::replyError(const Context &Ctx, ErrorCode code, + const llvm::StringRef &Message) { + log(Ctx, "Error " + Twine(static_cast<int>(code)) + ": " + Message); + if (auto *Span = Ctx.get(RequestSpan)) + SPAN_ATTACH(**Span, "Error", + (json::obj{{"code", static_cast<int>(code)}, + {"message", Message.str()}})); + + if (auto ID = Ctx.get(RequestID)) { + Ctx.getExisting(RequestOut) + ->writeMessage(json::obj{ + {"jsonrpc", "2.0"}, + {"id", *ID}, + {"error", + json::obj{{"code", static_cast<int>(code)}, {"message", Message}}}, + }); } } -void RequestContext::call(StringRef Method, json::Expr &&Params) { +void clangd::call(const Context &Ctx, StringRef Method, json::Expr &&Params) { // FIXME: Generate/Increment IDs for every request so that we can get proper // replies once we need to. - SPAN_ATTACH(tracer(), "Call", - (json::obj{{"method", Method.str()}, {"params", Params}})); - Out.writeMessage(json::obj{ - {"jsonrpc", "2.0"}, - {"id", 1}, - {"method", Method}, - {"params", std::move(Params)}, - }); + if (auto *Span = Ctx.get(RequestSpan)) + SPAN_ATTACH(**Span, "Call", + (json::obj{{"method", Method.str()}, {"params", Params}})); + Ctx.getExisting(RequestOut) + ->writeMessage(json::obj{ + {"jsonrpc", "2.0"}, + {"id", 1}, + {"method", Method}, + {"params", std::move(Params)}, + }); } void JSONRPCDispatcher::registerHandler(StringRef Method, Handler H) { @@ -120,8 +136,18 @@ bool JSONRPCDispatcher::call(const json::Expr &Message, JSONOutput &Out) const { auto I = Handlers.find(*Method); auto &Handler = I != Handlers.end() ? I->second : UnknownHandler; - RequestContext Ctx(Out, *Method, std::move(ID)); - SPAN_ATTACH(Ctx.tracer(), "Params", Params); + + auto Tracer = llvm::make_unique<trace::Span>(*Method); + if (ID) + SPAN_ATTACH(*Tracer, "ID", *ID); + SPAN_ATTACH(*Tracer, "Params", Params); + + auto Ctx = Context::empty() + .derive(RequestOut, &Out) + .derive(RequestSpan, std::move(Tracer)); + if (ID) + Ctx = std::move(Ctx).derive(RequestID, *ID); + Handler(std::move(Ctx), std::move(Params)); return true; } @@ -164,9 +190,10 @@ void clangd::runLanguageServerLoop(std::istream &In, JSONOutput &Out, // The end of headers is signified by an empty line. if (LineRef.consume_front("Content-Length: ")) { if (ContentLength != 0) { - Out.log("Warning: Duplicate Content-Length header received. " - "The previous value for this message (" + - std::to_string(ContentLength) + ") was ignored."); + log(Context::empty(), + "Warning: Duplicate Content-Length header received. " + "The previous value for this message (" + + std::to_string(ContentLength) + ") was ignored.\n"); } llvm::getAsUnsignedInteger(LineRef.trim(), 0, ContentLength); @@ -185,8 +212,8 @@ void clangd::runLanguageServerLoop(std::istream &In, JSONOutput &Out, // and we don't want to crash downstream because of it. if (ContentLength > 1 << 30) { // 1024M In.ignore(ContentLength); - Out.log("Skipped overly large message of " + Twine(ContentLength) + - " bytes."); + log(Context::empty(), "Skipped overly large message of " + + Twine(ContentLength) + " bytes.\n"); continue; } @@ -200,9 +227,10 @@ void clangd::runLanguageServerLoop(std::istream &In, JSONOutput &Out, // If the stream is aborted before we read ContentLength bytes, In // will have eofbit and failbit set. if (!In) { - Out.log("Input was aborted. Read only " + - std::to_string(In.gcount()) + " bytes of expected " + - std::to_string(ContentLength) + "."); + log(Context::empty(), "Input was aborted. Read only " + + std::to_string(In.gcount()) + + " bytes of expected " + + std::to_string(ContentLength) + ".\n"); break; } @@ -211,23 +239,25 @@ void clangd::runLanguageServerLoop(std::istream &In, JSONOutput &Out, if (auto Doc = json::parse(JSONRef)) { // Log the formatted message. - Out.log(llvm::formatv(Out.Pretty ? "<-- {0:2}" : "<-- {0}", *Doc)); + log(Context::empty(), + llvm::formatv(Out.Pretty ? "<-- {0:2}\n" : "<-- {0}\n", *Doc)); // Finally, execute the action for this JSON message. if (!Dispatcher.call(*Doc, Out)) - Out.log("JSON dispatch failed!"); + log(Context::empty(), "JSON dispatch failed!\n"); } else { // Parse error. Log the raw message. - Out.log("<-- " + JSONRef); - Out.log(llvm::Twine("JSON parse error: ") + - llvm::toString(Doc.takeError())); + log(Context::empty(), "<-- " + JSONRef + "\n"); + log(Context::empty(), llvm::Twine("JSON parse error: ") + + llvm::toString(Doc.takeError()) + "\n"); } // If we're done, exit the loop. if (IsDone) break; } else { - Out.log("Warning: Missing Content-Length header, or message has zero " - "length."); + log(Context::empty(), + "Warning: Missing Content-Length header, or message has zero " + "length.\n"); } } } |