[docs] Add LICENSE.txt to the root of the mono-repo
[llvm-project.git] / clang-tools-extra / clangd / index / YAMLSerialization.cpp
blob1ac74338298a8c86749609df27c7adcfa650042e
1 //===-- YAMLSerialization.cpp ------------------------------------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // A YAML index file is a sequence of tagged entries.
10 // Each entry either encodes a Symbol or the list of references to a symbol
11 // (a "ref bundle").
13 //===----------------------------------------------------------------------===//
15 #include "Headers.h"
16 #include "index/Ref.h"
17 #include "index/Relation.h"
18 #include "index/Serialization.h"
19 #include "index/Symbol.h"
20 #include "index/SymbolLocation.h"
21 #include "index/SymbolOrigin.h"
22 #include "clang/Tooling/CompilationDatabase.h"
23 #include "llvm/ADT/Optional.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/Support/Allocator.h"
26 #include "llvm/Support/StringSaver.h"
27 #include "llvm/Support/YAMLTraits.h"
28 #include "llvm/Support/raw_ostream.h"
29 #include <cstdint>
31 LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Symbol::IncludeHeaderWithReferences)
32 LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Ref)
34 namespace {
35 using RefBundle =
36 std::pair<clang::clangd::SymbolID, std::vector<clang::clangd::Ref>>;
37 // This is a pale imitation of std::variant<Symbol, RefBundle, Relation>
38 struct VariantEntry {
39 llvm::Optional<clang::clangd::Symbol> Symbol;
40 llvm::Optional<RefBundle> Refs;
41 llvm::Optional<clang::clangd::Relation> Relation;
42 llvm::Optional<clang::clangd::IncludeGraphNode> Source;
43 llvm::Optional<clang::tooling::CompileCommand> Cmd;
45 // A class helps YAML to serialize the 32-bit encoded position (Line&Column),
46 // as YAMLIO can't directly map bitfields.
47 struct YPosition {
48 uint32_t Line;
49 uint32_t Column;
52 // avoid ODR violation of specialization for non-owned CompileCommand
53 struct CompileCommandYAML : clang::tooling::CompileCommand {};
55 } // namespace
56 namespace llvm {
57 namespace yaml {
59 using clang::clangd::FileDigest;
60 using clang::clangd::IncludeGraph;
61 using clang::clangd::IncludeGraphNode;
62 using clang::clangd::Ref;
63 using clang::clangd::RefKind;
64 using clang::clangd::Relation;
65 using clang::clangd::RelationKind;
66 using clang::clangd::Symbol;
67 using clang::clangd::SymbolID;
68 using clang::clangd::SymbolLocation;
69 using clang::index::SymbolInfo;
70 using clang::index::SymbolKind;
71 using clang::index::SymbolLanguage;
72 using clang::tooling::CompileCommand;
74 // Helper to (de)serialize the SymbolID. We serialize it as a hex string.
75 struct NormalizedSymbolID {
76 NormalizedSymbolID(IO &) {}
77 NormalizedSymbolID(IO &, const SymbolID &ID) {
78 llvm::raw_string_ostream OS(HexString);
79 OS << ID;
82 SymbolID denormalize(IO &I) {
83 auto ID = SymbolID::fromStr(HexString);
84 if (!ID) {
85 I.setError(llvm::toString(ID.takeError()));
86 return SymbolID();
88 return *ID;
91 std::string HexString;
94 struct NormalizedSymbolFlag {
95 NormalizedSymbolFlag(IO &) {}
96 NormalizedSymbolFlag(IO &, Symbol::SymbolFlag F) {
97 Flag = static_cast<uint8_t>(F);
100 Symbol::SymbolFlag denormalize(IO &) {
101 return static_cast<Symbol::SymbolFlag>(Flag);
104 uint8_t Flag = 0;
107 template <> struct MappingTraits<YPosition> {
108 static void mapping(IO &IO, YPosition &Value) {
109 IO.mapRequired("Line", Value.Line);
110 IO.mapRequired("Column", Value.Column);
114 struct NormalizedPosition {
115 using Position = clang::clangd::SymbolLocation::Position;
116 NormalizedPosition(IO &) {}
117 NormalizedPosition(IO &, const Position &Pos) {
118 P.Line = Pos.line();
119 P.Column = Pos.column();
122 Position denormalize(IO &) {
123 Position Pos;
124 Pos.setLine(P.Line);
125 Pos.setColumn(P.Column);
126 return Pos;
128 YPosition P;
131 struct NormalizedFileURI {
132 NormalizedFileURI(IO &) {}
133 NormalizedFileURI(IO &, const char *FileURI) { URI = FileURI; }
135 const char *denormalize(IO &IO) {
136 assert(IO.getContext() &&
137 "Expecting an UniqueStringSaver to allocate data");
138 return static_cast<llvm::UniqueStringSaver *>(IO.getContext())
139 ->save(URI)
140 .data();
143 std::string URI;
146 template <> struct MappingTraits<SymbolLocation> {
147 static void mapping(IO &IO, SymbolLocation &Value) {
148 MappingNormalization<NormalizedFileURI, const char *> NFile(IO,
149 Value.FileURI);
150 IO.mapRequired("FileURI", NFile->URI);
151 MappingNormalization<NormalizedPosition, SymbolLocation::Position> NStart(
152 IO, Value.Start);
153 IO.mapRequired("Start", NStart->P);
154 MappingNormalization<NormalizedPosition, SymbolLocation::Position> NEnd(
155 IO, Value.End);
156 IO.mapRequired("End", NEnd->P);
160 template <> struct MappingTraits<SymbolInfo> {
161 static void mapping(IO &IO, SymbolInfo &SymInfo) {
162 // FIXME: expose other fields?
163 IO.mapRequired("Kind", SymInfo.Kind);
164 IO.mapRequired("Lang", SymInfo.Lang);
168 template <>
169 struct MappingTraits<clang::clangd::Symbol::IncludeHeaderWithReferences> {
170 static void mapping(IO &IO,
171 clang::clangd::Symbol::IncludeHeaderWithReferences &Inc) {
172 IO.mapRequired("Header", Inc.IncludeHeader);
173 IO.mapRequired("References", Inc.References);
177 template <> struct MappingTraits<Symbol> {
178 static void mapping(IO &IO, Symbol &Sym) {
179 MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, Sym.ID);
180 MappingNormalization<NormalizedSymbolFlag, Symbol::SymbolFlag> NSymbolFlag(
181 IO, Sym.Flags);
182 IO.mapRequired("ID", NSymbolID->HexString);
183 IO.mapRequired("Name", Sym.Name);
184 IO.mapRequired("Scope", Sym.Scope);
185 IO.mapRequired("SymInfo", Sym.SymInfo);
186 IO.mapOptional("CanonicalDeclaration", Sym.CanonicalDeclaration,
187 SymbolLocation());
188 IO.mapOptional("Definition", Sym.Definition, SymbolLocation());
189 IO.mapOptional("References", Sym.References, 0u);
190 IO.mapOptional("Flags", NSymbolFlag->Flag);
191 IO.mapOptional("Signature", Sym.Signature);
192 IO.mapOptional("TemplateSpecializationArgs",
193 Sym.TemplateSpecializationArgs);
194 IO.mapOptional("CompletionSnippetSuffix", Sym.CompletionSnippetSuffix);
195 IO.mapOptional("Documentation", Sym.Documentation);
196 IO.mapOptional("ReturnType", Sym.ReturnType);
197 IO.mapOptional("Type", Sym.Type);
198 IO.mapOptional("IncludeHeaders", Sym.IncludeHeaders);
202 template <> struct ScalarEnumerationTraits<SymbolLanguage> {
203 static void enumeration(IO &IO, SymbolLanguage &Value) {
204 IO.enumCase(Value, "C", SymbolLanguage::C);
205 IO.enumCase(Value, "Cpp", SymbolLanguage::CXX);
206 IO.enumCase(Value, "ObjC", SymbolLanguage::ObjC);
207 IO.enumCase(Value, "Swift", SymbolLanguage::Swift);
211 template <> struct ScalarEnumerationTraits<SymbolKind> {
212 static void enumeration(IO &IO, SymbolKind &Value) {
213 #define DEFINE_ENUM(name) IO.enumCase(Value, #name, SymbolKind::name)
215 DEFINE_ENUM(Unknown);
216 DEFINE_ENUM(Function);
217 DEFINE_ENUM(Module);
218 DEFINE_ENUM(Namespace);
219 DEFINE_ENUM(NamespaceAlias);
220 DEFINE_ENUM(Macro);
221 DEFINE_ENUM(Enum);
222 DEFINE_ENUM(Struct);
223 DEFINE_ENUM(Class);
224 DEFINE_ENUM(Protocol);
225 DEFINE_ENUM(Extension);
226 DEFINE_ENUM(Union);
227 DEFINE_ENUM(TypeAlias);
228 DEFINE_ENUM(Function);
229 DEFINE_ENUM(Variable);
230 DEFINE_ENUM(Field);
231 DEFINE_ENUM(EnumConstant);
232 DEFINE_ENUM(InstanceMethod);
233 DEFINE_ENUM(ClassMethod);
234 DEFINE_ENUM(StaticMethod);
235 DEFINE_ENUM(InstanceProperty);
236 DEFINE_ENUM(ClassProperty);
237 DEFINE_ENUM(StaticProperty);
238 DEFINE_ENUM(Constructor);
239 DEFINE_ENUM(Destructor);
240 DEFINE_ENUM(ConversionFunction);
241 DEFINE_ENUM(Parameter);
242 DEFINE_ENUM(Using);
244 #undef DEFINE_ENUM
248 template <> struct MappingTraits<RefBundle> {
249 static void mapping(IO &IO, RefBundle &Refs) {
250 MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO,
251 Refs.first);
252 IO.mapRequired("ID", NSymbolID->HexString);
253 IO.mapRequired("References", Refs.second);
257 struct NormalizedRefKind {
258 NormalizedRefKind(IO &) {}
259 NormalizedRefKind(IO &, RefKind O) { Kind = static_cast<uint8_t>(O); }
261 RefKind denormalize(IO &) { return static_cast<RefKind>(Kind); }
263 uint8_t Kind = 0;
266 template <> struct MappingTraits<Ref> {
267 static void mapping(IO &IO, Ref &R) {
268 MappingNormalization<NormalizedRefKind, RefKind> NKind(IO, R.Kind);
269 IO.mapRequired("Kind", NKind->Kind);
270 IO.mapRequired("Location", R.Location);
274 struct NormalizedSymbolRole {
275 NormalizedSymbolRole(IO &) {}
276 NormalizedSymbolRole(IO &IO, RelationKind R) {
277 Kind = static_cast<uint8_t>(R);
280 RelationKind denormalize(IO &IO) { return static_cast<RelationKind>(Kind); }
282 uint8_t Kind = 0;
285 template <> struct MappingTraits<SymbolID> {
286 static void mapping(IO &IO, SymbolID &ID) {
287 MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, ID);
288 IO.mapRequired("ID", NSymbolID->HexString);
292 template <> struct MappingTraits<Relation> {
293 static void mapping(IO &IO, Relation &Relation) {
294 MappingNormalization<NormalizedSymbolRole, RelationKind> NRole(
295 IO, Relation.Predicate);
296 IO.mapRequired("Subject", Relation.Subject);
297 IO.mapRequired("Predicate", NRole->Kind);
298 IO.mapRequired("Object", Relation.Object);
302 struct NormalizedSourceFlag {
303 NormalizedSourceFlag(IO &) {}
304 NormalizedSourceFlag(IO &, IncludeGraphNode::SourceFlag O) {
305 Flag = static_cast<uint8_t>(O);
308 IncludeGraphNode::SourceFlag denormalize(IO &) {
309 return static_cast<IncludeGraphNode::SourceFlag>(Flag);
312 uint8_t Flag = 0;
315 struct NormalizedFileDigest {
316 NormalizedFileDigest(IO &) {}
317 NormalizedFileDigest(IO &, const FileDigest &Digest) {
318 HexString = llvm::toHex(Digest);
321 FileDigest denormalize(IO &I) {
322 FileDigest Digest;
323 if (HexString.size() == Digest.size() * 2 &&
324 llvm::all_of(HexString, llvm::isHexDigit)) {
325 memcpy(Digest.data(), llvm::fromHex(HexString).data(), Digest.size());
326 } else {
327 I.setError(std::string("Bad hex file digest: ") + HexString);
329 return Digest;
332 std::string HexString;
335 template <> struct MappingTraits<IncludeGraphNode> {
336 static void mapping(IO &IO, IncludeGraphNode &Node) {
337 IO.mapRequired("URI", Node.URI);
338 MappingNormalization<NormalizedSourceFlag, IncludeGraphNode::SourceFlag>
339 NSourceFlag(IO, Node.Flags);
340 IO.mapRequired("Flags", NSourceFlag->Flag);
341 MappingNormalization<NormalizedFileDigest, FileDigest> NDigest(IO,
342 Node.Digest);
343 IO.mapRequired("Digest", NDigest->HexString);
344 IO.mapRequired("DirectIncludes", Node.DirectIncludes);
348 template <> struct MappingTraits<CompileCommandYAML> {
349 static void mapping(IO &IO, CompileCommandYAML &Cmd) {
350 IO.mapRequired("Directory", Cmd.Directory);
351 IO.mapRequired("CommandLine", Cmd.CommandLine);
355 template <> struct MappingTraits<VariantEntry> {
356 static void mapping(IO &IO, VariantEntry &Variant) {
357 if (IO.mapTag("!Symbol", Variant.Symbol.has_value())) {
358 if (!IO.outputting())
359 Variant.Symbol.emplace();
360 MappingTraits<Symbol>::mapping(IO, *Variant.Symbol);
361 } else if (IO.mapTag("!Refs", Variant.Refs.has_value())) {
362 if (!IO.outputting())
363 Variant.Refs.emplace();
364 MappingTraits<RefBundle>::mapping(IO, *Variant.Refs);
365 } else if (IO.mapTag("!Relations", Variant.Relation.has_value())) {
366 if (!IO.outputting())
367 Variant.Relation.emplace();
368 MappingTraits<Relation>::mapping(IO, *Variant.Relation);
369 } else if (IO.mapTag("!Source", Variant.Source.has_value())) {
370 if (!IO.outputting())
371 Variant.Source.emplace();
372 MappingTraits<IncludeGraphNode>::mapping(IO, *Variant.Source);
373 } else if (IO.mapTag("!Cmd", Variant.Cmd.has_value())) {
374 if (!IO.outputting())
375 Variant.Cmd.emplace();
376 MappingTraits<CompileCommandYAML>::mapping(
377 IO, static_cast<CompileCommandYAML &>(*Variant.Cmd));
382 } // namespace yaml
383 } // namespace llvm
385 namespace clang {
386 namespace clangd {
388 void writeYAML(const IndexFileOut &O, llvm::raw_ostream &OS) {
389 llvm::yaml::Output Yout(OS);
390 for (const auto &Sym : *O.Symbols) {
391 VariantEntry Entry;
392 Entry.Symbol = Sym;
393 Yout << Entry;
395 if (O.Refs)
396 for (auto &Sym : *O.Refs) {
397 VariantEntry Entry;
398 Entry.Refs = Sym;
399 Yout << Entry;
401 if (O.Relations)
402 for (auto &R : *O.Relations) {
403 VariantEntry Entry;
404 Entry.Relation = R;
405 Yout << Entry;
407 if (O.Sources) {
408 for (const auto &Source : *O.Sources) {
409 VariantEntry Entry;
410 Entry.Source = Source.getValue();
411 Yout << Entry;
414 if (O.Cmd) {
415 VariantEntry Entry;
416 Entry.Cmd = *O.Cmd;
417 Yout << Entry;
421 llvm::Expected<IndexFileIn> readYAML(llvm::StringRef Data,
422 SymbolOrigin Origin) {
423 SymbolSlab::Builder Symbols;
424 RefSlab::Builder Refs;
425 RelationSlab::Builder Relations;
426 llvm::BumpPtrAllocator
427 Arena; // store the underlying data of Position::FileURI.
428 llvm::UniqueStringSaver Strings(Arena);
429 llvm::yaml::Input Yin(Data, &Strings);
430 IncludeGraph Sources;
431 llvm::Optional<tooling::CompileCommand> Cmd;
432 while (Yin.setCurrentDocument()) {
433 llvm::yaml::EmptyContext Ctx;
434 VariantEntry Variant;
435 yamlize(Yin, Variant, true, Ctx);
436 if (Yin.error())
437 return llvm::errorCodeToError(Yin.error());
439 if (Variant.Symbol) {
440 Variant.Symbol->Origin = Origin;
441 Symbols.insert(*Variant.Symbol);
443 if (Variant.Refs)
444 for (const auto &Ref : Variant.Refs->second)
445 Refs.insert(Variant.Refs->first, Ref);
446 if (Variant.Relation)
447 Relations.insert(*Variant.Relation);
448 if (Variant.Source) {
449 auto &IGN = *Variant.Source;
450 auto Entry = Sources.try_emplace(IGN.URI).first;
451 Entry->getValue() = std::move(IGN);
452 // Fixup refs to refer to map keys which will live on
453 Entry->getValue().URI = Entry->getKey();
454 for (auto &Include : Entry->getValue().DirectIncludes)
455 Include = Sources.try_emplace(Include).first->getKey();
457 if (Variant.Cmd)
458 Cmd = *Variant.Cmd;
459 Yin.nextDocument();
462 IndexFileIn Result;
463 Result.Symbols.emplace(std::move(Symbols).build());
464 Result.Refs.emplace(std::move(Refs).build());
465 Result.Relations.emplace(std::move(Relations).build());
466 if (Sources.size())
467 Result.Sources = std::move(Sources);
468 Result.Cmd = std::move(Cmd);
469 return std::move(Result);
472 std::string toYAML(const Symbol &S) {
473 std::string Buf;
475 llvm::raw_string_ostream OS(Buf);
476 llvm::yaml::Output Yout(OS);
477 Symbol Sym = S; // copy: Yout<< requires mutability.
478 Yout << Sym;
480 return Buf;
483 std::string toYAML(const std::pair<SymbolID, llvm::ArrayRef<Ref>> &Data) {
484 RefBundle Refs = {Data.first, Data.second};
485 std::string Buf;
487 llvm::raw_string_ostream OS(Buf);
488 llvm::yaml::Output Yout(OS);
489 Yout << Refs;
491 return Buf;
494 std::string toYAML(const Relation &R) {
495 std::string Buf;
497 llvm::raw_string_ostream OS(Buf);
498 llvm::yaml::Output Yout(OS);
499 Relation Rel = R; // copy: Yout<< requires mutability.
500 Yout << Rel;
502 return Buf;
505 std::string toYAML(const Ref &R) {
506 std::string Buf;
508 llvm::raw_string_ostream OS(Buf);
509 llvm::yaml::Output Yout(OS);
510 Ref Reference = R; // copy: Yout<< requires mutability.
511 Yout << Reference;
513 return Buf;
516 } // namespace clangd
517 } // namespace clang