Skip to content

Commit 8c68de2

Browse files
committed
[clangd] Extend YAML Serialization
Reviewers: sammccall Reviewed By: sammccall Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits Tags: #clang-tools-extra, #clang Differential Revision: https://reviews.llvm.org/D77938
1 parent bef6e67 commit 8c68de2

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

clang-tools-extra/clangd/index/YAMLSerialization.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ struct VariantEntry {
4141
llvm::Optional<clang::clangd::Symbol> Symbol;
4242
llvm::Optional<RefBundle> Refs;
4343
llvm::Optional<clang::clangd::Relation> Relation;
44+
llvm::Optional<clang::clangd::IncludeGraphNode> Source;
45+
llvm::Optional<clang::tooling::CompileCommand> Cmd;
4446
};
4547
// A class helps YAML to serialize the 32-bit encoded position (Line&Column),
4648
// as YAMLIO can't directly map bitfields.
@@ -49,10 +51,16 @@ struct YPosition {
4951
uint32_t Column;
5052
};
5153

54+
// avoid ODR violation of specialization for non-owned CompileCommand
55+
struct CompileCommandYAML : clang::tooling::CompileCommand {};
56+
5257
} // namespace
5358
namespace llvm {
5459
namespace yaml {
5560

61+
using clang::clangd::FileDigest;
62+
using clang::clangd::IncludeGraph;
63+
using clang::clangd::IncludeGraphNode;
5664
using clang::clangd::Ref;
5765
using clang::clangd::RefKind;
5866
using clang::clangd::Relation;
@@ -65,6 +73,7 @@ using clang::index::SymbolInfo;
6573
using clang::index::SymbolKind;
6674
using clang::index::SymbolLanguage;
6775
using clang::index::SymbolRole;
76+
using clang::tooling::CompileCommand;
6877

6978
// Helper to (de)serialize the SymbolID. We serialize it as a hex string.
7079
struct NormalizedSymbolID {
@@ -308,6 +317,59 @@ template <> struct MappingTraits<Relation> {
308317
}
309318
};
310319

320+
struct NormalizedSourceFlag {
321+
NormalizedSourceFlag(IO &) {}
322+
NormalizedSourceFlag(IO &, IncludeGraphNode::SourceFlag O) {
323+
Flag = static_cast<uint8_t>(O);
324+
}
325+
326+
IncludeGraphNode::SourceFlag denormalize(IO &) {
327+
return static_cast<IncludeGraphNode::SourceFlag>(Flag);
328+
}
329+
330+
uint8_t Flag = 0;
331+
};
332+
333+
struct NormalizedFileDigest {
334+
NormalizedFileDigest(IO &) {}
335+
NormalizedFileDigest(IO &, const FileDigest &Digest) {
336+
HexString = llvm::toHex(Digest);
337+
}
338+
339+
FileDigest denormalize(IO &I) {
340+
FileDigest Digest;
341+
if (HexString.size() == Digest.size() * 2 &&
342+
llvm::all_of(HexString, llvm::isHexDigit)) {
343+
memcpy(Digest.data(), llvm::fromHex(HexString).data(), Digest.size());
344+
} else {
345+
I.setError(std::string("Bad hex file digest: ") + HexString);
346+
}
347+
return Digest;
348+
}
349+
350+
std::string HexString;
351+
};
352+
353+
template <> struct MappingTraits<IncludeGraphNode> {
354+
static void mapping(IO &IO, IncludeGraphNode &Node) {
355+
IO.mapRequired("URI", Node.URI);
356+
MappingNormalization<NormalizedSourceFlag, IncludeGraphNode::SourceFlag>
357+
NSourceFlag(IO, Node.Flags);
358+
IO.mapRequired("Flags", NSourceFlag->Flag);
359+
MappingNormalization<NormalizedFileDigest, FileDigest> NDigest(IO,
360+
Node.Digest);
361+
IO.mapRequired("Digest", NDigest->HexString);
362+
IO.mapRequired("DirectIncludes", Node.DirectIncludes);
363+
}
364+
};
365+
366+
template <> struct MappingTraits<CompileCommandYAML> {
367+
static void mapping(IO &IO, CompileCommandYAML &Cmd) {
368+
IO.mapRequired("Directory", Cmd.Directory);
369+
IO.mapRequired("CommandLine", Cmd.CommandLine);
370+
}
371+
};
372+
311373
template <> struct MappingTraits<VariantEntry> {
312374
static void mapping(IO &IO, VariantEntry &Variant) {
313375
if (IO.mapTag("!Symbol", Variant.Symbol.hasValue())) {
@@ -322,6 +384,15 @@ template <> struct MappingTraits<VariantEntry> {
322384
if (!IO.outputting())
323385
Variant.Relation.emplace();
324386
MappingTraits<Relation>::mapping(IO, *Variant.Relation);
387+
} else if (IO.mapTag("!Source", Variant.Source.hasValue())) {
388+
if (!IO.outputting())
389+
Variant.Source.emplace();
390+
MappingTraits<IncludeGraphNode>::mapping(IO, *Variant.Source);
391+
} else if (IO.mapTag("!Cmd", Variant.Cmd.hasValue())) {
392+
if (!IO.outputting())
393+
Variant.Cmd.emplace();
394+
MappingTraits<CompileCommandYAML>::mapping(
395+
IO, static_cast<CompileCommandYAML &>(*Variant.Cmd));
325396
}
326397
}
327398
};
@@ -351,6 +422,18 @@ void writeYAML(const IndexFileOut &O, llvm::raw_ostream &OS) {
351422
Entry.Relation = R;
352423
Yout << Entry;
353424
}
425+
if (O.Sources) {
426+
for (const auto &Source : *O.Sources) {
427+
VariantEntry Entry;
428+
Entry.Source = Source.getValue();
429+
Yout << Entry;
430+
}
431+
}
432+
if (O.Cmd) {
433+
VariantEntry Entry;
434+
Entry.Cmd = *O.Cmd;
435+
Yout << Entry;
436+
}
354437
}
355438

356439
llvm::Expected<IndexFileIn> readYAML(llvm::StringRef Data) {
@@ -361,6 +444,8 @@ llvm::Expected<IndexFileIn> readYAML(llvm::StringRef Data) {
361444
Arena; // store the underlying data of Position::FileURI.
362445
llvm::UniqueStringSaver Strings(Arena);
363446
llvm::yaml::Input Yin(Data, &Strings);
447+
IncludeGraph Sources;
448+
llvm::Optional<tooling::CompileCommand> Cmd;
364449
while (Yin.setCurrentDocument()) {
365450
llvm::yaml::EmptyContext Ctx;
366451
VariantEntry Variant;
@@ -375,13 +460,27 @@ llvm::Expected<IndexFileIn> readYAML(llvm::StringRef Data) {
375460
Refs.insert(Variant.Refs->first, Ref);
376461
if (Variant.Relation)
377462
Relations.insert(*Variant.Relation);
463+
if (Variant.Source) {
464+
auto &IGN = Variant.Source.getValue();
465+
auto Entry = Sources.try_emplace(IGN.URI).first;
466+
Entry->getValue() = std::move(IGN);
467+
// Fixup refs to refer to map keys which will live on
468+
Entry->getValue().URI = Entry->getKey();
469+
for (auto &Include : Entry->getValue().DirectIncludes)
470+
Include = Sources.try_emplace(Include).first->getKey();
471+
}
472+
if (Variant.Cmd)
473+
Cmd = *Variant.Cmd;
378474
Yin.nextDocument();
379475
}
380476

381477
IndexFileIn Result;
382478
Result.Symbols.emplace(std::move(Symbols).build());
383479
Result.Refs.emplace(std::move(Refs).build());
384480
Result.Relations.emplace(std::move(Relations).build());
481+
if (Sources.size())
482+
Result.Sources = std::move(Sources);
483+
Result.Cmd = std::move(Cmd);
385484
return std::move(Result);
386485
}
387486

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
using ::testing::_;
1818
using ::testing::AllOf;
19+
using ::testing::ElementsAre;
1920
using ::testing::Pair;
2021
using ::testing::UnorderedElementsAre;
2122
using ::testing::UnorderedElementsAreArray;
@@ -91,6 +92,20 @@ Predicate: 0
9192
Object:
9293
ID: 6512AEC512EA3A2D
9394
...
95+
--- !Cmd
96+
Directory: 'testdir'
97+
CommandLine:
98+
- 'cmd1'
99+
- 'cmd2'
100+
...
101+
--- !Source
102+
URI: 'file:///path/source1.cpp'
103+
Flags: 1
104+
Digest: EED8F5EAF25C453C
105+
DirectIncludes:
106+
- 'file:///path/inc1.h'
107+
- 'file:///path/inc2.h'
108+
...
94109
)";
95110

96111
MATCHER_P(ID, I, "") { return arg.ID == cantFail(SymbolID::fromStr(I)); }
@@ -152,6 +167,21 @@ TEST(SerializationTest, YAMLConversions) {
152167
EXPECT_THAT(
153168
*ParsedYAML->Relations,
154169
UnorderedElementsAre(Relation{Base, RelationKind::BaseOf, Derived}));
170+
171+
ASSERT_TRUE(bool(ParsedYAML->Cmd));
172+
auto &Cmd = *ParsedYAML->Cmd;
173+
ASSERT_EQ(Cmd.Directory, "testdir");
174+
EXPECT_THAT(Cmd.CommandLine, ElementsAre("cmd1", "cmd2"));
175+
176+
ASSERT_TRUE(bool(ParsedYAML->Sources));
177+
const auto *URI = "file:///path/source1.cpp";
178+
ASSERT_TRUE(ParsedYAML->Sources->count(URI));
179+
auto IGNDeserialized = ParsedYAML->Sources->lookup(URI);
180+
EXPECT_EQ(llvm::toHex(IGNDeserialized.Digest), "EED8F5EAF25C453C");
181+
EXPECT_THAT(IGNDeserialized.DirectIncludes,
182+
ElementsAre("file:///path/inc1.h", "file:///path/inc2.h"));
183+
EXPECT_EQ(IGNDeserialized.URI, URI);
184+
EXPECT_EQ(IGNDeserialized.Flags, IncludeGraphNode::SourceFlag(1));
155185
}
156186

157187
std::vector<std::string> YAMLFromSymbols(const SymbolSlab &Slab) {

0 commit comments

Comments
 (0)