2018-02-12 19:37:28 +08:00
|
|
|
//===--- SyncAPI.cpp - Sync version of ClangdServer's API --------*- C++-*-===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2018-02-12 19:37:28 +08:00
|
|
|
//
|
2018-08-15 00:03:32 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-02-12 19:37:28 +08:00
|
|
|
#include "SyncAPI.h"
|
2018-11-06 18:55:21 +08:00
|
|
|
#include "index/Index.h"
|
2018-02-12 19:37:28 +08:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
void runAddDocument(ClangdServer &Server, PathRef File,
|
|
|
|
llvm::StringRef Contents, WantDiagnostics WantDiags) {
|
2018-06-13 17:20:41 +08:00
|
|
|
Server.addDocument(File, Contents, WantDiags);
|
2018-03-06 01:28:54 +08:00
|
|
|
if (!Server.blockUntilIdleForTest())
|
|
|
|
llvm_unreachable("not idle after addDocument");
|
|
|
|
}
|
|
|
|
|
2018-02-12 19:37:28 +08:00
|
|
|
namespace {
|
|
|
|
/// A helper that waits for async callbacks to fire and exposes their result in
|
|
|
|
/// the output variable. Intended to be used in the following way:
|
|
|
|
/// T Result;
|
|
|
|
/// someAsyncFunc(Param1, Param2, /*Callback=*/capture(Result));
|
|
|
|
template <typename T> struct CaptureProxy {
|
2019-01-07 23:45:19 +08:00
|
|
|
CaptureProxy(llvm::Optional<T> &Target) : Target(&Target) {
|
2018-02-15 21:15:47 +08:00
|
|
|
assert(!Target.hasValue());
|
|
|
|
}
|
2018-02-12 19:37:28 +08:00
|
|
|
|
|
|
|
CaptureProxy(const CaptureProxy &) = delete;
|
|
|
|
CaptureProxy &operator=(const CaptureProxy &) = delete;
|
|
|
|
// We need move ctor to return a value from the 'capture' helper.
|
|
|
|
CaptureProxy(CaptureProxy &&Other) : Target(Other.Target) {
|
|
|
|
Other.Target = nullptr;
|
|
|
|
}
|
|
|
|
CaptureProxy &operator=(CaptureProxy &&) = delete;
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
operator llvm::unique_function<void(T)>() && {
|
2018-02-12 19:37:28 +08:00
|
|
|
assert(!Future.valid() && "conversion to callback called multiple times");
|
|
|
|
Future = Promise.get_future();
|
2018-02-23 15:54:17 +08:00
|
|
|
return Bind(
|
2018-02-15 23:41:49 +08:00
|
|
|
[](std::promise<std::shared_ptr<T>> Promise, T Value) {
|
|
|
|
Promise.set_value(std::make_shared<T>(std::move(Value)));
|
|
|
|
},
|
|
|
|
std::move(Promise));
|
2018-02-12 19:37:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
~CaptureProxy() {
|
|
|
|
if (!Target)
|
|
|
|
return;
|
|
|
|
assert(Future.valid() && "conversion to callback was not called");
|
2018-02-15 21:15:47 +08:00
|
|
|
assert(!Target->hasValue());
|
2018-02-15 23:41:49 +08:00
|
|
|
Target->emplace(std::move(*Future.get()));
|
2018-02-12 19:37:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Optional<T> *Target;
|
2018-02-15 23:41:49 +08:00
|
|
|
// Using shared_ptr to workaround compilation errors with MSVC.
|
|
|
|
// MSVC only allows default-construcitble and copyable objects as future<>
|
|
|
|
// arguments.
|
|
|
|
std::promise<std::shared_ptr<T>> Promise;
|
|
|
|
std::future<std::shared_ptr<T>> Future;
|
2018-02-12 19:37:28 +08:00
|
|
|
};
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
template <typename T> CaptureProxy<T> capture(llvm::Optional<T> &Target) {
|
2018-02-12 19:37:28 +08:00
|
|
|
return CaptureProxy<T>(Target);
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Expected<CodeCompleteResult>
|
|
|
|
runCodeComplete(ClangdServer &Server, PathRef File, Position Pos,
|
|
|
|
clangd::CodeCompleteOptions Opts) {
|
|
|
|
llvm::Optional<llvm::Expected<CodeCompleteResult>> Result;
|
2018-02-28 01:15:50 +08:00
|
|
|
Server.codeComplete(File, Pos, Opts, capture(Result));
|
2018-02-15 21:15:47 +08:00
|
|
|
return std::move(*Result);
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Expected<SignatureHelp> runSignatureHelp(ClangdServer &Server,
|
|
|
|
PathRef File, Position Pos) {
|
|
|
|
llvm::Optional<llvm::Expected<SignatureHelp>> Result;
|
2018-02-28 01:15:50 +08:00
|
|
|
Server.signatureHelp(File, Pos, capture(Result));
|
2018-02-15 21:15:47 +08:00
|
|
|
return std::move(*Result);
|
|
|
|
}
|
|
|
|
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
llvm::Expected<std::vector<LocatedSymbol>>
|
|
|
|
runLocateSymbolAt(ClangdServer &Server, PathRef File, Position Pos) {
|
|
|
|
llvm::Optional<llvm::Expected<std::vector<LocatedSymbol>>> Result;
|
|
|
|
Server.locateSymbolAt(File, Pos, capture(Result));
|
2018-02-15 21:15:47 +08:00
|
|
|
return std::move(*Result);
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Expected<std::vector<DocumentHighlight>>
|
2018-02-15 21:15:47 +08:00
|
|
|
runFindDocumentHighlights(ClangdServer &Server, PathRef File, Position Pos) {
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Optional<llvm::Expected<std::vector<DocumentHighlight>>> Result;
|
2018-02-15 21:15:47 +08:00
|
|
|
Server.findDocumentHighlights(File, Pos, capture(Result));
|
|
|
|
return std::move(*Result);
|
|
|
|
}
|
|
|
|
|
2019-04-03 15:18:43 +08:00
|
|
|
llvm::Expected<std::vector<TextEdit>> runRename(ClangdServer &Server,
|
|
|
|
PathRef File, Position Pos,
|
|
|
|
llvm::StringRef NewName) {
|
|
|
|
llvm::Optional<llvm::Expected<std::vector<TextEdit>>> Result;
|
2019-07-10 21:44:22 +08:00
|
|
|
Server.rename(File, Pos, NewName, /*WantFormat=*/true, capture(Result));
|
2018-02-15 21:15:47 +08:00
|
|
|
return std::move(*Result);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string runDumpAST(ClangdServer &Server, PathRef File) {
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Optional<std::string> Result;
|
2018-02-15 21:15:47 +08:00
|
|
|
Server.dumpAST(File, capture(Result));
|
|
|
|
return std::move(*Result);
|
2018-02-12 19:37:28 +08:00
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Expected<std::vector<SymbolInformation>>
|
|
|
|
runWorkspaceSymbols(ClangdServer &Server, llvm::StringRef Query, int Limit) {
|
|
|
|
llvm::Optional<llvm::Expected<std::vector<SymbolInformation>>> Result;
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
Server.workspaceSymbols(Query, Limit, capture(Result));
|
|
|
|
return std::move(*Result);
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Expected<std::vector<DocumentSymbol>>
|
|
|
|
runDocumentSymbols(ClangdServer &Server, PathRef File) {
|
|
|
|
llvm::Optional<llvm::Expected<std::vector<DocumentSymbol>>> Result;
|
2018-07-06 03:35:01 +08:00
|
|
|
Server.documentSymbols(File, capture(Result));
|
|
|
|
return std::move(*Result);
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
SymbolSlab runFuzzyFind(const SymbolIndex &Index, llvm::StringRef Query) {
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
FuzzyFindRequest Req;
|
|
|
|
Req.Query = Query;
|
2018-11-06 19:08:17 +08:00
|
|
|
Req.AnyScope = true;
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
return runFuzzyFind(Index, Req);
|
|
|
|
}
|
|
|
|
|
|
|
|
SymbolSlab runFuzzyFind(const SymbolIndex &Index, const FuzzyFindRequest &Req) {
|
|
|
|
SymbolSlab::Builder Builder;
|
|
|
|
Index.fuzzyFind(Req, [&](const Symbol &Sym) { Builder.insert(Sym); });
|
|
|
|
return std::move(Builder).build();
|
|
|
|
}
|
|
|
|
|
2018-11-06 18:55:21 +08:00
|
|
|
RefSlab getRefs(const SymbolIndex &Index, SymbolID ID) {
|
|
|
|
RefsRequest Req;
|
|
|
|
Req.IDs = {ID};
|
|
|
|
RefSlab::Builder Slab;
|
|
|
|
Index.refs(Req, [&](const Ref &S) { Slab.insert(ID, S); });
|
|
|
|
return std::move(Slab).build();
|
|
|
|
}
|
|
|
|
|
2018-02-12 19:37:28 +08:00
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|