#include "Headers.h"
#include "Index.pb.h"
#include "Protocol.h"
+#include "index/Index.h"
#include "index/Serialization.h"
#include "index/Symbol.h"
#include "index/SymbolID.h"
namespace {
-template <typename MessageT>
-llvm::Expected<llvm::DenseSet<SymbolID>> getIDs(MessageT *Message) {
+template <typename IDRange>
+llvm::Expected<llvm::DenseSet<SymbolID>> getIDs(IDRange IDs) {
llvm::DenseSet<SymbolID> Result;
- for (const auto &ID : Message->ids()) {
+ for (const auto &ID : IDs) {
auto SID = SymbolID::fromStr(StringRef(ID));
if (!SID)
return SID.takeError();
llvm::Expected<clangd::LookupRequest>
Marshaller::fromProtobuf(const LookupRequest *Message) {
clangd::LookupRequest Req;
- auto IDs = getIDs(Message);
+ auto IDs = getIDs(Message->ids());
if (!IDs)
return IDs.takeError();
Req.IDs = std::move(*IDs);
llvm::Expected<clangd::RefsRequest>
Marshaller::fromProtobuf(const RefsRequest *Message) {
clangd::RefsRequest Req;
- auto IDs = getIDs(Message);
+ auto IDs = getIDs(Message->ids());
if (!IDs)
return IDs.takeError();
Req.IDs = std::move(*IDs);
return Req;
}
+llvm::Expected<clangd::RelationsRequest>
+Marshaller::fromProtobuf(const RelationsRequest *Message) {
+ clangd::RelationsRequest Req;
+ auto IDs = getIDs(Message->subjects());
+ if (!IDs)
+ return IDs.takeError();
+ Req.Subjects = std::move(*IDs);
+ Req.Predicate = static_cast<RelationKind>(Message->predicate());
+ if (Message->limit())
+ Req.Limit = Message->limit();
+ return Req;
+}
+
llvm::Optional<clangd::Symbol> Marshaller::fromProtobuf(const Symbol &Message) {
if (!Message.has_info() || !Message.has_canonical_declaration()) {
elog("Cannot convert Symbol from protobuf (missing info, definition or "
return Result;
}
+llvm::Optional<std::pair<clangd::SymbolID, clangd::Symbol>>
+Marshaller::fromProtobuf(const Relation &Message) {
+ auto SubjectID = SymbolID::fromStr(Message.subject_id());
+ if (!SubjectID) {
+ elog("Cannot convert Relation from protobuf (invalid Subject ID): {0}",
+ SubjectID.takeError());
+ return llvm::None;
+ }
+ if (!Message.has_object()) {
+ elog("Cannot convert Relation from protobuf (missing Object): {0}");
+ return llvm::None;
+ }
+ auto Object = fromProtobuf(Message.object());
+ if (!Object)
+ return llvm::None;
+ return std::make_pair(*SubjectID, *Object);
+}
+
LookupRequest Marshaller::toProtobuf(const clangd::LookupRequest &From) {
LookupRequest RPCRequest;
for (const auto &SymbolID : From.IDs)
return RPCRequest;
}
+RelationsRequest Marshaller::toProtobuf(const clangd::RelationsRequest &From) {
+ RelationsRequest RPCRequest;
+ for (const auto &ID : From.Subjects)
+ RPCRequest.add_subjects(ID.str());
+ RPCRequest.set_predicate(static_cast<uint32_t>(From.Predicate));
+ if (From.Limit)
+ RPCRequest.set_limit(*From.Limit);
+ return RPCRequest;
+}
+
llvm::Optional<Symbol> Marshaller::toProtobuf(const clangd::Symbol &From) {
Symbol Result;
Result.set_id(From.ID.str());
return Result;
}
+llvm::Optional<Relation> Marshaller::toProtobuf(const clangd::SymbolID &Subject,
+ const clangd::Symbol &Object) {
+ Relation Result;
+ *Result.mutable_subject_id() = Subject.str();
+ auto SerializedObject = toProtobuf(Object);
+ if (!SerializedObject) {
+ elog("Can not convert Relation to protobuf (invalid symbol): {0}", Object);
+ return llvm::None;
+ }
+ *Result.mutable_object() = *SerializedObject;
+ return Result;
+}
+
llvm::Optional<std::string>
Marshaller::relativePathToURI(llvm::StringRef RelativePath) {
assert(LocalIndexRoot);
#include "TestFS.h"
#include "index/Index.h"
#include "index/Ref.h"
+#include "index/Relation.h"
#include "index/Serialization.h"
#include "index/Symbol.h"
#include "index/SymbolID.h"
#include "clang/Index/IndexSymbol.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/StringSaver.h"
return Strings.save(URI.toString()).begin();
}
+clangd::Symbol createSymbol(llvm::StringRef PathPrefix,
+ llvm::UniqueStringSaver &Strings) {
+ clangd::Symbol Sym;
+ Sym.ID = llvm::cantFail(SymbolID::fromStr("057557CEBF6E6B2D"));
+
+ index::SymbolInfo Info;
+ Info.Kind = index::SymbolKind::Function;
+ Info.SubKind = index::SymbolSubKind::AccessorGetter;
+ Info.Lang = index::SymbolLanguage::CXX;
+ Info.Properties = static_cast<index::SymbolPropertySet>(
+ index::SymbolProperty::TemplateSpecialization);
+ Sym.SymInfo = Info;
+
+ Sym.Name = Strings.save("Foo");
+ Sym.Scope = Strings.save("llvm::foo::bar::");
+
+ clangd::SymbolLocation Location;
+ Location.Start.setLine(1);
+ Location.Start.setColumn(15);
+ Location.End.setLine(3);
+ Location.End.setColumn(121);
+ Location.FileURI = testPathURI(PathPrefix.str() + "Definition.cpp", Strings);
+ Sym.Definition = Location;
+
+ Location.Start.setLine(42);
+ Location.Start.setColumn(31);
+ Location.End.setLine(20);
+ Location.End.setColumn(400);
+ Location.FileURI = testPathURI(PathPrefix.str() + "Declaration.h", Strings);
+ Sym.CanonicalDeclaration = Location;
+
+ Sym.References = 9000;
+ Sym.Origin = clangd::SymbolOrigin::Static;
+ Sym.Signature = Strings.save("(int X, char Y, Type T)");
+ Sym.TemplateSpecializationArgs = Strings.save("<int, char, bool, Type>");
+ Sym.CompletionSnippetSuffix =
+ Strings.save("({1: int X}, {2: char Y}, {3: Type T})");
+ Sym.Documentation = Strings.save("This is my amazing Foo constructor!");
+ Sym.ReturnType = Strings.save("Foo");
+
+ Sym.Flags = clangd::Symbol::SymbolFlag::IndexedForCodeCompletion;
+
+ return Sym;
+}
+
TEST(RemoteMarshallingTest, URITranslation) {
llvm::BumpPtrAllocator Arena;
llvm::UniqueStringSaver Strings(Arena);
}
TEST(RemoteMarshallingTest, SymbolSerialization) {
- clangd::Symbol Sym;
-
- auto ID = SymbolID::fromStr("057557CEBF6E6B2D");
- ASSERT_TRUE(bool(ID));
- Sym.ID = *ID;
-
- index::SymbolInfo Info;
- Info.Kind = index::SymbolKind::Function;
- Info.SubKind = index::SymbolSubKind::AccessorGetter;
- Info.Lang = index::SymbolLanguage::CXX;
- Info.Properties = static_cast<index::SymbolPropertySet>(
- index::SymbolProperty::TemplateSpecialization);
- Sym.SymInfo = Info;
-
llvm::BumpPtrAllocator Arena;
llvm::UniqueStringSaver Strings(Arena);
- Sym.Name = Strings.save("Foo");
- Sym.Scope = Strings.save("llvm::foo::bar::");
-
- clangd::SymbolLocation Location;
- Location.Start.setLine(1);
- Location.Start.setColumn(15);
- Location.End.setLine(3);
- Location.End.setColumn(121);
- Location.FileURI = testPathURI("home/Definition.cpp", Strings);
- Sym.Definition = Location;
-
- Location.Start.setLine(42);
- Location.Start.setColumn(31);
- Location.End.setLine(20);
- Location.End.setColumn(400);
- Location.FileURI = testPathURI("home/Declaration.h", Strings);
- Sym.CanonicalDeclaration = Location;
-
- Sym.References = 9000;
- Sym.Origin = clangd::SymbolOrigin::Static;
- Sym.Signature = Strings.save("(int X, char Y, Type T)");
- Sym.TemplateSpecializationArgs = Strings.save("<int, char, bool, Type>");
- Sym.CompletionSnippetSuffix =
- Strings.save("({1: int X}, {2: char Y}, {3: Type T})");
- Sym.Documentation = Strings.save("This is my amazing Foo constructor!");
- Sym.ReturnType = Strings.save("Foo");
-
- Sym.Flags = clangd::Symbol::SymbolFlag::IndexedForCodeCompletion;
-
+ clangd::Symbol Sym = createSymbol("home/", Strings);
Marshaller ProtobufMarshaller(testPath("home/"), testPath("home/"));
// Check that symbols are exactly the same if the path to indexed project is
EXPECT_FALSE(ProtobufMarshaller.fromProtobuf(*Serialized));
// Fail with an invalid URI.
- Location.FileURI = "Not A URI";
- Sym.Definition = Location;
+ Sym.Definition.FileURI = "Not A URI";
EXPECT_FALSE(ProtobufMarshaller.toProtobuf(Sym));
// Schemes other than "file" can not be used.
auto UnittestURI = URI::create(testPath("home/SomePath.h"), "unittest");
ASSERT_TRUE(bool(UnittestURI));
- Location.FileURI = Strings.save(UnittestURI->toString()).begin();
- Sym.Definition = Location;
+ Sym.Definition.FileURI = Strings.save(UnittestURI->toString()).begin();
EXPECT_FALSE(ProtobufMarshaller.toProtobuf(Sym));
// Passing root that is not prefix of the original file path.
- Location.FileURI = testPathURI("home/File.h", Strings);
- Sym.Definition = Location;
+ Sym.Definition.FileURI = testPathURI("home/File.h", Strings);
// Check that the symbol is valid and passing the correct path works.
Serialized = ProtobufMarshaller.toProtobuf(Sym);
ASSERT_TRUE(Serialized);
llvm::consumeError(Deserialized.takeError());
}
+TEST(RemoteMarshallingTest, RelationsRequestSerialization) {
+ clangd::RelationsRequest Request;
+ Request.Subjects.insert(
+ llvm::cantFail(SymbolID::fromStr("0000000000000001")));
+ Request.Subjects.insert(
+ llvm::cantFail(SymbolID::fromStr("0000000000000002")));
+
+ Request.Limit = 9000;
+ Request.Predicate = RelationKind::BaseOf;
+
+ Marshaller ProtobufMarshaller(testPath("remote/"), testPath("local/"));
+
+ auto Serialized = ProtobufMarshaller.toProtobuf(Request);
+ EXPECT_EQ(static_cast<unsigned>(Serialized.subjects_size()),
+ Request.Subjects.size());
+ EXPECT_EQ(Serialized.limit(), Request.Limit);
+ EXPECT_EQ(static_cast<RelationKind>(Serialized.predicate()),
+ Request.Predicate);
+ auto Deserialized = ProtobufMarshaller.fromProtobuf(&Serialized);
+ ASSERT_TRUE(bool(Deserialized));
+ EXPECT_EQ(Deserialized->Subjects, Request.Subjects);
+ ASSERT_TRUE(Deserialized->Limit);
+ EXPECT_EQ(*Deserialized->Limit, Request.Limit);
+ EXPECT_EQ(Deserialized->Predicate, Request.Predicate);
+}
+
+TEST(RemoteMarshallingTest, RelationsRequestFailingSerialization) {
+ RelationsRequest Serialized;
+ Serialized.add_subjects("ZZZZZZZZZZZZZZZZ");
+ Marshaller ProtobufMarshaller(testPath("remote/"), testPath("local/"));
+ auto Deserialized = ProtobufMarshaller.fromProtobuf(&Serialized);
+ EXPECT_FALSE(Deserialized);
+ llvm::consumeError(Deserialized.takeError());
+}
+
+TEST(RemoteMarshallingTest, RelationsSerializion) {
+ llvm::BumpPtrAllocator Arena;
+ llvm::UniqueStringSaver Strings(Arena);
+
+ clangd::Symbol Sym = createSymbol("remote/", Strings);
+ SymbolID ID = llvm::cantFail(SymbolID::fromStr("0000000000000002"));
+ Marshaller ProtobufMarshaller(testPath("remote/"), testPath("local/"));
+ auto Serialized = ProtobufMarshaller.toProtobuf(ID, Sym);
+ auto Deserialized = ProtobufMarshaller.fromProtobuf(*Serialized);
+ ASSERT_TRUE(Deserialized);
+ EXPECT_THAT(Deserialized->first, ID);
+ EXPECT_THAT(Deserialized->second.ID, Sym.ID);
+}
+
TEST(RemoteMarshallingTest, RelativePathToURITranslation) {
Marshaller ProtobufMarshaller(/*RemoteIndexRoot=*/"",
/*LocalIndexRoot=*/testPath("home/project/"));