diff --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt --- a/clang-tools-extra/clangd/CMakeLists.txt +++ b/clang-tools-extra/clangd/CMakeLists.txt @@ -140,7 +140,6 @@ endif() add_subdirectory(tool) add_subdirectory(indexer) -add_subdirectory(index/dex/dexp) if (LLVM_INCLUDE_BENCHMARKS) add_subdirectory(benchmarks) @@ -160,5 +159,6 @@ if (CLANGD_ENABLE_REMOTE) include(FindGRPC) - add_subdirectory(index/remote) endif() +add_subdirectory(index/remote) +add_subdirectory(index/dex/dexp) diff --git a/clang-tools-extra/clangd/Features.inc.in b/clang-tools-extra/clangd/Features.inc.in --- a/clang-tools-extra/clangd/Features.inc.in +++ b/clang-tools-extra/clangd/Features.inc.in @@ -1 +1,2 @@ #define CLANGD_BUILD_XPC @CLANGD_BUILD_XPC@ +#define CLANGD_ENABLE_REMOTE @CLANGD_ENABLE_REMOTE@ diff --git a/clang-tools-extra/clangd/index/Serialization.h b/clang-tools-extra/clangd/index/Serialization.h --- a/clang-tools-extra/clangd/index/Serialization.h +++ b/clang-tools-extra/clangd/index/Serialization.h @@ -77,6 +77,13 @@ std::string toYAML(const Symbol &); std::string toYAML(const std::pair> &); std::string toYAML(const Relation &); +std::string toYAML(const Ref &); + +// Deserialize a single symbol from YAML. +llvm::Expected symbolFromYAML(StringRef YAML, + llvm::UniqueStringSaver *Strings); +llvm::Expected refFromYAML(StringRef YAML, + llvm::UniqueStringSaver *Strings); // Build an in-memory static index from an index file. // The size should be relatively small, so data can be managed in memory. diff --git a/clang-tools-extra/clangd/index/YAMLSerialization.cpp b/clang-tools-extra/clangd/index/YAMLSerialization.cpp --- a/clang-tools-extra/clangd/index/YAMLSerialization.cpp +++ b/clang-tools-extra/clangd/index/YAMLSerialization.cpp @@ -517,5 +517,40 @@ return Buf; } +std::string toYAML(const Ref &R) { + std::string Buf; + { + llvm::raw_string_ostream OS(Buf); + llvm::yaml::Output Yout(OS); + Ref Reference = R; // copy: Yout<< requires mutability. + Yout << Reference; + } + return Buf; +} + +llvm::Expected +symbolFromYAML(StringRef YAML, llvm::UniqueStringSaver *Strings) { + clangd::Symbol Deserialized; + llvm::yaml::Input YAMLInput(YAML, Strings); + if (YAMLInput.error()) + return llvm::make_error( + llvm::formatv("Unable to deserialize Symbol from YAML: {0}", YAML), + llvm::inconvertibleErrorCode()); + YAMLInput >> Deserialized; + return Deserialized; +} + +llvm::Expected refFromYAML(StringRef YAML, + llvm::UniqueStringSaver *Strings) { + clangd::Ref Deserialized; + llvm::yaml::Input YAMLInput(YAML, Strings); + if (YAMLInput.error()) + return llvm::make_error( + llvm::formatv("Unable to deserialize Symbol from YAML: {0}", YAML), + llvm::inconvertibleErrorCode()); + YAMLInput >> Deserialized; + return Deserialized; +} + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/index/dex/dexp/CMakeLists.txt b/clang-tools-extra/clangd/index/dex/dexp/CMakeLists.txt --- a/clang-tools-extra/clangd/index/dex/dexp/CMakeLists.txt +++ b/clang-tools-extra/clangd/index/dex/dexp/CMakeLists.txt @@ -1,4 +1,5 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../) set(LLVM_LINK_COMPONENTS LineEditor @@ -16,4 +17,5 @@ target_link_libraries(dexp PRIVATE clangDaemon + clangdRemoteIndex ) diff --git a/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp b/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp --- a/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp +++ b/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp @@ -11,9 +11,11 @@ // //===----------------------------------------------------------------------===// +#include "Features.inc" #include "SourceCode.h" #include "index/Serialization.h" #include "index/dex/Dex.h" +#include "index/remote/Client.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -26,8 +28,9 @@ namespace clangd { namespace { -llvm::cl::opt IndexPath(llvm::cl::desc(""), - llvm::cl::Positional, llvm::cl::Required); +llvm::cl::opt IndexLocation( + llvm::cl::desc(""), + llvm::cl::Positional); llvm::cl::opt ExecCommand("c", llvm::cl::desc("Command to execute and then exit")); @@ -38,6 +41,10 @@ tool can be used to evaluate search quality of existing index implementations and manually construct non-trivial test cases. +You can connect to remote index by passing remote:address to dexp. Example: + +$ dexp remote:0.0.0.0:9000 + Type use "help" request to get information about the details. )"; @@ -150,7 +157,7 @@ } Request.AnyScope = Request.Scopes.empty(); // FIXME(kbobyrev): Print symbol final scores to see the distribution. - static const auto OutputFormat = "{0,-4} | {1,-40} | {2,-25}\n"; + static const auto *OutputFormat = "{0,-4} | {1,-40} | {2,-25}\n"; llvm::outs() << llvm::formatv(OutputFormat, "Rank", "Symbol ID", "Symbol Name"); size_t Rank = 0; @@ -316,13 +323,14 @@ {"find", "Search for symbols with fuzzyFind", std::make_unique}, {"lookup", "Dump symbol details by ID or qualified name", std::make_unique}, - {"refs", "Find references by ID or qualified name", - std::make_unique}, + {"refs", "Find references by ID or qualified name", std::make_unique}, {"export", "Export index", std::make_unique}, }; std::unique_ptr openIndex(llvm::StringRef Index) { - return loadIndex(Index, /*UseDex=*/true); + return Index.startswith("remote:") + ? remote::getClient(Index.drop_front(strlen("remote:"))) + : loadIndex(Index, /*UseDex=*/true); } bool runCommand(std::string Request, const SymbolIndex &Index) { @@ -365,9 +373,10 @@ llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); std::unique_ptr Index; - reportTime("Dex build", [&]() { - Index = openIndex(IndexPath); - }); + reportTime(llvm::StringRef(IndexLocation).startswith("remote:") + ? "Remote index client creation" + : "Dex build", + [&]() { Index = openIndex(IndexLocation); }); if (!Index) { llvm::outs() << "Failed to open the index.\n"; diff --git a/clang-tools-extra/clangd/index/remote/CMakeLists.txt b/clang-tools-extra/clangd/index/remote/CMakeLists.txt --- a/clang-tools-extra/clangd/index/remote/CMakeLists.txt +++ b/clang-tools-extra/clangd/index/remote/CMakeLists.txt @@ -1,7 +1,28 @@ -generate_grpc_protos(RemoteIndexProtos "Index.proto") +if (CLANGD_ENABLE_REMOTE) + generate_grpc_protos(RemoteIndexProtos "Index.proto") + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../) -include_directories("${CMAKE_CURRENT_BINARY_DIR}") -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../) + # FIXME(kirillbobyrev): target_compile_definitions is not working with + # add_clang_library for some reason. Is there any way to make this + # target-local? + add_definitions(-DGOOGLE_PROTOBUF_NO_RTTI=1) -add_subdirectory(client) -add_subdirectory(server) + add_clang_library(clangdRemoteIndex + Client.cpp + + LINK_LIBS + RemoteIndexProtos + clangdRemoteMarshalling + + protobuf + grpc++ + clangDaemon + ) + + add_subdirectory(marshalling) + add_subdirectory(server) +else() + # Provides a dummy implementation of clangdRemoteIndex. + add_subdirectory(unimplemented) +endif() diff --git a/clang-tools-extra/clangd/index/remote/Client.h b/clang-tools-extra/clangd/index/remote/Client.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/index/remote/Client.h @@ -0,0 +1,31 @@ +//===--- Client.h - Connect to a remote index via gRPC -----------*- C++-*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_REMOTE_INDEX_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_REMOTE_INDEX_H + +#include "index/Index.h" + +namespace clang { +namespace clangd { +namespace remote { + +/// Returns an SymbolIndex client that passes requests to remote index located +/// at \p Address. The client allows synchronous RPC calls. +/// +/// This method attempts to resolve the address and establish the connection. +/// +/// \returns nullptr if the address is not resolved during the function call or +/// if the project was compiled without Remote Index support. +std::unique_ptr getClient(llvm::StringRef Address); + +} // namespace remote +} // namespace clangd +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_REMOTE_INDEX_H diff --git a/clang-tools-extra/clangd/index/remote/Client.cpp b/clang-tools-extra/clangd/index/remote/Client.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/index/remote/Client.cpp @@ -0,0 +1,105 @@ +//===--- Client.cpp ----------------------------------------------*- C++-*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include + +#include "Client.h" +#include "Index.grpc.pb.h" +#include "Logger.h" +#include "Trace.h" +#include "index/Serialization.h" +#include "marshalling/Marshalling.h" +#include "llvm/Support/YAMLTraits.h" + +namespace clang { +namespace clangd { +namespace remote { +namespace { + +class IndexClient : public clangd::SymbolIndex { + template + using StreamingCall = std::unique_ptr> ( + remote::SymbolIndex::Stub::*)(grpc::ClientContext *, const RequestT &); + + // FIXME(kirillbobyrev): Set deadlines for requests. + template + bool streamRPC(ClangdRequestT Request, + StreamingCall RPCCall, + CallbackT Callback) const { + bool FinalResult = false; + trace::Span Tracer(RequestT::descriptor()->name()); + const auto RPCRequest = toProtobuf(Request); + grpc::ClientContext Context; + auto Reader = (Stub.get()->*RPCCall)(&Context, RPCRequest); + llvm::BumpPtrAllocator Arena; + llvm::UniqueStringSaver Strings(Arena); + ReplyT Reply; + while (Reader->Read(&Reply)) { + if (!Reply.has_stream_result()) { + FinalResult = Reply.final_result(); + continue; + } + auto Sym = fromProtobuf(Reply.stream_result(), &Strings); + if (!Sym) + elog("Received invalid {0}: {1}", ReplyT::descriptor()->name(), + Reply.stream_result().yaml_serialization()); + Callback(*Sym); + } + SPAN_ATTACH(Tracer, "status", Reader->Finish().ok()); + return FinalResult; + } + +public: + IndexClient(std::shared_ptr Channel) + : Stub(remote::SymbolIndex::NewStub(Channel)) {} + + void lookup(const clangd::LookupRequest &Request, + llvm::function_ref Callback) const { + streamRPC( + Request, &remote::SymbolIndex::Stub::Lookup, Callback); + } + + bool + fuzzyFind(const clangd::FuzzyFindRequest &Request, + llvm::function_ref Callback) const { + return streamRPC( + Request, &remote::SymbolIndex::Stub::FuzzyFind, Callback); + } + + bool refs(const clangd::RefsRequest &Request, + llvm::function_ref Callback) const { + return streamRPC( + Request, &remote::SymbolIndex::Stub::Refs, Callback); + } + + // FIXME(kirillbobyrev): Implement this. + void + relations(const clangd::RelationsRequest &, + llvm::function_ref) + const {} + + // IndexClient does not take any space since the data is stored on the server. + size_t estimateMemoryUsage() const { return 0; } + +private: + std::unique_ptr Stub; +}; + +} // namespace + +std::unique_ptr getClient(llvm::StringRef Address) { + const auto Channel = + grpc::CreateChannel(Address.str(), grpc::InsecureChannelCredentials()); + Channel->GetState(true); + return std::unique_ptr(new IndexClient(Channel)); +} + +} // namespace remote +} // namespace clangd +} // namespace clang diff --git a/clang-tools-extra/clangd/index/remote/Index.proto b/clang-tools-extra/clangd/index/remote/Index.proto --- a/clang-tools-extra/clangd/index/remote/Index.proto +++ b/clang-tools-extra/clangd/index/remote/Index.proto @@ -10,10 +10,60 @@ package clang.clangd.remote; -service Index { +service SymbolIndex { rpc Lookup(LookupRequest) returns (stream LookupReply) {} + + rpc FuzzyFind(FuzzyFindRequest) returns (stream FuzzyFindReply) {} + + rpc Refs(RefsRequest) returns (stream RefsReply) {} +} + +message LookupRequest { repeated string ids = 1; } + +// The response is a stream of symbol messages and the terminating message +// indicating the end of stream. +message LookupReply { + oneof kind { + Symbol stream_result = 1; + bool final_result = 2; + } +} + +message FuzzyFindRequest { + string query = 1; + repeated string scopes = 2; + bool any_scope = 3; + uint32 limit = 4; + bool resricted_for_code_completion = 5; + repeated string proximity_paths = 6; + repeated string preferred_types = 7; +} + +// The response is a stream of symbol messages, and one terminating has_more +// message. +message FuzzyFindReply { + oneof kind { + Symbol stream_result = 1; + bool final_result = 2; // HasMore + } } -message LookupRequest { string id = 1; } +message RefsRequest { + repeated string ids = 1; + uint32 filter = 2; + uint32 limit = 3; +} + +// The response is a stream of reference messages, and one terminating has_more +// message. +message RefsReply { + oneof kind { + Ref stream_result = 1; + bool final_result = 2; // HasMore + } +} -message LookupReply { string symbol_yaml = 1; } +// FIXME(kirillbobyrev): Properly serialize symbols and refs instead of passing +// YAML. +message Ref { string yaml_serialization = 1; } +message Symbol { string yaml_serialization = 1; } diff --git a/clang-tools-extra/clangd/index/remote/client/CMakeLists.txt b/clang-tools-extra/clangd/index/remote/client/CMakeLists.txt deleted file mode 100644 --- a/clang-tools-extra/clangd/index/remote/client/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -set(LLVM_LINK_COMPONENTS - LineEditor - Support - ) -add_clang_executable(clangd-index-client - Client.cpp - ) -target_compile_definitions(clangd-index-client PRIVATE -DGOOGLE_PROTOBUF_NO_RTTI=1) -clang_target_link_libraries(clangd-index-client - PRIVATE - clangDaemon - ) -target_link_libraries(clangd-index-client - PRIVATE - RemoteIndexProtos - - protobuf - grpc++ - ) diff --git a/clang-tools-extra/clangd/index/remote/client/Client.cpp b/clang-tools-extra/clangd/index/remote/client/Client.cpp deleted file mode 100644 --- a/clang-tools-extra/clangd/index/remote/client/Client.cpp +++ /dev/null @@ -1,91 +0,0 @@ -//===--- Client.cpp - Remote Index Client -----------------------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// This file implements a simple interactive tool which can be used to manually -// evaluate symbol search quality of Clangd index. -// -//===----------------------------------------------------------------------===// - -#include "SourceCode.h" -#include "index/Serialization.h" -#include "index/dex/Dex.h" -#include "llvm/ADT/ScopeExit.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/LineEditor/LineEditor.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Signals.h" - -#include "grpcpp/grpcpp.h" - -#include "Index.grpc.pb.h" - -namespace clang { -namespace clangd { -namespace { - -llvm::cl::opt - ServerAddress("server-address", - llvm::cl::desc("Address of remote index server to use."), - llvm::cl::init("0.0.0.0:50051")); - -static const std::string Overview = R"( -This is an **experimental** interactive tool to process user-provided search -queries over given symbol collection obtained via clangd-indexer with the help -of remote index server. The client will connect to remote index server and pass -it lookup queries. -)"; - -class RemoteIndexClient { -public: - RemoteIndexClient(std::shared_ptr Channel) - : Stub(remote::Index::NewStub(Channel)) {} - - void lookup(llvm::StringRef ID) { - llvm::outs() << "Lookup of symbol with ID " << ID << '\n'; - remote::LookupRequest Proto; - Proto.set_id(ID.str()); - - grpc::ClientContext Context; - remote::LookupReply Reply; - std::unique_ptr> Reader( - Stub->Lookup(&Context, Proto)); - while (Reader->Read(&Reply)) { - llvm::outs() << Reply.symbol_yaml(); - } - grpc::Status Status = Reader->Finish(); - if (Status.ok()) { - llvm::outs() << "lookupRequest rpc succeeded.\n"; - } else { - llvm::outs() << "lookupRequest rpc failed.\n"; - } - } - -private: - std::unique_ptr Stub; -}; - -} // namespace -} // namespace clangd -} // namespace clang - -int main(int argc, const char *argv[]) { - using namespace clang::clangd; - - llvm::cl::ParseCommandLineOptions(argc, argv, Overview); - llvm::cl::ResetCommandLineParser(); // We reuse it for REPL commands. - llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); - - RemoteIndexClient IndexClient( - grpc::CreateChannel(ServerAddress, grpc::InsecureChannelCredentials())); - - llvm::LineEditor LE("remote-index-client"); - while (llvm::Optional Request = LE.readLine()) - IndexClient.lookup(std::move(*Request)); -} diff --git a/clang-tools-extra/clangd/index/remote/marshalling/CMakeLists.txt b/clang-tools-extra/clangd/index/remote/marshalling/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/index/remote/marshalling/CMakeLists.txt @@ -0,0 +1,9 @@ +add_clang_library(clangdRemoteMarshalling + Marshalling.cpp + + LINK_LIBS + RemoteIndexProtos + + protobuf + clangDaemon + ) diff --git a/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.h b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.h @@ -0,0 +1,41 @@ +//===--- Marshalling.h -------------------------------------------*- C++-*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Transformations between native Clangd types and Protobuf-generated classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_REMOTE_MARSHALLING_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_REMOTE_MARSHALLING_H + +#include "Index.grpc.pb.h" +#include "index/Index.h" +#include "llvm/Support/StringSaver.h" + +namespace clang { +namespace clangd { +namespace remote { + +clangd::FuzzyFindRequest fromProtobuf(const FuzzyFindRequest *Request); +llvm::Optional fromProtobuf(const Symbol &Message, + llvm::UniqueStringSaver *Strings); +llvm::Optional fromProtobuf(const Ref &Message, + llvm::UniqueStringSaver *Strings); + +LookupRequest toProtobuf(const clangd::LookupRequest &From); +FuzzyFindRequest toProtobuf(const clangd::FuzzyFindRequest &From); +RefsRequest toProtobuf(const clangd::RefsRequest &From); + +Ref toProtobuf(const clangd::Ref &From); +Symbol toProtobuf(const clangd::Symbol &From); + +} // namespace remote +} // namespace clangd +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_REMOTE_MARSHALLING_H diff --git a/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp @@ -0,0 +1,99 @@ +//===--- Marshalling.cpp -----------------------------------------*- C++-*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "Marshalling.h" +#include "Logger.h" +#include "index/Serialization.h" + +namespace clang { +namespace clangd { +namespace remote { + +clangd::FuzzyFindRequest fromProtobuf(const FuzzyFindRequest *Request) { + clangd::FuzzyFindRequest Result; + Result.Query = Request->query(); + for (const auto &Scope : Request->scopes()) + Result.Scopes.push_back(Scope); + Result.AnyScope = Request->any_scope(); + if (Request->limit()) + Result.Limit = Request->limit(); + Result.RestrictForCodeCompletion = Request->resricted_for_code_completion(); + for (const auto &Path : Request->proximity_paths()) + Result.ProximityPaths.push_back(Path); + for (const auto &Type : Request->preferred_types()) + Result.ProximityPaths.push_back(Type); + return Result; +} + +llvm::Optional fromProtobuf(const Symbol &Message, + llvm::UniqueStringSaver *Strings) { + auto Result = symbolFromYAML(Message.yaml_serialization(), Strings); + if (!Result) { + elog("Cannot convert Symbol from Protobuf: {}", Result.takeError()); + return llvm::None; + } + return *Result; +} +llvm::Optional fromProtobuf(const Ref &Message, + llvm::UniqueStringSaver *Strings) { + auto Result = refFromYAML(Message.yaml_serialization(), Strings); + if (!Result) { + elog("Cannot convert Ref from Protobuf: {}", Result.takeError()); + return llvm::None; + } + return *Result; +} + +LookupRequest toProtobuf(const clangd::LookupRequest &From) { + LookupRequest RPCRequest; + for (const auto &SymbolID : From.IDs) + RPCRequest.add_ids(SymbolID.str()); + return RPCRequest; +} + +FuzzyFindRequest toProtobuf(const clangd::FuzzyFindRequest &From) { + FuzzyFindRequest RPCRequest; + RPCRequest.set_query(From.Query); + for (const auto &Scope : From.Scopes) + RPCRequest.add_scopes(Scope); + RPCRequest.set_any_scope(From.AnyScope); + if (From.Limit) + RPCRequest.set_limit(*From.Limit); + RPCRequest.set_resricted_for_code_completion(From.RestrictForCodeCompletion); + for (const auto &Path : From.ProximityPaths) + RPCRequest.add_proximity_paths(Path); + for (const auto &Type : From.PreferredTypes) + RPCRequest.add_preferred_types(Type); + return RPCRequest; +} + +RefsRequest toProtobuf(const clangd::RefsRequest &From) { + RefsRequest RPCRequest; + for (const auto &ID : From.IDs) + RPCRequest.add_ids(ID.str()); + RPCRequest.set_filter(static_cast(From.Filter)); + if (From.Limit) + RPCRequest.set_limit(*From.Limit); + return RPCRequest; +} + +Symbol toProtobuf(const clangd::Symbol &From) { + Symbol Result; + Result.set_yaml_serialization(toYAML(From)); + return Result; +} + +Ref toProtobuf(const clangd::Ref &From) { + Ref Result; + Result.set_yaml_serialization(toYAML(From)); + return Result; +} + +} // namespace remote +} // namespace clangd +} // namespace clang diff --git a/clang-tools-extra/clangd/index/remote/server/CMakeLists.txt b/clang-tools-extra/clangd/index/remote/server/CMakeLists.txt --- a/clang-tools-extra/clangd/index/remote/server/CMakeLists.txt +++ b/clang-tools-extra/clangd/index/remote/server/CMakeLists.txt @@ -5,7 +5,7 @@ add_clang_executable(clangd-index-server Server.cpp ) -target_compile_definitions(clangd-index-server PRIVATE -DGOOGLE_PROTOBUF_NO_RTTI=1) +target_compile_definitions(clangd-index-server PRIVATE -D GOOGLE_PROTOBUF_NO_RTTI=1) clang_target_link_libraries(clangd-index-server PRIVATE clangDaemon @@ -14,7 +14,5 @@ PRIVATE RemoteIndexProtos - protobuf - grpc++ - clangDaemon + clangdRemoteMarshalling ) diff --git a/clang-tools-extra/clangd/index/remote/server/Server.cpp b/clang-tools-extra/clangd/index/remote/server/Server.cpp --- a/clang-tools-extra/clangd/index/remote/server/Server.cpp +++ b/clang-tools-extra/clangd/index/remote/server/Server.cpp @@ -8,6 +8,7 @@ #include "index/Index.h" #include "index/Serialization.h" +#include "index/remote/marshalling/Marshalling.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/LineEditor/LineEditor.h" @@ -16,13 +17,14 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" -#include "grpcpp/grpcpp.h" -#include "grpcpp/health_check_service_interface.h" +#include +#include #include "Index.grpc.pb.h" namespace clang { namespace clangd { +namespace remote { namespace { static const std::string Overview = R"( @@ -33,42 +35,80 @@ llvm::cl::opt IndexPath(llvm::cl::desc(""), llvm::cl::Positional, llvm::cl::Required); -llvm::cl::opt ServerAddress("server-address", - llvm::cl::init("0.0.0.0:50051")); +llvm::cl::opt ServerAddress( + "server-address", llvm::cl::init("0.0.0.0:50051"), + llvm::cl::desc("Address of the invoked server. Defaults to 0.0.0.0:50051")); -std::unique_ptr openIndex(llvm::StringRef Index) { +std::unique_ptr openIndex(llvm::StringRef Index) { return loadIndex(Index, /*UseIndex=*/true); } -class RemoteIndexServer final : public remote::Index::Service { +class RemoteIndexServer final : public SymbolIndex::Service { public: - RemoteIndexServer(std::unique_ptr Index) + RemoteIndexServer(std::unique_ptr Index) : Index(std::move(Index)) {} private: grpc::Status Lookup(grpc::ServerContext *Context, - const remote::LookupRequest *Request, - grpc::ServerWriter *Reply) override { - llvm::outs() << "Lookup of symbol with ID " << Request->id() << '\n'; - LookupRequest Req; - auto SID = SymbolID::fromStr(Request->id()); - if (!SID) { - llvm::outs() << llvm::toString(SID.takeError()) << "\n"; - return grpc::Status::CANCELLED; + const LookupRequest *Request, + grpc::ServerWriter *Reply) override { + clangd::LookupRequest Req; + for (const auto &ID : Request->ids()) { + auto SID = SymbolID::fromStr(StringRef(ID)); + if (!SID) + return grpc::Status::CANCELLED; + Req.IDs.insert(*SID); } - Req.IDs.insert(*SID); - Index->lookup(Req, [&](const Symbol &Sym) { - remote::LookupReply NextSymbol; - NextSymbol.set_symbol_yaml(toYAML(Sym)); - Reply->Write(NextSymbol); + Index->lookup(Req, [&](const clangd::Symbol &Sym) { + LookupReply NextMessage; + *NextMessage.mutable_stream_result() = toProtobuf(Sym); + Reply->Write(NextMessage); }); + LookupReply LastMessage; + LastMessage.set_final_result(true); + Reply->Write(LastMessage); return grpc::Status::OK; } - std::unique_ptr Index; + grpc::Status FuzzyFind(grpc::ServerContext *Context, + const FuzzyFindRequest *Request, + grpc::ServerWriter *Reply) override { + const auto Req = fromProtobuf(Request); + bool HasMore = Index->fuzzyFind(Req, [&](const clangd::Symbol &Sym) { + FuzzyFindReply NextMessage; + *NextMessage.mutable_stream_result() = toProtobuf(Sym); + Reply->Write(NextMessage); + }); + FuzzyFindReply LastMessage; + LastMessage.set_final_result(HasMore); + Reply->Write(LastMessage); + return grpc::Status::OK; + } + + grpc::Status Refs(grpc::ServerContext *Context, const RefsRequest *Request, + grpc::ServerWriter *Reply) override { + clangd::RefsRequest Req; + for (const auto &ID : Request->ids()) { + auto SID = SymbolID::fromStr(StringRef(ID)); + if (!SID) + return grpc::Status::CANCELLED; + Req.IDs.insert(*SID); + } + bool HasMore = Index->refs(Req, [&](const clangd::Ref &Reference) { + RefsReply NextMessage; + *NextMessage.mutable_stream_result() = toProtobuf(Reference); + Reply->Write(NextMessage); + }); + RefsReply LastMessage; + LastMessage.set_final_result(HasMore); + Reply->Write(LastMessage); + return grpc::Status::OK; + } + + std::unique_ptr Index; }; -void runServer(std::unique_ptr Index, +void runServer(std::unique_ptr Index, const std::string &ServerAddress) { RemoteIndexServer Service(std::move(Index)); @@ -83,15 +123,16 @@ } } // namespace +} // namespace remote } // namespace clangd } // namespace clang int main(int argc, char *argv[]) { - using namespace clang::clangd; - llvm::cl::ParseCommandLineOptions(argc, argv, clang::clangd::Overview); + using namespace clang::clangd::remote; + llvm::cl::ParseCommandLineOptions(argc, argv, Overview); llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); - std::unique_ptr Index = openIndex(IndexPath); + std::unique_ptr Index = openIndex(IndexPath); if (!Index) { llvm::outs() << "Failed to open the index.\n"; diff --git a/clang-tools-extra/clangd/index/remote/unimplemented/CMakeLists.txt b/clang-tools-extra/clangd/index/remote/unimplemented/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/index/remote/unimplemented/CMakeLists.txt @@ -0,0 +1,10 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../) +# When compiled without Remote Index support, the real implementation index +# client is not present. Users will get a notification about this when trying +# to connect to remote index server instance. +add_clang_library(clangdRemoteIndex + UnimplementedClient.cpp + + LINK_LIBS + clangDaemon + ) diff --git a/clang-tools-extra/clangd/index/remote/unimplemented/UnimplementedClient.cpp b/clang-tools-extra/clangd/index/remote/unimplemented/UnimplementedClient.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/index/remote/unimplemented/UnimplementedClient.cpp @@ -0,0 +1,23 @@ +//===--- UnimplementedClient.cpp ---------------------------------*- C++-*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "Logger.h" +#include "index/remote/Client.h" + +namespace clang { +namespace clangd { +namespace remote { + +std::unique_ptr getClient(llvm::StringRef Address) { + elog("Can't create SymbolIndex client without Remote Index support."); + return nullptr; +} + +} // namespace remote +} // namespace clangd +} // namespace clang