forked from OSchip/llvm-project
[clangd] Don't send invalid messages from remote index
Summary: Remote server should not send messages that are invalid and will cause problems on the client side. The client should not be affected by server's failures whenever possible. Also add more error messages and logs. Reviewers: sammccall Reviewed By: sammccall Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D83826
This commit is contained in:
parent
1890a65ca1
commit
eef162c330
|
@ -29,16 +29,6 @@ class IndexClient : public clangd::SymbolIndex {
|
||||||
using StreamingCall = std::unique_ptr<grpc::ClientReader<ReplyT>> (
|
using StreamingCall = std::unique_ptr<grpc::ClientReader<ReplyT>> (
|
||||||
remote::SymbolIndex::Stub::*)(grpc::ClientContext *, const RequestT &);
|
remote::SymbolIndex::Stub::*)(grpc::ClientContext *, const RequestT &);
|
||||||
|
|
||||||
template <typename ClangdRequestT, typename RequestT>
|
|
||||||
RequestT serializeRequest(ClangdRequestT Request) const {
|
|
||||||
return toProtobuf(Request);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
FuzzyFindRequest serializeRequest(clangd::FuzzyFindRequest Request) const {
|
|
||||||
return toProtobuf(Request, ProjectRoot);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename RequestT, typename ReplyT, typename ClangdRequestT,
|
template <typename RequestT, typename ReplyT, typename ClangdRequestT,
|
||||||
typename CallbackT>
|
typename CallbackT>
|
||||||
bool streamRPC(ClangdRequestT Request,
|
bool streamRPC(ClangdRequestT Request,
|
||||||
|
@ -46,24 +36,23 @@ class IndexClient : public clangd::SymbolIndex {
|
||||||
CallbackT Callback) const {
|
CallbackT Callback) const {
|
||||||
bool FinalResult = false;
|
bool FinalResult = false;
|
||||||
trace::Span Tracer(RequestT::descriptor()->name());
|
trace::Span Tracer(RequestT::descriptor()->name());
|
||||||
const auto RPCRequest = serializeRequest<ClangdRequestT, RequestT>(Request);
|
const auto RPCRequest = ProtobufMarshaller->toProtobuf(Request);
|
||||||
grpc::ClientContext Context;
|
grpc::ClientContext Context;
|
||||||
std::chrono::system_clock::time_point Deadline =
|
std::chrono::system_clock::time_point Deadline =
|
||||||
std::chrono::system_clock::now() + DeadlineWaitingTime;
|
std::chrono::system_clock::now() + DeadlineWaitingTime;
|
||||||
Context.set_deadline(Deadline);
|
Context.set_deadline(Deadline);
|
||||||
auto Reader = (Stub.get()->*RPCCall)(&Context, RPCRequest);
|
auto Reader = (Stub.get()->*RPCCall)(&Context, RPCRequest);
|
||||||
llvm::BumpPtrAllocator Arena;
|
|
||||||
llvm::UniqueStringSaver Strings(Arena);
|
|
||||||
ReplyT Reply;
|
ReplyT Reply;
|
||||||
while (Reader->Read(&Reply)) {
|
while (Reader->Read(&Reply)) {
|
||||||
if (!Reply.has_stream_result()) {
|
if (!Reply.has_stream_result()) {
|
||||||
FinalResult = Reply.final_result();
|
FinalResult = Reply.final_result();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto Response =
|
auto Response = ProtobufMarshaller->fromProtobuf(Reply.stream_result());
|
||||||
fromProtobuf(Reply.stream_result(), &Strings, ProjectRoot);
|
if (!Response) {
|
||||||
if (!Response)
|
|
||||||
elog("Received invalid {0}", ReplyT::descriptor()->name());
|
elog("Received invalid {0}", ReplyT::descriptor()->name());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Callback(*Response);
|
Callback(*Response);
|
||||||
}
|
}
|
||||||
SPAN_ATTACH(Tracer, "status", Reader->Finish().ok());
|
SPAN_ATTACH(Tracer, "status", Reader->Finish().ok());
|
||||||
|
@ -74,7 +63,9 @@ public:
|
||||||
IndexClient(
|
IndexClient(
|
||||||
std::shared_ptr<grpc::Channel> Channel, llvm::StringRef ProjectRoot,
|
std::shared_ptr<grpc::Channel> Channel, llvm::StringRef ProjectRoot,
|
||||||
std::chrono::milliseconds DeadlineTime = std::chrono::milliseconds(1000))
|
std::chrono::milliseconds DeadlineTime = std::chrono::milliseconds(1000))
|
||||||
: Stub(remote::SymbolIndex::NewStub(Channel)), ProjectRoot(ProjectRoot),
|
: Stub(remote::SymbolIndex::NewStub(Channel)),
|
||||||
|
ProtobufMarshaller(new Marshaller(/*RemoteIndexRoot=*/"",
|
||||||
|
/*LocalIndexRoot=*/ProjectRoot)),
|
||||||
DeadlineWaitingTime(DeadlineTime) {}
|
DeadlineWaitingTime(DeadlineTime) {}
|
||||||
|
|
||||||
void lookup(const clangd::LookupRequest &Request,
|
void lookup(const clangd::LookupRequest &Request,
|
||||||
|
@ -105,7 +96,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<remote::SymbolIndex::Stub> Stub;
|
std::unique_ptr<remote::SymbolIndex::Stub> Stub;
|
||||||
std::string ProjectRoot;
|
std::unique_ptr<Marshaller> ProtobufMarshaller;
|
||||||
// Each request will be terminated if it takes too long.
|
// Each request will be terminated if it takes too long.
|
||||||
std::chrono::milliseconds DeadlineWaitingTime;
|
std::chrono::milliseconds DeadlineWaitingTime;
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,101 +30,28 @@ namespace clang {
|
||||||
namespace clangd {
|
namespace clangd {
|
||||||
namespace remote {
|
namespace remote {
|
||||||
|
|
||||||
namespace {
|
Marshaller::Marshaller(llvm::StringRef RemoteIndexRoot,
|
||||||
|
llvm::StringRef LocalIndexRoot)
|
||||||
clangd::SymbolLocation::Position fromProtobuf(const Position &Message) {
|
: Strings(Arena) {
|
||||||
clangd::SymbolLocation::Position Result;
|
if (!RemoteIndexRoot.empty()) {
|
||||||
Result.setColumn(static_cast<uint32_t>(Message.column()));
|
assert(llvm::sys::path::is_absolute(RemoteIndexRoot));
|
||||||
Result.setLine(static_cast<uint32_t>(Message.line()));
|
assert(RemoteIndexRoot ==
|
||||||
return Result;
|
llvm::sys::path::convert_to_slash(RemoteIndexRoot));
|
||||||
}
|
assert(RemoteIndexRoot.endswith(llvm::sys::path::get_separator()));
|
||||||
|
this->RemoteIndexRoot = RemoteIndexRoot.str();
|
||||||
Position toProtobuf(const clangd::SymbolLocation::Position &Position) {
|
|
||||||
remote::Position Result;
|
|
||||||
Result.set_column(Position.column());
|
|
||||||
Result.set_line(Position.line());
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
clang::index::SymbolInfo fromProtobuf(const SymbolInfo &Message) {
|
|
||||||
clang::index::SymbolInfo Result;
|
|
||||||
Result.Kind = static_cast<clang::index::SymbolKind>(Message.kind());
|
|
||||||
Result.SubKind = static_cast<clang::index::SymbolSubKind>(Message.subkind());
|
|
||||||
Result.Lang = static_cast<clang::index::SymbolLanguage>(Message.language());
|
|
||||||
Result.Properties =
|
|
||||||
static_cast<clang::index::SymbolPropertySet>(Message.properties());
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
SymbolInfo toProtobuf(const clang::index::SymbolInfo &Info) {
|
|
||||||
SymbolInfo Result;
|
|
||||||
Result.set_kind(static_cast<uint32_t>(Info.Kind));
|
|
||||||
Result.set_subkind(static_cast<uint32_t>(Info.SubKind));
|
|
||||||
Result.set_language(static_cast<uint32_t>(Info.Lang));
|
|
||||||
Result.set_properties(static_cast<uint32_t>(Info.Properties));
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Optional<clangd::SymbolLocation>
|
|
||||||
fromProtobuf(const SymbolLocation &Message, llvm::UniqueStringSaver *Strings,
|
|
||||||
llvm::StringRef IndexRoot) {
|
|
||||||
clangd::SymbolLocation Location;
|
|
||||||
auto URIString = relativePathToURI(Message.file_path(), IndexRoot);
|
|
||||||
if (!URIString)
|
|
||||||
return llvm::None;
|
|
||||||
Location.FileURI = Strings->save(*URIString).begin();
|
|
||||||
Location.Start = fromProtobuf(Message.start());
|
|
||||||
Location.End = fromProtobuf(Message.end());
|
|
||||||
return Location;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Optional<SymbolLocation>
|
|
||||||
toProtobuf(const clangd::SymbolLocation &Location, llvm::StringRef IndexRoot) {
|
|
||||||
remote::SymbolLocation Result;
|
|
||||||
auto RelativePath = uriToRelativePath(Location.FileURI, IndexRoot);
|
|
||||||
if (!RelativePath)
|
|
||||||
return llvm::None;
|
|
||||||
*Result.mutable_file_path() = *RelativePath;
|
|
||||||
*Result.mutable_start() = toProtobuf(Location.Start);
|
|
||||||
*Result.mutable_end() = toProtobuf(Location.End);
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Optional<HeaderWithReferences>
|
|
||||||
toProtobuf(const clangd::Symbol::IncludeHeaderWithReferences &IncludeHeader,
|
|
||||||
llvm::StringRef IndexRoot) {
|
|
||||||
HeaderWithReferences Result;
|
|
||||||
Result.set_references(IncludeHeader.References);
|
|
||||||
const std::string Header = IncludeHeader.IncludeHeader.str();
|
|
||||||
if (isLiteralInclude(Header)) {
|
|
||||||
Result.set_header(Header);
|
|
||||||
return Result;
|
|
||||||
}
|
}
|
||||||
auto RelativePath = uriToRelativePath(Header, IndexRoot);
|
if (!LocalIndexRoot.empty()) {
|
||||||
if (!RelativePath)
|
assert(llvm::sys::path::is_absolute(LocalIndexRoot));
|
||||||
return llvm::None;
|
assert(LocalIndexRoot == llvm::sys::path::convert_to_slash(LocalIndexRoot));
|
||||||
Result.set_header(*RelativePath);
|
assert(LocalIndexRoot.endswith(llvm::sys::path::get_separator()));
|
||||||
return Result;
|
this->LocalIndexRoot = LocalIndexRoot.str();
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Optional<clangd::Symbol::IncludeHeaderWithReferences>
|
|
||||||
fromProtobuf(const HeaderWithReferences &Message,
|
|
||||||
llvm::UniqueStringSaver *Strings, llvm::StringRef IndexRoot) {
|
|
||||||
std::string Header = Message.header();
|
|
||||||
if (Header.front() != '<' && Header.front() != '"') {
|
|
||||||
auto URIString = relativePathToURI(Header, IndexRoot);
|
|
||||||
if (!URIString)
|
|
||||||
return llvm::None;
|
|
||||||
Header = *URIString;
|
|
||||||
}
|
}
|
||||||
return clangd::Symbol::IncludeHeaderWithReferences{Strings->save(Header),
|
assert(!RemoteIndexRoot.empty() || !LocalIndexRoot.empty());
|
||||||
Message.references()};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
clangd::FuzzyFindRequest
|
||||||
|
Marshaller::fromProtobuf(const FuzzyFindRequest *Request) {
|
||||||
clangd::FuzzyFindRequest fromProtobuf(const FuzzyFindRequest *Request,
|
assert(LocalIndexRoot);
|
||||||
llvm::StringRef IndexRoot) {
|
|
||||||
clangd::FuzzyFindRequest Result;
|
clangd::FuzzyFindRequest Result;
|
||||||
Result.Query = Request->query();
|
Result.Query = Request->query();
|
||||||
for (const auto &Scope : Request->scopes())
|
for (const auto &Scope : Request->scopes())
|
||||||
|
@ -134,7 +61,7 @@ clangd::FuzzyFindRequest fromProtobuf(const FuzzyFindRequest *Request,
|
||||||
Result.Limit = Request->limit();
|
Result.Limit = Request->limit();
|
||||||
Result.RestrictForCodeCompletion = Request->restricted_for_code_completion();
|
Result.RestrictForCodeCompletion = Request->restricted_for_code_completion();
|
||||||
for (const auto &Path : Request->proximity_paths()) {
|
for (const auto &Path : Request->proximity_paths()) {
|
||||||
llvm::SmallString<256> LocalPath = llvm::StringRef(IndexRoot);
|
llvm::SmallString<256> LocalPath = llvm::StringRef(*LocalIndexRoot);
|
||||||
llvm::sys::path::append(LocalPath, Path);
|
llvm::sys::path::append(LocalPath, Path);
|
||||||
Result.ProximityPaths.push_back(std::string(LocalPath));
|
Result.ProximityPaths.push_back(std::string(LocalPath));
|
||||||
}
|
}
|
||||||
|
@ -143,34 +70,35 @@ clangd::FuzzyFindRequest fromProtobuf(const FuzzyFindRequest *Request,
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Optional<clangd::Symbol> fromProtobuf(const Symbol &Message,
|
llvm::Optional<clangd::Symbol> Marshaller::fromProtobuf(const Symbol &Message) {
|
||||||
llvm::UniqueStringSaver *Strings,
|
if (!Message.has_info() || !Message.has_canonical_declaration()) {
|
||||||
llvm::StringRef IndexRoot) {
|
elog("Cannot convert Symbol from protobuf (missing info, definition or "
|
||||||
if (!Message.has_info() || !Message.has_definition() ||
|
"declaration): {0}",
|
||||||
!Message.has_canonical_declaration()) {
|
Message.DebugString());
|
||||||
elog("Cannot convert Symbol from Protobuf: {0}",
|
|
||||||
Message.ShortDebugString());
|
|
||||||
return llvm::None;
|
return llvm::None;
|
||||||
}
|
}
|
||||||
clangd::Symbol Result;
|
clangd::Symbol Result;
|
||||||
auto ID = SymbolID::fromStr(Message.id());
|
auto ID = SymbolID::fromStr(Message.id());
|
||||||
if (!ID) {
|
if (!ID) {
|
||||||
elog("Cannot parse SymbolID {0} given Protobuf: {1}", ID.takeError(),
|
elog("Cannot parse SymbolID {0} given protobuf: {1}", ID.takeError(),
|
||||||
Message.ShortDebugString());
|
Message.DebugString());
|
||||||
return llvm::None;
|
return llvm::None;
|
||||||
}
|
}
|
||||||
Result.ID = *ID;
|
Result.ID = *ID;
|
||||||
Result.SymInfo = fromProtobuf(Message.info());
|
Result.SymInfo = fromProtobuf(Message.info());
|
||||||
Result.Name = Message.name();
|
Result.Name = Message.name();
|
||||||
Result.Scope = Message.scope();
|
Result.Scope = Message.scope();
|
||||||
auto Definition = fromProtobuf(Message.definition(), Strings, IndexRoot);
|
if (Message.has_definition()) {
|
||||||
if (!Definition)
|
auto Definition = fromProtobuf(Message.definition());
|
||||||
return llvm::None;
|
if (Definition)
|
||||||
Result.Definition = *Definition;
|
Result.Definition = *Definition;
|
||||||
auto Declaration =
|
}
|
||||||
fromProtobuf(Message.canonical_declaration(), Strings, IndexRoot);
|
auto Declaration = fromProtobuf(Message.canonical_declaration());
|
||||||
if (!Declaration)
|
if (!Declaration) {
|
||||||
|
elog("Cannot convert Symbol from protobuf (invalid declaration): {0}",
|
||||||
|
Message.DebugString());
|
||||||
return llvm::None;
|
return llvm::None;
|
||||||
|
}
|
||||||
Result.CanonicalDeclaration = *Declaration;
|
Result.CanonicalDeclaration = *Declaration;
|
||||||
Result.References = Message.references();
|
Result.References = Message.references();
|
||||||
Result.Origin = static_cast<clangd::SymbolOrigin>(Message.origin());
|
Result.Origin = static_cast<clangd::SymbolOrigin>(Message.origin());
|
||||||
|
@ -181,39 +109,44 @@ llvm::Optional<clangd::Symbol> fromProtobuf(const Symbol &Message,
|
||||||
Result.ReturnType = Message.return_type();
|
Result.ReturnType = Message.return_type();
|
||||||
Result.Type = Message.type();
|
Result.Type = Message.type();
|
||||||
for (const auto &Header : Message.headers()) {
|
for (const auto &Header : Message.headers()) {
|
||||||
auto SerializedHeader = fromProtobuf(Header, Strings, IndexRoot);
|
auto SerializedHeader = fromProtobuf(Header);
|
||||||
if (SerializedHeader)
|
if (SerializedHeader)
|
||||||
Result.IncludeHeaders.push_back(*SerializedHeader);
|
Result.IncludeHeaders.push_back(*SerializedHeader);
|
||||||
|
else
|
||||||
|
elog("Cannot convert HeaderWithIncludes from protobuf: {0}",
|
||||||
|
Header.DebugString());
|
||||||
}
|
}
|
||||||
Result.Flags = static_cast<clangd::Symbol::SymbolFlag>(Message.flags());
|
Result.Flags = static_cast<clangd::Symbol::SymbolFlag>(Message.flags());
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Optional<clangd::Ref> fromProtobuf(const Ref &Message,
|
llvm::Optional<clangd::Ref> Marshaller::fromProtobuf(const Ref &Message) {
|
||||||
llvm::UniqueStringSaver *Strings,
|
|
||||||
llvm::StringRef IndexRoot) {
|
|
||||||
if (!Message.has_location()) {
|
if (!Message.has_location()) {
|
||||||
elog("Cannot convert Ref from Protobuf: {}", Message.ShortDebugString());
|
elog("Cannot convert Ref from protobuf (missing location): {0}",
|
||||||
|
Message.DebugString());
|
||||||
return llvm::None;
|
return llvm::None;
|
||||||
}
|
}
|
||||||
clangd::Ref Result;
|
clangd::Ref Result;
|
||||||
auto Location = fromProtobuf(Message.location(), Strings, IndexRoot);
|
auto Location = fromProtobuf(Message.location());
|
||||||
if (!Location)
|
if (!Location) {
|
||||||
|
elog("Cannot convert Ref from protobuf (invalid location): {0}",
|
||||||
|
Message.DebugString());
|
||||||
return llvm::None;
|
return llvm::None;
|
||||||
|
}
|
||||||
Result.Location = *Location;
|
Result.Location = *Location;
|
||||||
Result.Kind = static_cast<clangd::RefKind>(Message.kind());
|
Result.Kind = static_cast<clangd::RefKind>(Message.kind());
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LookupRequest toProtobuf(const clangd::LookupRequest &From) {
|
LookupRequest Marshaller::toProtobuf(const clangd::LookupRequest &From) {
|
||||||
LookupRequest RPCRequest;
|
LookupRequest RPCRequest;
|
||||||
for (const auto &SymbolID : From.IDs)
|
for (const auto &SymbolID : From.IDs)
|
||||||
RPCRequest.add_ids(SymbolID.str());
|
RPCRequest.add_ids(SymbolID.str());
|
||||||
return RPCRequest;
|
return RPCRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
FuzzyFindRequest toProtobuf(const clangd::FuzzyFindRequest &From,
|
FuzzyFindRequest Marshaller::toProtobuf(const clangd::FuzzyFindRequest &From) {
|
||||||
llvm::StringRef IndexRoot) {
|
assert(RemoteIndexRoot);
|
||||||
FuzzyFindRequest RPCRequest;
|
FuzzyFindRequest RPCRequest;
|
||||||
RPCRequest.set_query(From.Query);
|
RPCRequest.set_query(From.Query);
|
||||||
for (const auto &Scope : From.Scopes)
|
for (const auto &Scope : From.Scopes)
|
||||||
|
@ -224,7 +157,8 @@ FuzzyFindRequest toProtobuf(const clangd::FuzzyFindRequest &From,
|
||||||
RPCRequest.set_restricted_for_code_completion(From.RestrictForCodeCompletion);
|
RPCRequest.set_restricted_for_code_completion(From.RestrictForCodeCompletion);
|
||||||
for (const auto &Path : From.ProximityPaths) {
|
for (const auto &Path : From.ProximityPaths) {
|
||||||
llvm::SmallString<256> RelativePath = llvm::StringRef(Path);
|
llvm::SmallString<256> RelativePath = llvm::StringRef(Path);
|
||||||
if (llvm::sys::path::replace_path_prefix(RelativePath, IndexRoot, ""))
|
if (llvm::sys::path::replace_path_prefix(RelativePath, *RemoteIndexRoot,
|
||||||
|
""))
|
||||||
RPCRequest.add_proximity_paths(llvm::sys::path::convert_to_slash(
|
RPCRequest.add_proximity_paths(llvm::sys::path::convert_to_slash(
|
||||||
RelativePath, llvm::sys::path::Style::posix));
|
RelativePath, llvm::sys::path::Style::posix));
|
||||||
}
|
}
|
||||||
|
@ -233,7 +167,7 @@ FuzzyFindRequest toProtobuf(const clangd::FuzzyFindRequest &From,
|
||||||
return RPCRequest;
|
return RPCRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefsRequest toProtobuf(const clangd::RefsRequest &From) {
|
RefsRequest Marshaller::toProtobuf(const clangd::RefsRequest &From) {
|
||||||
RefsRequest RPCRequest;
|
RefsRequest RPCRequest;
|
||||||
for (const auto &ID : From.IDs)
|
for (const auto &ID : From.IDs)
|
||||||
RPCRequest.add_ids(ID.str());
|
RPCRequest.add_ids(ID.str());
|
||||||
|
@ -243,18 +177,28 @@ RefsRequest toProtobuf(const clangd::RefsRequest &From) {
|
||||||
return RPCRequest;
|
return RPCRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol toProtobuf(const clangd::Symbol &From, llvm::StringRef IndexRoot) {
|
llvm::Optional<Symbol> Marshaller::toProtobuf(const clangd::Symbol &From) {
|
||||||
Symbol Result;
|
Symbol Result;
|
||||||
Result.set_id(From.ID.str());
|
Result.set_id(From.ID.str());
|
||||||
*Result.mutable_info() = toProtobuf(From.SymInfo);
|
*Result.mutable_info() = toProtobuf(From.SymInfo);
|
||||||
Result.set_name(From.Name.str());
|
Result.set_name(From.Name.str());
|
||||||
auto Definition = toProtobuf(From.Definition, IndexRoot);
|
if (*From.Definition.FileURI) {
|
||||||
if (Definition)
|
auto Definition = toProtobuf(From.Definition);
|
||||||
|
if (!Definition) {
|
||||||
|
elog("Can not convert Symbol to protobuf (invalid definition) {0}: {1}",
|
||||||
|
From, From.Definition);
|
||||||
|
return llvm::None;
|
||||||
|
}
|
||||||
*Result.mutable_definition() = *Definition;
|
*Result.mutable_definition() = *Definition;
|
||||||
|
}
|
||||||
Result.set_scope(From.Scope.str());
|
Result.set_scope(From.Scope.str());
|
||||||
auto Declaration = toProtobuf(From.CanonicalDeclaration, IndexRoot);
|
auto Declaration = toProtobuf(From.CanonicalDeclaration);
|
||||||
if (Declaration)
|
if (!Declaration) {
|
||||||
*Result.mutable_canonical_declaration() = *Declaration;
|
elog("Can not convert Symbol to protobuf (invalid declaration) {0}: {1}",
|
||||||
|
From, From.CanonicalDeclaration);
|
||||||
|
return llvm::None;
|
||||||
|
}
|
||||||
|
*Result.mutable_canonical_declaration() = *Declaration;
|
||||||
Result.set_references(From.References);
|
Result.set_references(From.References);
|
||||||
Result.set_origin(static_cast<uint32_t>(From.Origin));
|
Result.set_origin(static_cast<uint32_t>(From.Origin));
|
||||||
Result.set_signature(From.Signature.str());
|
Result.set_signature(From.Signature.str());
|
||||||
|
@ -265,9 +209,12 @@ Symbol toProtobuf(const clangd::Symbol &From, llvm::StringRef IndexRoot) {
|
||||||
Result.set_return_type(From.ReturnType.str());
|
Result.set_return_type(From.ReturnType.str());
|
||||||
Result.set_type(From.Type.str());
|
Result.set_type(From.Type.str());
|
||||||
for (const auto &Header : From.IncludeHeaders) {
|
for (const auto &Header : From.IncludeHeaders) {
|
||||||
auto Serialized = toProtobuf(Header, IndexRoot);
|
auto Serialized = toProtobuf(Header);
|
||||||
if (!Serialized)
|
if (!Serialized) {
|
||||||
|
elog("Can not convert IncludeHeaderWithReferences to protobuf: {0}",
|
||||||
|
Header.IncludeHeader);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
auto *NextHeader = Result.add_headers();
|
auto *NextHeader = Result.add_headers();
|
||||||
*NextHeader = *Serialized;
|
*NextHeader = *Serialized;
|
||||||
}
|
}
|
||||||
|
@ -275,50 +222,38 @@ Symbol toProtobuf(const clangd::Symbol &From, llvm::StringRef IndexRoot) {
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(kirillbobyrev): A reference without location is invalid.
|
llvm::Optional<Ref> Marshaller::toProtobuf(const clangd::Ref &From) {
|
||||||
// llvm::Optional<Ref> here and on the server side?
|
|
||||||
Ref toProtobuf(const clangd::Ref &From, llvm::StringRef IndexRoot) {
|
|
||||||
Ref Result;
|
Ref Result;
|
||||||
Result.set_kind(static_cast<uint32_t>(From.Kind));
|
Result.set_kind(static_cast<uint32_t>(From.Kind));
|
||||||
auto Location = toProtobuf(From.Location, IndexRoot);
|
auto Location = toProtobuf(From.Location);
|
||||||
if (Location)
|
if (!Location) {
|
||||||
*Result.mutable_location() = *Location;
|
elog("Can not convert Reference to protobuf (invalid location) {0}: {1}",
|
||||||
|
From, From.Location);
|
||||||
|
return llvm::None;
|
||||||
|
}
|
||||||
|
*Result.mutable_location() = *Location;
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Optional<std::string> relativePathToURI(llvm::StringRef RelativePath,
|
llvm::Optional<std::string>
|
||||||
llvm::StringRef IndexRoot) {
|
Marshaller::relativePathToURI(llvm::StringRef RelativePath) {
|
||||||
|
assert(LocalIndexRoot);
|
||||||
assert(RelativePath == llvm::sys::path::convert_to_slash(
|
assert(RelativePath == llvm::sys::path::convert_to_slash(
|
||||||
RelativePath, llvm::sys::path::Style::posix));
|
RelativePath, llvm::sys::path::Style::posix));
|
||||||
assert(IndexRoot == llvm::sys::path::convert_to_slash(IndexRoot));
|
if (RelativePath.empty()) {
|
||||||
assert(IndexRoot.endswith(llvm::sys::path::get_separator()));
|
return llvm::None;
|
||||||
if (RelativePath.empty())
|
}
|
||||||
return std::string();
|
|
||||||
if (llvm::sys::path::is_absolute(RelativePath)) {
|
if (llvm::sys::path::is_absolute(RelativePath)) {
|
||||||
elog("Remote index client got absolute path from server: {0}",
|
|
||||||
RelativePath);
|
|
||||||
return llvm::None;
|
return llvm::None;
|
||||||
}
|
}
|
||||||
if (llvm::sys::path::is_relative(IndexRoot)) {
|
llvm::SmallString<256> FullPath = llvm::StringRef(*LocalIndexRoot);
|
||||||
elog("Remote index client got a relative path as index root: {0}",
|
|
||||||
IndexRoot);
|
|
||||||
return llvm::None;
|
|
||||||
}
|
|
||||||
llvm::SmallString<256> FullPath = IndexRoot;
|
|
||||||
llvm::sys::path::append(FullPath, RelativePath);
|
llvm::sys::path::append(FullPath, RelativePath);
|
||||||
auto Result = URI::createFile(FullPath);
|
auto Result = URI::createFile(FullPath);
|
||||||
return Result.toString();
|
return Result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Optional<std::string> uriToRelativePath(llvm::StringRef URI,
|
llvm::Optional<std::string> Marshaller::uriToRelativePath(llvm::StringRef URI) {
|
||||||
llvm::StringRef IndexRoot) {
|
assert(RemoteIndexRoot);
|
||||||
assert(IndexRoot.endswith(llvm::sys::path::get_separator()));
|
|
||||||
assert(IndexRoot == llvm::sys::path::convert_to_slash(IndexRoot));
|
|
||||||
assert(!IndexRoot.empty());
|
|
||||||
if (llvm::sys::path::is_relative(IndexRoot)) {
|
|
||||||
elog("Index root {0} is not absolute path", IndexRoot);
|
|
||||||
return llvm::None;
|
|
||||||
}
|
|
||||||
auto ParsedURI = URI::parse(URI);
|
auto ParsedURI = URI::parse(URI);
|
||||||
if (!ParsedURI) {
|
if (!ParsedURI) {
|
||||||
elog("Remote index got bad URI from client {0}: {1}", URI,
|
elog("Remote index got bad URI from client {0}: {1}", URI,
|
||||||
|
@ -326,14 +261,10 @@ llvm::Optional<std::string> uriToRelativePath(llvm::StringRef URI,
|
||||||
return llvm::None;
|
return llvm::None;
|
||||||
}
|
}
|
||||||
if (ParsedURI->scheme() != "file") {
|
if (ParsedURI->scheme() != "file") {
|
||||||
elog("Remote index got URI with scheme other than \"file\" {0}: {1}", URI,
|
|
||||||
ParsedURI->scheme());
|
|
||||||
return llvm::None;
|
return llvm::None;
|
||||||
}
|
}
|
||||||
llvm::SmallString<256> Result = ParsedURI->body();
|
llvm::SmallString<256> Result = ParsedURI->body();
|
||||||
if (!llvm::sys::path::replace_path_prefix(Result, IndexRoot, "")) {
|
if (!llvm::sys::path::replace_path_prefix(Result, *RemoteIndexRoot, "")) {
|
||||||
elog("Can not get relative path from the URI {0} given the index root {1}",
|
|
||||||
URI, IndexRoot);
|
|
||||||
return llvm::None;
|
return llvm::None;
|
||||||
}
|
}
|
||||||
// Make sure the result has UNIX slashes.
|
// Make sure the result has UNIX slashes.
|
||||||
|
@ -341,6 +272,94 @@ llvm::Optional<std::string> uriToRelativePath(llvm::StringRef URI,
|
||||||
llvm::sys::path::Style::posix);
|
llvm::sys::path::Style::posix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clangd::SymbolLocation::Position
|
||||||
|
Marshaller::fromProtobuf(const Position &Message) {
|
||||||
|
clangd::SymbolLocation::Position Result;
|
||||||
|
Result.setColumn(static_cast<uint32_t>(Message.column()));
|
||||||
|
Result.setLine(static_cast<uint32_t>(Message.line()));
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Position
|
||||||
|
Marshaller::toProtobuf(const clangd::SymbolLocation::Position &Position) {
|
||||||
|
remote::Position Result;
|
||||||
|
Result.set_column(Position.column());
|
||||||
|
Result.set_line(Position.line());
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::index::SymbolInfo Marshaller::fromProtobuf(const SymbolInfo &Message) {
|
||||||
|
clang::index::SymbolInfo Result;
|
||||||
|
Result.Kind = static_cast<clang::index::SymbolKind>(Message.kind());
|
||||||
|
Result.SubKind = static_cast<clang::index::SymbolSubKind>(Message.subkind());
|
||||||
|
Result.Lang = static_cast<clang::index::SymbolLanguage>(Message.language());
|
||||||
|
Result.Properties =
|
||||||
|
static_cast<clang::index::SymbolPropertySet>(Message.properties());
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolInfo Marshaller::toProtobuf(const clang::index::SymbolInfo &Info) {
|
||||||
|
SymbolInfo Result;
|
||||||
|
Result.set_kind(static_cast<uint32_t>(Info.Kind));
|
||||||
|
Result.set_subkind(static_cast<uint32_t>(Info.SubKind));
|
||||||
|
Result.set_language(static_cast<uint32_t>(Info.Lang));
|
||||||
|
Result.set_properties(static_cast<uint32_t>(Info.Properties));
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Optional<clangd::SymbolLocation>
|
||||||
|
Marshaller::fromProtobuf(const SymbolLocation &Message) {
|
||||||
|
clangd::SymbolLocation Location;
|
||||||
|
auto URIString = relativePathToURI(Message.file_path());
|
||||||
|
if (!URIString)
|
||||||
|
return llvm::None;
|
||||||
|
Location.FileURI = Strings.save(*URIString).begin();
|
||||||
|
Location.Start = fromProtobuf(Message.start());
|
||||||
|
Location.End = fromProtobuf(Message.end());
|
||||||
|
return Location;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Optional<SymbolLocation>
|
||||||
|
Marshaller::toProtobuf(const clangd::SymbolLocation &Location) {
|
||||||
|
remote::SymbolLocation Result;
|
||||||
|
auto RelativePath = uriToRelativePath(Location.FileURI);
|
||||||
|
if (!RelativePath)
|
||||||
|
return llvm::None;
|
||||||
|
*Result.mutable_file_path() = *RelativePath;
|
||||||
|
*Result.mutable_start() = toProtobuf(Location.Start);
|
||||||
|
*Result.mutable_end() = toProtobuf(Location.End);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Optional<HeaderWithReferences> Marshaller::toProtobuf(
|
||||||
|
const clangd::Symbol::IncludeHeaderWithReferences &IncludeHeader) {
|
||||||
|
HeaderWithReferences Result;
|
||||||
|
Result.set_references(IncludeHeader.References);
|
||||||
|
const std::string Header = IncludeHeader.IncludeHeader.str();
|
||||||
|
if (isLiteralInclude(Header)) {
|
||||||
|
Result.set_header(Header);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
auto RelativePath = uriToRelativePath(Header);
|
||||||
|
if (!RelativePath)
|
||||||
|
return llvm::None;
|
||||||
|
Result.set_header(*RelativePath);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Optional<clangd::Symbol::IncludeHeaderWithReferences>
|
||||||
|
Marshaller::fromProtobuf(const HeaderWithReferences &Message) {
|
||||||
|
std::string Header = Message.header();
|
||||||
|
if (Header.front() != '<' && Header.front() != '"') {
|
||||||
|
auto URIString = relativePathToURI(Header);
|
||||||
|
if (!URIString)
|
||||||
|
return llvm::None;
|
||||||
|
Header = *URIString;
|
||||||
|
}
|
||||||
|
return clangd::Symbol::IncludeHeaderWithReferences{Strings.save(Header),
|
||||||
|
Message.references()};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace remote
|
} // namespace remote
|
||||||
} // namespace clangd
|
} // namespace clangd
|
||||||
} // namespace clang
|
} // namespace clang
|
||||||
|
|
|
@ -5,31 +5,6 @@
|
||||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
//
|
|
||||||
// Marshalling provides translation between native clangd types into the
|
|
||||||
// Protobuf-generated classes. Most translations are 1-to-1 and wrap variables
|
|
||||||
// into appropriate Protobuf types.
|
|
||||||
//
|
|
||||||
// A notable exception is URI translation. Because paths to files are different
|
|
||||||
// on indexing machine and client machine
|
|
||||||
// ("/remote/machine/projects/llvm-project/llvm/include/HelloWorld.h" versus
|
|
||||||
// "/usr/local/username/llvm-project/llvm/include/HelloWorld.h"), they need to
|
|
||||||
// be converted appropriately. Remote machine strips the prefix from the
|
|
||||||
// absolute path and passes paths relative to the project root over the wire
|
|
||||||
// ("include/HelloWorld.h" in this example). The indexed project root is passed
|
|
||||||
// to the remote server. Client receives this relative path and constructs a URI
|
|
||||||
// that points to the relevant file in the filesystem. The relative path is
|
|
||||||
// appended to IndexRoot to construct the full path and build the final URI.
|
|
||||||
//
|
|
||||||
// Index root is the absolute path to the project and includes a trailing slash.
|
|
||||||
// The relative path passed over the wire has unix slashes.
|
|
||||||
//
|
|
||||||
// toProtobuf() functions serialize native clangd types and strip IndexRoot from
|
|
||||||
// the file paths specific to indexing machine. fromProtobuf() functions
|
|
||||||
// deserialize clangd types and translate relative paths into machine-native
|
|
||||||
// URIs.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_REMOTE_MARSHALLING_H
|
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_REMOTE_MARSHALLING_H
|
||||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_REMOTE_MARSHALLING_H
|
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_REMOTE_MARSHALLING_H
|
||||||
|
@ -43,33 +18,76 @@ namespace clang {
|
||||||
namespace clangd {
|
namespace clangd {
|
||||||
namespace remote {
|
namespace remote {
|
||||||
|
|
||||||
clangd::FuzzyFindRequest fromProtobuf(const FuzzyFindRequest *Request,
|
// Marshalling provides an interface for translattion between native clangd
|
||||||
llvm::StringRef IndexRoot);
|
// types into the Protobuf-generated classes. Most translations are 1-to-1 and
|
||||||
llvm::Optional<clangd::Symbol> fromProtobuf(const Symbol &Message,
|
// wrap variables into appropriate Protobuf types.
|
||||||
llvm::UniqueStringSaver *Strings,
|
//
|
||||||
llvm::StringRef IndexRoot);
|
/// A notable exception is URI translation. Because paths to files are different
|
||||||
llvm::Optional<clangd::Ref> fromProtobuf(const Ref &Message,
|
/// on indexing machine and client machine
|
||||||
llvm::UniqueStringSaver *Strings,
|
/// ("/remote/machine/projects/llvm-project/llvm/include/HelloWorld.h" versus
|
||||||
llvm::StringRef IndexRoot);
|
/// "/usr/local/username/llvm-project/llvm/include/HelloWorld.h"), they need to
|
||||||
|
/// be converted appropriately. Remote machine strips the prefix
|
||||||
|
/// (RemoteIndexRoot) from the absolute path and passes paths relative to the
|
||||||
|
/// project root over the wire ("include/HelloWorld.h" in this example). The
|
||||||
|
/// indexed project root is passed to the remote server. Client receives this
|
||||||
|
/// relative path and constructs a URI that points to the relevant file in the
|
||||||
|
/// filesystem. The relative path is appended to LocalIndexRoot to construct the
|
||||||
|
/// full path and build the final URI.
|
||||||
|
class Marshaller {
|
||||||
|
public:
|
||||||
|
Marshaller() = delete;
|
||||||
|
Marshaller(llvm::StringRef RemoteIndexRoot, llvm::StringRef LocalIndexRoot);
|
||||||
|
|
||||||
LookupRequest toProtobuf(const clangd::LookupRequest &From);
|
clangd::FuzzyFindRequest fromProtobuf(const FuzzyFindRequest *Request);
|
||||||
FuzzyFindRequest toProtobuf(const clangd::FuzzyFindRequest &From,
|
llvm::Optional<clangd::Symbol> fromProtobuf(const Symbol &Message);
|
||||||
llvm::StringRef IndexRoot);
|
llvm::Optional<clangd::Ref> fromProtobuf(const Ref &Message);
|
||||||
RefsRequest toProtobuf(const clangd::RefsRequest &From);
|
|
||||||
|
|
||||||
Ref toProtobuf(const clangd::Ref &From, llvm::StringRef IndexRoot);
|
/// toProtobuf() functions serialize native clangd types and strip IndexRoot
|
||||||
Symbol toProtobuf(const clangd::Symbol &From, llvm::StringRef IndexRoot);
|
/// from the file paths specific to indexing machine. fromProtobuf() functions
|
||||||
|
/// deserialize clangd types and translate relative paths into machine-native
|
||||||
|
/// URIs.
|
||||||
|
LookupRequest toProtobuf(const clangd::LookupRequest &From);
|
||||||
|
FuzzyFindRequest toProtobuf(const clangd::FuzzyFindRequest &From);
|
||||||
|
RefsRequest toProtobuf(const clangd::RefsRequest &From);
|
||||||
|
|
||||||
/// Translates \p RelativePath into the absolute path and builds URI for the
|
llvm::Optional<Ref> toProtobuf(const clangd::Ref &From);
|
||||||
/// user machine. This translation happens on the client side with the
|
llvm::Optional<Symbol> toProtobuf(const clangd::Symbol &From);
|
||||||
/// \p RelativePath received from remote index server and \p IndexRoot is
|
|
||||||
/// provided by the client.
|
/// Translates \p RelativePath into the absolute path and builds URI for the
|
||||||
llvm::Optional<std::string> relativePathToURI(llvm::StringRef RelativePath,
|
/// user machine. This translation happens on the client side with the
|
||||||
llvm::StringRef IndexRoot);
|
/// \p RelativePath received from remote index server and \p IndexRoot is
|
||||||
/// Translates a URI from the server's backing index to a relative path suitable
|
/// provided by the client.
|
||||||
/// to send over the wire to the client.
|
///
|
||||||
llvm::Optional<std::string> uriToRelativePath(llvm::StringRef URI,
|
/// The relative path passed over the wire has unix slashes.
|
||||||
llvm::StringRef IndexRoot);
|
llvm::Optional<std::string> relativePathToURI(llvm::StringRef RelativePath);
|
||||||
|
/// Translates a URI from the server's backing index to a relative path
|
||||||
|
/// suitable to send over the wire to the client.
|
||||||
|
llvm::Optional<std::string> uriToRelativePath(llvm::StringRef URI);
|
||||||
|
|
||||||
|
private:
|
||||||
|
clangd::SymbolLocation::Position fromProtobuf(const Position &Message);
|
||||||
|
Position toProtobuf(const clangd::SymbolLocation::Position &Position);
|
||||||
|
clang::index::SymbolInfo fromProtobuf(const SymbolInfo &Message);
|
||||||
|
SymbolInfo toProtobuf(const clang::index::SymbolInfo &Info);
|
||||||
|
llvm::Optional<clangd::SymbolLocation>
|
||||||
|
fromProtobuf(const SymbolLocation &Message);
|
||||||
|
llvm::Optional<SymbolLocation>
|
||||||
|
toProtobuf(const clangd::SymbolLocation &Location);
|
||||||
|
llvm::Optional<HeaderWithReferences>
|
||||||
|
toProtobuf(const clangd::Symbol::IncludeHeaderWithReferences &IncludeHeader);
|
||||||
|
llvm::Optional<clangd::Symbol::IncludeHeaderWithReferences>
|
||||||
|
fromProtobuf(const HeaderWithReferences &Message);
|
||||||
|
|
||||||
|
/// RemoteIndexRoot and LocalIndexRoot are absolute paths to the project (on
|
||||||
|
/// remote and local machine respectively) and include a trailing slash. One
|
||||||
|
/// of them can be missing (if the machines are different they don't know each
|
||||||
|
/// other's specifics and will only do one-way translation), but both can not
|
||||||
|
/// be missing at the same time.
|
||||||
|
llvm::Optional<std::string> RemoteIndexRoot;
|
||||||
|
llvm::Optional<std::string> LocalIndexRoot;
|
||||||
|
llvm::BumpPtrAllocator Arena;
|
||||||
|
llvm::UniqueStringSaver Strings;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace remote
|
} // namespace remote
|
||||||
} // namespace clangd
|
} // namespace clangd
|
||||||
|
|
|
@ -50,7 +50,9 @@ public:
|
||||||
: Index(std::move(Index)) {
|
: Index(std::move(Index)) {
|
||||||
llvm::SmallString<256> NativePath = IndexRoot;
|
llvm::SmallString<256> NativePath = IndexRoot;
|
||||||
llvm::sys::path::native(NativePath);
|
llvm::sys::path::native(NativePath);
|
||||||
IndexedProjectRoot = std::string(NativePath);
|
ProtobufMarshaller = std::unique_ptr<Marshaller>(new Marshaller(
|
||||||
|
/*RemoteIndexRoot=*/llvm::StringRef(NativePath),
|
||||||
|
/*LocalIndexRoot=*/""));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -65,9 +67,11 @@ private:
|
||||||
Req.IDs.insert(*SID);
|
Req.IDs.insert(*SID);
|
||||||
}
|
}
|
||||||
Index->lookup(Req, [&](const clangd::Symbol &Sym) {
|
Index->lookup(Req, [&](const clangd::Symbol &Sym) {
|
||||||
|
auto SerializedSymbol = ProtobufMarshaller->toProtobuf(Sym);
|
||||||
|
if (!SerializedSymbol)
|
||||||
|
return;
|
||||||
LookupReply NextMessage;
|
LookupReply NextMessage;
|
||||||
*NextMessage.mutable_stream_result() =
|
*NextMessage.mutable_stream_result() = *SerializedSymbol;
|
||||||
toProtobuf(Sym, IndexedProjectRoot);
|
|
||||||
Reply->Write(NextMessage);
|
Reply->Write(NextMessage);
|
||||||
});
|
});
|
||||||
LookupReply LastMessage;
|
LookupReply LastMessage;
|
||||||
|
@ -79,11 +83,13 @@ private:
|
||||||
grpc::Status FuzzyFind(grpc::ServerContext *Context,
|
grpc::Status FuzzyFind(grpc::ServerContext *Context,
|
||||||
const FuzzyFindRequest *Request,
|
const FuzzyFindRequest *Request,
|
||||||
grpc::ServerWriter<FuzzyFindReply> *Reply) override {
|
grpc::ServerWriter<FuzzyFindReply> *Reply) override {
|
||||||
const auto Req = fromProtobuf(Request, IndexedProjectRoot);
|
const auto Req = ProtobufMarshaller->fromProtobuf(Request);
|
||||||
bool HasMore = Index->fuzzyFind(Req, [&](const clangd::Symbol &Sym) {
|
bool HasMore = Index->fuzzyFind(Req, [&](const clangd::Symbol &Sym) {
|
||||||
|
auto SerializedSymbol = ProtobufMarshaller->toProtobuf(Sym);
|
||||||
|
if (!SerializedSymbol)
|
||||||
|
return;
|
||||||
FuzzyFindReply NextMessage;
|
FuzzyFindReply NextMessage;
|
||||||
*NextMessage.mutable_stream_result() =
|
*NextMessage.mutable_stream_result() = *SerializedSymbol;
|
||||||
toProtobuf(Sym, IndexedProjectRoot);
|
|
||||||
Reply->Write(NextMessage);
|
Reply->Write(NextMessage);
|
||||||
});
|
});
|
||||||
FuzzyFindReply LastMessage;
|
FuzzyFindReply LastMessage;
|
||||||
|
@ -102,8 +108,11 @@ private:
|
||||||
Req.IDs.insert(*SID);
|
Req.IDs.insert(*SID);
|
||||||
}
|
}
|
||||||
bool HasMore = Index->refs(Req, [&](const clangd::Ref &Reference) {
|
bool HasMore = Index->refs(Req, [&](const clangd::Ref &Reference) {
|
||||||
|
auto SerializedRef = ProtobufMarshaller->toProtobuf(Reference);
|
||||||
|
if (!SerializedRef)
|
||||||
|
return;
|
||||||
RefsReply NextMessage;
|
RefsReply NextMessage;
|
||||||
*NextMessage.mutable_stream_result() = toProtobuf(Reference, IndexRoot);
|
*NextMessage.mutable_stream_result() = *SerializedRef;
|
||||||
Reply->Write(NextMessage);
|
Reply->Write(NextMessage);
|
||||||
});
|
});
|
||||||
RefsReply LastMessage;
|
RefsReply LastMessage;
|
||||||
|
@ -113,7 +122,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<clangd::SymbolIndex> Index;
|
std::unique_ptr<clangd::SymbolIndex> Index;
|
||||||
std::string IndexedProjectRoot;
|
std::unique_ptr<Marshaller> ProtobufMarshaller;
|
||||||
};
|
};
|
||||||
|
|
||||||
void runServer(std::unique_ptr<clangd::SymbolIndex> Index,
|
void runServer(std::unique_ptr<clangd::SymbolIndex> Index,
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "index/Serialization.h"
|
#include "index/Serialization.h"
|
||||||
#include "index/Symbol.h"
|
#include "index/Symbol.h"
|
||||||
#include "index/SymbolID.h"
|
#include "index/SymbolID.h"
|
||||||
|
#include "index/SymbolLocation.h"
|
||||||
#include "index/remote/marshalling/Marshalling.h"
|
#include "index/remote/marshalling/Marshalling.h"
|
||||||
#include "clang/Index/IndexSymbol.h"
|
#include "clang/Index/IndexSymbol.h"
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
|
@ -39,29 +40,35 @@ const char *testPathURI(llvm::StringRef Path,
|
||||||
TEST(RemoteMarshallingTest, URITranslation) {
|
TEST(RemoteMarshallingTest, URITranslation) {
|
||||||
llvm::BumpPtrAllocator Arena;
|
llvm::BumpPtrAllocator Arena;
|
||||||
llvm::UniqueStringSaver Strings(Arena);
|
llvm::UniqueStringSaver Strings(Arena);
|
||||||
|
Marshaller ProtobufMarshaller(
|
||||||
|
testPath("remote/machine/projects/llvm-project/"),
|
||||||
|
testPath("home/my-projects/llvm-project/"));
|
||||||
clangd::Ref Original;
|
clangd::Ref Original;
|
||||||
Original.Location.FileURI =
|
Original.Location.FileURI =
|
||||||
testPathURI("remote/machine/projects/llvm-project/clang-tools-extra/"
|
testPathURI("remote/machine/projects/llvm-project/clang-tools-extra/"
|
||||||
"clangd/unittests/remote/MarshallingTests.cpp",
|
"clangd/unittests/remote/MarshallingTests.cpp",
|
||||||
Strings);
|
Strings);
|
||||||
auto Serialized =
|
auto Serialized = ProtobufMarshaller.toProtobuf(Original);
|
||||||
toProtobuf(Original, testPath("remote/machine/projects/llvm-project/"));
|
EXPECT_TRUE(Serialized);
|
||||||
EXPECT_EQ(Serialized.location().file_path(),
|
EXPECT_EQ(Serialized->location().file_path(),
|
||||||
"clang-tools-extra/clangd/unittests/remote/MarshallingTests.cpp");
|
"clang-tools-extra/clangd/unittests/remote/MarshallingTests.cpp");
|
||||||
const std::string LocalIndexPrefix = testPath("local/machine/project/");
|
auto Deserialized = ProtobufMarshaller.fromProtobuf(*Serialized);
|
||||||
auto Deserialized = fromProtobuf(Serialized, &Strings,
|
|
||||||
testPath("home/my-projects/llvm-project/"));
|
|
||||||
EXPECT_TRUE(Deserialized);
|
EXPECT_TRUE(Deserialized);
|
||||||
EXPECT_EQ(Deserialized->Location.FileURI,
|
EXPECT_STREQ(Deserialized->Location.FileURI,
|
||||||
testPathURI("home/my-projects/llvm-project/clang-tools-extra/"
|
testPathURI("home/my-projects/llvm-project/clang-tools-extra/"
|
||||||
"clangd/unittests/remote/MarshallingTests.cpp",
|
"clangd/unittests/remote/MarshallingTests.cpp",
|
||||||
Strings));
|
Strings));
|
||||||
|
|
||||||
|
// Can't have empty paths.
|
||||||
|
*Serialized->mutable_location()->mutable_file_path() = std::string();
|
||||||
|
Deserialized = ProtobufMarshaller.fromProtobuf(*Serialized);
|
||||||
|
EXPECT_FALSE(Deserialized);
|
||||||
|
|
||||||
clangd::Ref WithInvalidURI;
|
clangd::Ref WithInvalidURI;
|
||||||
// Invalid URI results in empty path.
|
// Invalid URI results in serialization failure.
|
||||||
WithInvalidURI.Location.FileURI = "This is not a URI";
|
WithInvalidURI.Location.FileURI = "This is not a URI";
|
||||||
Serialized = toProtobuf(WithInvalidURI, testPath("home/"));
|
Serialized = ProtobufMarshaller.toProtobuf(WithInvalidURI);
|
||||||
EXPECT_EQ(Serialized.location().file_path(), "");
|
EXPECT_FALSE(Serialized);
|
||||||
|
|
||||||
// Can not use URIs with scheme different from "file".
|
// Can not use URIs with scheme different from "file".
|
||||||
auto UnittestURI =
|
auto UnittestURI =
|
||||||
|
@ -69,15 +76,15 @@ TEST(RemoteMarshallingTest, URITranslation) {
|
||||||
EXPECT_TRUE(bool(UnittestURI));
|
EXPECT_TRUE(bool(UnittestURI));
|
||||||
WithInvalidURI.Location.FileURI =
|
WithInvalidURI.Location.FileURI =
|
||||||
Strings.save(UnittestURI->toString()).begin();
|
Strings.save(UnittestURI->toString()).begin();
|
||||||
Serialized = toProtobuf(WithInvalidURI, testPath("project/lib/"));
|
Serialized = ProtobufMarshaller.toProtobuf(WithInvalidURI);
|
||||||
EXPECT_EQ(Serialized.location().file_path(), "");
|
EXPECT_FALSE(Serialized);
|
||||||
|
|
||||||
|
// Paths transmitted over the wire can not be absolute, they have to be
|
||||||
|
// relative.
|
||||||
Ref WithAbsolutePath;
|
Ref WithAbsolutePath;
|
||||||
*WithAbsolutePath.mutable_location()->mutable_file_path() =
|
*WithAbsolutePath.mutable_location()->mutable_file_path() =
|
||||||
"/usr/local/user/home/HelloWorld.cpp";
|
"/usr/local/user/home/HelloWorld.cpp";
|
||||||
Deserialized = fromProtobuf(WithAbsolutePath, &Strings, LocalIndexPrefix);
|
Deserialized = ProtobufMarshaller.fromProtobuf(WithAbsolutePath);
|
||||||
// Paths transmitted over the wire can not be absolute, they have to be
|
|
||||||
// relative.
|
|
||||||
EXPECT_FALSE(Deserialized);
|
EXPECT_FALSE(Deserialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,48 +135,63 @@ TEST(RemoteMarshallingTest, SymbolSerialization) {
|
||||||
|
|
||||||
Sym.Flags = clangd::Symbol::SymbolFlag::IndexedForCodeCompletion;
|
Sym.Flags = clangd::Symbol::SymbolFlag::IndexedForCodeCompletion;
|
||||||
|
|
||||||
|
Marshaller ProtobufMarshaller(testPath("home/"), testPath("home/"));
|
||||||
|
|
||||||
// Check that symbols are exactly the same if the path to indexed project is
|
// Check that symbols are exactly the same if the path to indexed project is
|
||||||
// the same on indexing machine and the client.
|
// the same on indexing machine and the client.
|
||||||
auto Serialized = toProtobuf(Sym, testPath("home/"));
|
auto Serialized = ProtobufMarshaller.toProtobuf(Sym);
|
||||||
auto Deserialized = fromProtobuf(Serialized, &Strings, testPath("home/"));
|
EXPECT_TRUE(Serialized);
|
||||||
|
auto Deserialized = ProtobufMarshaller.fromProtobuf(*Serialized);
|
||||||
EXPECT_TRUE(Deserialized);
|
EXPECT_TRUE(Deserialized);
|
||||||
EXPECT_EQ(toYAML(Sym), toYAML(*Deserialized));
|
EXPECT_EQ(toYAML(Sym), toYAML(*Deserialized));
|
||||||
// Serialized paths are relative and have UNIX slashes.
|
// Serialized paths are relative and have UNIX slashes.
|
||||||
EXPECT_EQ(convert_to_slash(Serialized.definition().file_path(),
|
EXPECT_EQ(convert_to_slash(Serialized->definition().file_path(),
|
||||||
llvm::sys::path::Style::posix),
|
llvm::sys::path::Style::posix),
|
||||||
Serialized.definition().file_path());
|
Serialized->definition().file_path());
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
llvm::sys::path::is_relative(Serialized.definition().file_path()));
|
llvm::sys::path::is_relative(Serialized->definition().file_path()));
|
||||||
|
|
||||||
|
// Missing definition is OK.
|
||||||
|
Sym.Definition = clangd::SymbolLocation();
|
||||||
|
Serialized = ProtobufMarshaller.toProtobuf(Sym);
|
||||||
|
EXPECT_TRUE(Serialized);
|
||||||
|
Deserialized = ProtobufMarshaller.fromProtobuf(*Serialized);
|
||||||
|
EXPECT_TRUE(Deserialized);
|
||||||
|
|
||||||
|
// Relative path is absolute.
|
||||||
|
*Serialized->mutable_canonical_declaration()->mutable_file_path() =
|
||||||
|
convert_to_slash("/path/to/Declaration.h");
|
||||||
|
Deserialized = ProtobufMarshaller.fromProtobuf(*Serialized);
|
||||||
|
EXPECT_FALSE(Deserialized);
|
||||||
|
|
||||||
// Fail with an invalid URI.
|
// Fail with an invalid URI.
|
||||||
Location.FileURI = "Not A URI";
|
Location.FileURI = "Not A URI";
|
||||||
Sym.Definition = Location;
|
Sym.Definition = Location;
|
||||||
Serialized = toProtobuf(Sym, testPath("home/"));
|
Serialized = ProtobufMarshaller.toProtobuf(Sym);
|
||||||
Deserialized = fromProtobuf(Serialized, &Strings, testPath("home/"));
|
EXPECT_FALSE(Serialized);
|
||||||
EXPECT_FALSE(Deserialized);
|
|
||||||
|
|
||||||
// Schemes other than "file" can not be used.
|
// Schemes other than "file" can not be used.
|
||||||
auto UnittestURI = URI::create(testPath("home/SomePath.h"), "unittest");
|
auto UnittestURI = URI::create(testPath("home/SomePath.h"), "unittest");
|
||||||
EXPECT_TRUE(bool(UnittestURI));
|
EXPECT_TRUE(bool(UnittestURI));
|
||||||
Location.FileURI = Strings.save(UnittestURI->toString()).begin();
|
Location.FileURI = Strings.save(UnittestURI->toString()).begin();
|
||||||
Sym.Definition = Location;
|
Sym.Definition = Location;
|
||||||
Serialized = toProtobuf(Sym, testPath("home/"));
|
Serialized = ProtobufMarshaller.toProtobuf(Sym);
|
||||||
Deserialized = fromProtobuf(Serialized, &Strings, testPath("home/"));
|
EXPECT_FALSE(Serialized);
|
||||||
EXPECT_FALSE(Deserialized);
|
|
||||||
|
|
||||||
// Passing root that is not prefix of the original file path.
|
// Passing root that is not prefix of the original file path.
|
||||||
Location.FileURI = testPathURI("home/File.h", Strings);
|
Location.FileURI = testPathURI("home/File.h", Strings);
|
||||||
Sym.Definition = Location;
|
Sym.Definition = Location;
|
||||||
// Check that the symbol is valid and passing the correct path works.
|
// Check that the symbol is valid and passing the correct path works.
|
||||||
Serialized = toProtobuf(Sym, testPath("home/"));
|
Serialized = ProtobufMarshaller.toProtobuf(Sym);
|
||||||
Deserialized = fromProtobuf(Serialized, &Strings, testPath("home/"));
|
EXPECT_TRUE(Serialized);
|
||||||
|
Deserialized = ProtobufMarshaller.fromProtobuf(*Serialized);
|
||||||
EXPECT_TRUE(Deserialized);
|
EXPECT_TRUE(Deserialized);
|
||||||
EXPECT_EQ(Deserialized->Definition.FileURI,
|
EXPECT_STREQ(Deserialized->Definition.FileURI,
|
||||||
testPathURI("home/File.h", Strings));
|
testPathURI("home/File.h", Strings));
|
||||||
// Fail with a wrong root.
|
// Fail with a wrong root.
|
||||||
Serialized = toProtobuf(Sym, testPath("nothome/"));
|
Marshaller WrongMarshaller(testPath("nothome/"), testPath("home/"));
|
||||||
Deserialized = fromProtobuf(Serialized, &Strings, testPath("home/"));
|
Serialized = WrongMarshaller.toProtobuf(Sym);
|
||||||
EXPECT_FALSE(Deserialized);
|
EXPECT_FALSE(Serialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RemoteMarshallingTest, RefSerialization) {
|
TEST(RemoteMarshallingTest, RefSerialization) {
|
||||||
|
@ -188,9 +210,12 @@ TEST(RemoteMarshallingTest, RefSerialization) {
|
||||||
"llvm-project/llvm/clang-tools-extra/clangd/Protocol.h", Strings);
|
"llvm-project/llvm/clang-tools-extra/clangd/Protocol.h", Strings);
|
||||||
Ref.Location = Location;
|
Ref.Location = Location;
|
||||||
|
|
||||||
auto Serialized = toProtobuf(Ref, testPath("llvm-project/"));
|
Marshaller ProtobufMarshaller(testPath("llvm-project/"),
|
||||||
auto Deserialized =
|
testPath("llvm-project/"));
|
||||||
fromProtobuf(Serialized, &Strings, testPath("llvm-project/"));
|
|
||||||
|
auto Serialized = ProtobufMarshaller.toProtobuf(Ref);
|
||||||
|
EXPECT_TRUE(Serialized);
|
||||||
|
auto Deserialized = ProtobufMarshaller.fromProtobuf(*Serialized);
|
||||||
EXPECT_TRUE(Deserialized);
|
EXPECT_TRUE(Deserialized);
|
||||||
EXPECT_EQ(toYAML(Ref), toYAML(*Deserialized));
|
EXPECT_EQ(toYAML(Ref), toYAML(*Deserialized));
|
||||||
}
|
}
|
||||||
|
@ -242,10 +267,13 @@ TEST(RemoteMarshallingTest, IncludeHeaderURIs) {
|
||||||
InvalidHeaders.end());
|
InvalidHeaders.end());
|
||||||
Sym.IncludeHeaders = AllHeaders;
|
Sym.IncludeHeaders = AllHeaders;
|
||||||
|
|
||||||
auto Serialized = toProtobuf(Sym, convert_to_slash("/"));
|
Marshaller ProtobufMarshaller(convert_to_slash("/"), convert_to_slash("/"));
|
||||||
EXPECT_EQ(static_cast<size_t>(Serialized.headers_size()),
|
|
||||||
|
auto Serialized = ProtobufMarshaller.toProtobuf(Sym);
|
||||||
|
EXPECT_EQ(static_cast<size_t>(Serialized->headers_size()),
|
||||||
ValidHeaders.size());
|
ValidHeaders.size());
|
||||||
auto Deserialized = fromProtobuf(Serialized, &Strings, convert_to_slash("/"));
|
EXPECT_TRUE(Serialized);
|
||||||
|
auto Deserialized = ProtobufMarshaller.fromProtobuf(*Serialized);
|
||||||
EXPECT_TRUE(Deserialized);
|
EXPECT_TRUE(Deserialized);
|
||||||
|
|
||||||
Sym.IncludeHeaders = ValidHeaders;
|
Sym.IncludeHeaders = ValidHeaders;
|
||||||
|
@ -257,35 +285,38 @@ TEST(RemoteMarshallingTest, FuzzyFindRequestSerialization) {
|
||||||
Request.ProximityPaths = {testPath("remote/Header.h"),
|
Request.ProximityPaths = {testPath("remote/Header.h"),
|
||||||
testPath("remote/subdir/OtherHeader.h"),
|
testPath("remote/subdir/OtherHeader.h"),
|
||||||
testPath("notremote/File.h"), "Not a Path."};
|
testPath("notremote/File.h"), "Not a Path."};
|
||||||
auto Serialized = toProtobuf(Request, testPath("remote/"));
|
Marshaller ProtobufMarshaller(testPath("remote/"), testPath("home/"));
|
||||||
|
auto Serialized = ProtobufMarshaller.toProtobuf(Request);
|
||||||
EXPECT_EQ(Serialized.proximity_paths_size(), 2);
|
EXPECT_EQ(Serialized.proximity_paths_size(), 2);
|
||||||
auto Deserialized = fromProtobuf(&Serialized, testPath("home/"));
|
auto Deserialized = ProtobufMarshaller.fromProtobuf(&Serialized);
|
||||||
EXPECT_THAT(Deserialized.ProximityPaths,
|
EXPECT_THAT(Deserialized.ProximityPaths,
|
||||||
testing::ElementsAre(testPath("home/Header.h"),
|
testing::ElementsAre(testPath("home/Header.h"),
|
||||||
testPath("home/subdir/OtherHeader.h")));
|
testPath("home/subdir/OtherHeader.h")));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RemoteMarshallingTest, RelativePathToURITranslation) {
|
TEST(RemoteMarshallingTest, RelativePathToURITranslation) {
|
||||||
EXPECT_TRUE(relativePathToURI("lib/File.cpp", testPath("home/project/")));
|
Marshaller ProtobufMarshaller(/*RemoteIndexRoot=*/"",
|
||||||
|
/*LocalIndexRoot=*/testPath("home/project/"));
|
||||||
|
EXPECT_TRUE(ProtobufMarshaller.relativePathToURI("lib/File.cpp"));
|
||||||
// RelativePath can not be absolute.
|
// RelativePath can not be absolute.
|
||||||
EXPECT_FALSE(relativePathToURI("/lib/File.cpp", testPath("home/project/")));
|
EXPECT_FALSE(ProtobufMarshaller.relativePathToURI("/lib/File.cpp"));
|
||||||
// IndexRoot has to be absolute path.
|
// RelativePath can not be empty.
|
||||||
EXPECT_FALSE(relativePathToURI("lib/File.cpp", "home/project/"));
|
EXPECT_FALSE(ProtobufMarshaller.relativePathToURI(std::string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RemoteMarshallingTest, URIToRelativePathTranslation) {
|
TEST(RemoteMarshallingTest, URIToRelativePathTranslation) {
|
||||||
llvm::BumpPtrAllocator Arena;
|
llvm::BumpPtrAllocator Arena;
|
||||||
llvm::UniqueStringSaver Strings(Arena);
|
llvm::UniqueStringSaver Strings(Arena);
|
||||||
EXPECT_TRUE(
|
Marshaller ProtobufMarshaller(/*RemoteIndexRoot=*/testPath("remote/project/"),
|
||||||
uriToRelativePath(testPathURI("home/project/lib/File.cpp", Strings),
|
/*LocalIndexRoot=*/"");
|
||||||
testPath("home/project/")));
|
EXPECT_TRUE(ProtobufMarshaller.uriToRelativePath(
|
||||||
// IndexRoot has to be absolute path.
|
testPathURI("remote/project/lib/File.cpp", Strings)));
|
||||||
EXPECT_FALSE(uriToRelativePath(
|
// RemoteIndexRoot has to be be a prefix of the file path.
|
||||||
testPathURI("home/project/lib/File.cpp", Strings), "home/project/"));
|
Marshaller WrongMarshaller(
|
||||||
// IndexRoot has to be be a prefix of the file path.
|
/*RemoteIndexRoot=*/testPath("remote/other/project/"),
|
||||||
EXPECT_FALSE(
|
/*LocalIndexRoot=*/"");
|
||||||
uriToRelativePath(testPathURI("home/project/lib/File.cpp", Strings),
|
EXPECT_FALSE(WrongMarshaller.uriToRelativePath(
|
||||||
testPath("home/other/project/")));
|
testPathURI("remote/project/lib/File.cpp", Strings)));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
Loading…
Reference in New Issue