Skip to content

Commit 8e21f79

Browse files
committed
Merge commit '715dc556b782f718ce1815aaf5c58626f5fe839c' into ww07-08_oldPM
2 parents 4a14de7 + 715dc55 commit 8e21f79

File tree

329 files changed

+12131
-9697
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

329 files changed

+12131
-9697
lines changed

clang-tools-extra/clangd/ClangdLSPServer.cpp

Lines changed: 152 additions & 186 deletions
Large diffs are not rendered by default.

clang-tools-extra/clangd/ClangdLSPServer.h

Lines changed: 8 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "Features.inc"
1515
#include "FindSymbols.h"
1616
#include "GlobalCompilationDatabase.h"
17+
#include "LSPBinder.h"
1718
#include "Protocol.h"
1819
#include "Transport.h"
1920
#include "support/Context.h"
@@ -90,8 +91,8 @@ class ClangdLSPServer : private ClangdServer::Callbacks {
9091
// Calls have signature void(const Params&, Callback<Response>).
9192
void onInitialize(const InitializeParams &, Callback<llvm::json::Value>);
9293
void onInitialized(const InitializedParams &);
93-
void onShutdown(Callback<std::nullptr_t>);
94-
void onSync(Callback<std::nullptr_t>);
94+
void onShutdown(const NoParams &, Callback<std::nullptr_t>);
95+
void onSync(const NoParams &, Callback<std::nullptr_t>);
9596
void onDocumentDidOpen(const DidOpenTextDocumentParams &);
9697
void onDocumentDidChange(const DidChangeTextDocumentParams &);
9798
void onDocumentDidClose(const DidCloseTextDocumentParams &);
@@ -157,11 +158,7 @@ class ClangdLSPServer : private ClangdServer::Callbacks {
157158
Callback<SemanticTokensOrDelta>);
158159
/// This is a clangd extension. Provides a json tree representing memory usage
159160
/// hierarchy.
160-
void onMemoryUsage(Callback<MemoryTree>);
161-
162-
llvm::StringMap<llvm::unique_function<void(const llvm::json::Value &,
163-
Callback<llvm::json::Value>)>>
164-
CommandHandlers;
161+
void onMemoryUsage(const NoParams &, Callback<MemoryTree>);
165162
void onCommand(const ExecuteCommandParams &, Callback<llvm::json::Value>);
166163

167164
/// Implement commands.
@@ -171,6 +168,7 @@ class ClangdLSPServer : private ClangdServer::Callbacks {
171168
void applyEdit(WorkspaceEdit WE, llvm::json::Value Success,
172169
Callback<llvm::json::Value> Reply);
173170

171+
void bindMethods(LSPBinder &);
174172
std::vector<Fix> getFixes(StringRef File, const clangd::Diagnostic &D);
175173

176174
/// Checks if completion request should be ignored. We need this due to the
@@ -229,29 +227,6 @@ class ClangdLSPServer : private ClangdServer::Callbacks {
229227
std::unique_ptr<MessageHandler> MsgHandler;
230228
std::mutex TranspWriter;
231229

232-
template <typename T>
233-
static Expected<T> parse(const llvm::json::Value &Raw,
234-
llvm::StringRef PayloadName,
235-
llvm::StringRef PayloadKind) {
236-
T Result;
237-
llvm::json::Path::Root Root;
238-
if (!fromJSON(Raw, Result, Root)) {
239-
elog("Failed to decode {0} {1}: {2}", PayloadName, PayloadKind,
240-
Root.getError());
241-
// Dump the relevant parts of the broken message.
242-
std::string Context;
243-
llvm::raw_string_ostream OS(Context);
244-
Root.printErrorContext(Raw, OS);
245-
vlog("{0}", OS.str());
246-
// Report the error (e.g. to the client).
247-
return llvm::make_error<LSPError>(
248-
llvm::formatv("failed to decode {0} {1}: {2}", PayloadName,
249-
PayloadKind, fmt_consume(Root.getError())),
250-
ErrorCode::InvalidParams);
251-
}
252-
return std::move(Result);
253-
}
254-
255230
template <typename Response>
256231
void call(StringRef Method, llvm::json::Value Params, Callback<Response> CB) {
257232
// Wrap the callback with LSP conversion and error-handling.
@@ -261,7 +236,7 @@ class ClangdLSPServer : private ClangdServer::Callbacks {
261236
llvm::Expected<llvm::json::Value> RawResponse) mutable {
262237
if (!RawResponse)
263238
return CB(RawResponse.takeError());
264-
CB(parse<Response>(*RawResponse, Method, "response"));
239+
CB(LSPBinder::parse<Response>(*RawResponse, Method, "response"));
265240
};
266241
callRaw(Method, std::move(Params), std::move(HandleReply));
267242
}
@@ -274,19 +249,8 @@ class ClangdLSPServer : private ClangdServer::Callbacks {
274249
Params.value = std::move(Value);
275250
notify("$/progress", Params);
276251
}
277-
template <typename Param, typename Result>
278-
void bindCommand(llvm::StringLiteral Method,
279-
void (ClangdLSPServer::*Handler)(const Param &,
280-
Callback<Result>)) {
281-
CommandHandlers[Method] = [Method, Handler,
282-
this](llvm::json::Value RawParams,
283-
Callback<Result> Reply) {
284-
auto P = parse<Param>(RawParams, Method, "command");
285-
if (!P)
286-
return Reply(P.takeError());
287-
(this->*Handler)(*P, std::move(Reply));
288-
};
289-
}
252+
253+
LSPBinder::RawHandlers Handlers;
290254

291255
const ThreadsafeFS &TFS;
292256
/// Options used for diagnostics.

clang-tools-extra/clangd/LSPBinder.h

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
//===--- LSPBinder.h - Tables of LSP handlers --------------------*- 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+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_LSPBINDER_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_LSPBINDER_H
11+
12+
#include "Protocol.h"
13+
#include "support/Function.h"
14+
#include "support/Logger.h"
15+
#include "llvm/ADT/FunctionExtras.h"
16+
#include "llvm/ADT/StringMap.h"
17+
#include "llvm/Support/JSON.h"
18+
19+
namespace clang {
20+
namespace clangd {
21+
22+
/// LSPBinder collects a table of functions that handle LSP calls.
23+
///
24+
/// It translates a handler method's signature, e.g.
25+
/// void codeComplete(CompletionParams, Callback<CompletionList>)
26+
/// into a wrapper with a generic signature:
27+
/// void(json::Value, Callback<json::Value>)
28+
/// The wrapper takes care of parsing/serializing responses.
29+
///
30+
/// Incoming calls can be methods, notifications, or commands - all are similar.
31+
///
32+
/// FIXME: this should also take responsibility for wrapping *outgoing* calls,
33+
/// replacing the typed ClangdLSPServer::call<> etc.
34+
class LSPBinder {
35+
public:
36+
using JSON = llvm::json::Value;
37+
38+
struct RawHandlers {
39+
template <typename HandlerT>
40+
using HandlerMap = llvm::StringMap<llvm::unique_function<HandlerT>>;
41+
42+
HandlerMap<void(JSON)> NotificationHandlers;
43+
HandlerMap<void(JSON, Callback<JSON>)> MethodHandlers;
44+
HandlerMap<void(JSON, Callback<JSON>)> CommandHandlers;
45+
};
46+
47+
LSPBinder(RawHandlers &Raw) : Raw(Raw) {}
48+
49+
/// Bind a handler for an LSP method.
50+
/// e.g. Bind.method("peek", this, &ThisModule::peek);
51+
/// Handler should be e.g. void peek(const PeekParams&, Callback<PeekResult>);
52+
/// PeekParams must be JSON-parseable and PeekResult must be serializable.
53+
template <typename Param, typename Result, typename ThisT>
54+
void method(llvm::StringLiteral Method, ThisT *This,
55+
void (ThisT::*Handler)(const Param &, Callback<Result>));
56+
57+
/// Bind a handler for an LSP notification.
58+
/// e.g. Bind.notification("poke", this, &ThisModule::poke);
59+
/// Handler should be e.g. void poke(const PokeParams&);
60+
/// PokeParams must be JSON-parseable.
61+
template <typename Param, typename ThisT>
62+
void notification(llvm::StringLiteral Method, ThisT *This,
63+
void (ThisT::*Handler)(const Param &));
64+
65+
/// Bind a handler for an LSP command.
66+
/// e.g. Bind.command("load", this, &ThisModule::load);
67+
/// Handler should be e.g. void load(const LoadParams&, Callback<LoadResult>);
68+
/// LoadParams must be JSON-parseable and LoadResult must be serializable.
69+
template <typename Param, typename Result, typename ThisT>
70+
void command(llvm::StringLiteral Command, ThisT *This,
71+
void (ThisT::*Handler)(const Param &, Callback<Result>));
72+
73+
// FIXME: remove usage from ClangdLSPServer and make this private.
74+
template <typename T>
75+
static llvm::Expected<T> parse(const llvm::json::Value &Raw,
76+
llvm::StringRef PayloadName,
77+
llvm::StringRef PayloadKind);
78+
79+
private:
80+
RawHandlers &Raw;
81+
};
82+
83+
template <typename T>
84+
llvm::Expected<T> LSPBinder::parse(const llvm::json::Value &Raw,
85+
llvm::StringRef PayloadName,
86+
llvm::StringRef PayloadKind) {
87+
T Result;
88+
llvm::json::Path::Root Root;
89+
if (!fromJSON(Raw, Result, Root)) {
90+
elog("Failed to decode {0} {1}: {2}", PayloadName, PayloadKind,
91+
Root.getError());
92+
// Dump the relevant parts of the broken message.
93+
std::string Context;
94+
llvm::raw_string_ostream OS(Context);
95+
Root.printErrorContext(Raw, OS);
96+
vlog("{0}", OS.str());
97+
// Report the error (e.g. to the client).
98+
return llvm::make_error<LSPError>(
99+
llvm::formatv("failed to decode {0} {1}: {2}", PayloadName, PayloadKind,
100+
fmt_consume(Root.getError())),
101+
ErrorCode::InvalidParams);
102+
}
103+
return std::move(Result);
104+
}
105+
106+
template <typename Param, typename Result, typename ThisT>
107+
void LSPBinder::method(llvm::StringLiteral Method, ThisT *This,
108+
void (ThisT::*Handler)(const Param &,
109+
Callback<Result>)) {
110+
Raw.MethodHandlers[Method] = [Method, Handler, This](JSON RawParams,
111+
Callback<JSON> Reply) {
112+
auto P = LSPBinder::parse<Param>(RawParams, Method, "request");
113+
if (!P)
114+
return Reply(P.takeError());
115+
(This->*Handler)(*P, std::move(Reply));
116+
};
117+
}
118+
119+
template <typename Param, typename ThisT>
120+
void LSPBinder::notification(llvm::StringLiteral Method, ThisT *This,
121+
void (ThisT::*Handler)(const Param &)) {
122+
Raw.NotificationHandlers[Method] = [Method, Handler, This](JSON RawParams) {
123+
llvm::Expected<Param> P =
124+
LSPBinder::parse<Param>(RawParams, Method, "request");
125+
if (!P)
126+
return llvm::consumeError(P.takeError());
127+
(This->*Handler)(*P);
128+
};
129+
}
130+
131+
template <typename Param, typename Result, typename ThisT>
132+
void LSPBinder::command(llvm::StringLiteral Method, ThisT *This,
133+
void (ThisT::*Handler)(const Param &,
134+
Callback<Result>)) {
135+
Raw.CommandHandlers[Method] = [Method, Handler, This](JSON RawParams,
136+
Callback<JSON> Reply) {
137+
auto P = LSPBinder::parse<Param>(RawParams, Method, "command");
138+
if (!P)
139+
return Reply(P.takeError());
140+
(This->*Handler)(*P, std::move(Reply));
141+
};
142+
}
143+
144+
} // namespace clangd
145+
} // namespace clang
146+
147+
#endif

clang-tools-extra/clangd/Module.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_MODULE_H
22
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_MODULE_H
33

4+
#include "LSPBinder.h"
5+
#include "Protocol.h"
46
#include "llvm/ADT/StringRef.h"
7+
#include "llvm/Support/JSON.h"
58
#include <memory>
69
#include <vector>
710

@@ -10,14 +13,11 @@ namespace clangd {
1013

1114
/// A Module contributes a vertical feature to clangd.
1215
///
13-
/// FIXME: Extend this with LSP bindings to support reading/updating
14-
/// capabilities and implementing LSP endpoints.
16+
/// FIXME: Extend this to support outgoing LSP calls.
1517
///
1618
/// The lifetime of a module is roughly:
1719
/// - modules are created before the LSP server, in ClangdMain.cpp
1820
/// - these modules are then passed to ClangdLSPServer and ClangdServer
19-
/// FIXME: LSP bindings should be registered at ClangdLSPServer
20-
/// initialization.
2121
/// - module hooks can be called at this point.
2222
/// FIXME: We should make some server facilities like TUScheduler and index
2323
/// available to those modules after ClangdServer is initalized.
@@ -30,6 +30,17 @@ namespace clangd {
3030
class Module {
3131
public:
3232
virtual ~Module() = default;
33+
34+
/// Called by the server to connect this module to LSP.
35+
/// The module should register the methods/notifications/commands it handles,
36+
/// and update the server capabilities to advertise them.
37+
///
38+
/// This is only called if the module is running in ClangdLSPServer!
39+
/// Modules with a public interface should satisfy it without LSP bindings.
40+
// FIXME: ClientCaps should be a raw json::Object here.
41+
virtual void initializeLSP(LSPBinder &Bind,
42+
const ClientCapabilities &ClientCaps,
43+
llvm::json::Object &ServerCaps) {}
3344
};
3445

3546
class ModuleSet {

clang-tools-extra/clangd/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ add_unittest(ClangdUnitTests ClangdTests
7070
IndexTests.cpp
7171
JSONTransportTests.cpp
7272
LoggerTests.cpp
73+
LSPBinderTests.cpp
7374
LSPClient.cpp
7475
ModulesTests.cpp
7576
ParsedASTTests.cpp

clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,29 @@ TEST_F(LSPTest, CDBConfigIntegration) {
221221
DiagMessage("Use of undeclared identifier 'BAR'"))));
222222
}
223223

224+
TEST_F(LSPTest, ModulesTest) {
225+
class MathModule : public Module {
226+
void initializeLSP(LSPBinder &Bind, const ClientCapabilities &ClientCaps,
227+
llvm::json::Object &ServerCaps) override {
228+
Bind.notification("add", this, &MathModule::add);
229+
Bind.method("get", this, &MathModule::get);
230+
}
231+
232+
void add(const int &X) { Value += X; }
233+
void get(const std::nullptr_t &, Callback<int> Reply) { Reply(Value); }
234+
int Value = 0;
235+
};
236+
std::vector<std::unique_ptr<Module>> Mods;
237+
Mods.push_back(std::make_unique<MathModule>());
238+
ModuleSet ModSet(std::move(Mods));
239+
Opts.Modules = &ModSet;
240+
241+
auto &Client = start();
242+
Client.notify("add", 2);
243+
Client.notify("add", 8);
244+
EXPECT_EQ(10, Client.call("get", nullptr).takeValue());
245+
}
246+
224247
} // namespace
225248
} // namespace clangd
226249
} // namespace clang

0 commit comments

Comments
 (0)