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").
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "Index.h"
16 #include "Relation.h"
17 #include "Serialization.h"
18 #include "SymbolLocation.h"
19 #include "SymbolOrigin.h"
20 #include "dex/Dex.h"
21 #include "support/Trace.h"
22 #include "llvm/ADT/Optional.h"
23 #include "llvm/ADT/SmallVector.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/Support/Allocator.h"
26 #include "llvm/Support/Errc.h"
27 #include "llvm/Support/MemoryBuffer.h"
28 #include "llvm/Support/StringSaver.h"
29 #include "llvm/Support/YAMLTraits.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include <cstdint>
32 
33 LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Symbol::IncludeHeaderWithReferences)
34 LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Ref)
35 
36 namespace {
37 using RefBundle =
38     std::pair<clang::clangd::SymbolID, std::vector<clang::clangd::Ref>>;
39 // This is a pale imitation of std::variant<Symbol, RefBundle, Relation>
40 struct VariantEntry {
41   llvm::Optional<clang::clangd::Symbol> Symbol;
42   llvm::Optional<RefBundle> Refs;
43   llvm::Optional<clang::clangd::Relation> Relation;
44   llvm::Optional<clang::clangd::IncludeGraphNode> Source;
45   llvm::Optional<clang::tooling::CompileCommand> Cmd;
46 };
47 // A class helps YAML to serialize the 32-bit encoded position (Line&Column),
48 // as YAMLIO can't directly map bitfields.
49 struct YPosition {
50   uint32_t Line;
51   uint32_t Column;
52 };
53 
54 // avoid ODR violation of specialization for non-owned CompileCommand
55 struct CompileCommandYAML : clang::tooling::CompileCommand {};
56 
57 } // namespace
58 namespace llvm {
59 namespace yaml {
60 
61 using clang::clangd::FileDigest;
62 using clang::clangd::IncludeGraph;
63 using clang::clangd::IncludeGraphNode;
64 using clang::clangd::Ref;
65 using clang::clangd::RefKind;
66 using clang::clangd::Relation;
67 using clang::clangd::RelationKind;
68 using clang::clangd::Symbol;
69 using clang::clangd::SymbolID;
70 using clang::clangd::SymbolLocation;
71 using clang::clangd::SymbolOrigin;
72 using clang::index::SymbolInfo;
73 using clang::index::SymbolKind;
74 using clang::index::SymbolLanguage;
75 using clang::index::SymbolRole;
76 using clang::tooling::CompileCommand;
77 
78 // Helper to (de)serialize the SymbolID. We serialize it as a hex string.
79 struct NormalizedSymbolID {
NormalizedSymbolIDllvm::yaml::NormalizedSymbolID80   NormalizedSymbolID(IO &) {}
NormalizedSymbolIDllvm::yaml::NormalizedSymbolID81   NormalizedSymbolID(IO &, const SymbolID &ID) {
82     llvm::raw_string_ostream OS(HexString);
83     OS << ID;
84   }
85 
denormalizellvm::yaml::NormalizedSymbolID86   SymbolID denormalize(IO &I) {
87     auto ID = SymbolID::fromStr(HexString);
88     if (!ID) {
89       I.setError(llvm::toString(ID.takeError()));
90       return SymbolID();
91     }
92     return *ID;
93   }
94 
95   std::string HexString;
96 };
97 
98 struct NormalizedSymbolFlag {
NormalizedSymbolFlagllvm::yaml::NormalizedSymbolFlag99   NormalizedSymbolFlag(IO &) {}
NormalizedSymbolFlagllvm::yaml::NormalizedSymbolFlag100   NormalizedSymbolFlag(IO &, Symbol::SymbolFlag F) {
101     Flag = static_cast<uint8_t>(F);
102   }
103 
denormalizellvm::yaml::NormalizedSymbolFlag104   Symbol::SymbolFlag denormalize(IO &) {
105     return static_cast<Symbol::SymbolFlag>(Flag);
106   }
107 
108   uint8_t Flag = 0;
109 };
110 
111 struct NormalizedSymbolOrigin {
NormalizedSymbolOriginllvm::yaml::NormalizedSymbolOrigin112   NormalizedSymbolOrigin(IO &) {}
NormalizedSymbolOriginllvm::yaml::NormalizedSymbolOrigin113   NormalizedSymbolOrigin(IO &, SymbolOrigin O) {
114     Origin = static_cast<uint8_t>(O);
115   }
116 
denormalizellvm::yaml::NormalizedSymbolOrigin117   SymbolOrigin denormalize(IO &) { return static_cast<SymbolOrigin>(Origin); }
118 
119   uint8_t Origin = 0;
120 };
121 
122 template <> struct MappingTraits<YPosition> {
mappingllvm::yaml::MappingTraits123   static void mapping(IO &IO, YPosition &Value) {
124     IO.mapRequired("Line", Value.Line);
125     IO.mapRequired("Column", Value.Column);
126   }
127 };
128 
129 struct NormalizedPosition {
130   using Position = clang::clangd::SymbolLocation::Position;
NormalizedPositionllvm::yaml::NormalizedPosition131   NormalizedPosition(IO &) {}
NormalizedPositionllvm::yaml::NormalizedPosition132   NormalizedPosition(IO &, const Position &Pos) {
133     P.Line = Pos.line();
134     P.Column = Pos.column();
135   }
136 
denormalizellvm::yaml::NormalizedPosition137   Position denormalize(IO &) {
138     Position Pos;
139     Pos.setLine(P.Line);
140     Pos.setColumn(P.Column);
141     return Pos;
142   }
143   YPosition P;
144 };
145 
146 struct NormalizedFileURI {
NormalizedFileURIllvm::yaml::NormalizedFileURI147   NormalizedFileURI(IO &) {}
NormalizedFileURIllvm::yaml::NormalizedFileURI148   NormalizedFileURI(IO &, const char *FileURI) { URI = FileURI; }
149 
denormalizellvm::yaml::NormalizedFileURI150   const char *denormalize(IO &IO) {
151     assert(IO.getContext() &&
152            "Expecting an UniqueStringSaver to allocate data");
153     return static_cast<llvm::UniqueStringSaver *>(IO.getContext())
154         ->save(URI)
155         .data();
156   }
157 
158   std::string URI;
159 };
160 
161 template <> struct MappingTraits<SymbolLocation> {
mappingllvm::yaml::MappingTraits162   static void mapping(IO &IO, SymbolLocation &Value) {
163     MappingNormalization<NormalizedFileURI, const char *> NFile(IO,
164                                                                 Value.FileURI);
165     IO.mapRequired("FileURI", NFile->URI);
166     MappingNormalization<NormalizedPosition, SymbolLocation::Position> NStart(
167         IO, Value.Start);
168     IO.mapRequired("Start", NStart->P);
169     MappingNormalization<NormalizedPosition, SymbolLocation::Position> NEnd(
170         IO, Value.End);
171     IO.mapRequired("End", NEnd->P);
172   }
173 };
174 
175 template <> struct MappingTraits<SymbolInfo> {
mappingllvm::yaml::MappingTraits176   static void mapping(IO &io, SymbolInfo &SymInfo) {
177     // FIXME: expose other fields?
178     io.mapRequired("Kind", SymInfo.Kind);
179     io.mapRequired("Lang", SymInfo.Lang);
180   }
181 };
182 
183 template <>
184 struct MappingTraits<clang::clangd::Symbol::IncludeHeaderWithReferences> {
mappingllvm::yaml::MappingTraits185   static void mapping(IO &io,
186                       clang::clangd::Symbol::IncludeHeaderWithReferences &Inc) {
187     io.mapRequired("Header", Inc.IncludeHeader);
188     io.mapRequired("References", Inc.References);
189   }
190 };
191 
192 template <> struct MappingTraits<Symbol> {
mappingllvm::yaml::MappingTraits193   static void mapping(IO &IO, Symbol &Sym) {
194     MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, Sym.ID);
195     MappingNormalization<NormalizedSymbolFlag, Symbol::SymbolFlag> NSymbolFlag(
196         IO, Sym.Flags);
197     MappingNormalization<NormalizedSymbolOrigin, SymbolOrigin> NSymbolOrigin(
198         IO, Sym.Origin);
199     IO.mapRequired("ID", NSymbolID->HexString);
200     IO.mapRequired("Name", Sym.Name);
201     IO.mapRequired("Scope", Sym.Scope);
202     IO.mapRequired("SymInfo", Sym.SymInfo);
203     IO.mapOptional("CanonicalDeclaration", Sym.CanonicalDeclaration,
204                    SymbolLocation());
205     IO.mapOptional("Definition", Sym.Definition, SymbolLocation());
206     IO.mapOptional("References", Sym.References, 0u);
207     IO.mapOptional("Origin", NSymbolOrigin->Origin);
208     IO.mapOptional("Flags", NSymbolFlag->Flag);
209     IO.mapOptional("Signature", Sym.Signature);
210     IO.mapOptional("TemplateSpecializationArgs",
211                    Sym.TemplateSpecializationArgs);
212     IO.mapOptional("CompletionSnippetSuffix", Sym.CompletionSnippetSuffix);
213     IO.mapOptional("Documentation", Sym.Documentation);
214     IO.mapOptional("ReturnType", Sym.ReturnType);
215     IO.mapOptional("Type", Sym.Type);
216     IO.mapOptional("IncludeHeaders", Sym.IncludeHeaders);
217   }
218 };
219 
220 template <> struct ScalarEnumerationTraits<SymbolLanguage> {
enumerationllvm::yaml::ScalarEnumerationTraits221   static void enumeration(IO &IO, SymbolLanguage &Value) {
222     IO.enumCase(Value, "C", SymbolLanguage::C);
223     IO.enumCase(Value, "Cpp", SymbolLanguage::CXX);
224     IO.enumCase(Value, "ObjC", SymbolLanguage::ObjC);
225     IO.enumCase(Value, "Swift", SymbolLanguage::Swift);
226   }
227 };
228 
229 template <> struct ScalarEnumerationTraits<SymbolKind> {
enumerationllvm::yaml::ScalarEnumerationTraits230   static void enumeration(IO &IO, SymbolKind &Value) {
231 #define DEFINE_ENUM(name) IO.enumCase(Value, #name, SymbolKind::name)
232 
233     DEFINE_ENUM(Unknown);
234     DEFINE_ENUM(Function);
235     DEFINE_ENUM(Module);
236     DEFINE_ENUM(Namespace);
237     DEFINE_ENUM(NamespaceAlias);
238     DEFINE_ENUM(Macro);
239     DEFINE_ENUM(Enum);
240     DEFINE_ENUM(Struct);
241     DEFINE_ENUM(Class);
242     DEFINE_ENUM(Protocol);
243     DEFINE_ENUM(Extension);
244     DEFINE_ENUM(Union);
245     DEFINE_ENUM(TypeAlias);
246     DEFINE_ENUM(Function);
247     DEFINE_ENUM(Variable);
248     DEFINE_ENUM(Field);
249     DEFINE_ENUM(EnumConstant);
250     DEFINE_ENUM(InstanceMethod);
251     DEFINE_ENUM(ClassMethod);
252     DEFINE_ENUM(StaticMethod);
253     DEFINE_ENUM(InstanceProperty);
254     DEFINE_ENUM(ClassProperty);
255     DEFINE_ENUM(StaticProperty);
256     DEFINE_ENUM(Constructor);
257     DEFINE_ENUM(Destructor);
258     DEFINE_ENUM(ConversionFunction);
259     DEFINE_ENUM(Parameter);
260     DEFINE_ENUM(Using);
261 
262 #undef DEFINE_ENUM
263   }
264 };
265 
266 template <> struct MappingTraits<RefBundle> {
mappingllvm::yaml::MappingTraits267   static void mapping(IO &IO, RefBundle &Refs) {
268     MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO,
269                                                                  Refs.first);
270     IO.mapRequired("ID", NSymbolID->HexString);
271     IO.mapRequired("References", Refs.second);
272   }
273 };
274 
275 struct NormalizedRefKind {
NormalizedRefKindllvm::yaml::NormalizedRefKind276   NormalizedRefKind(IO &) {}
NormalizedRefKindllvm::yaml::NormalizedRefKind277   NormalizedRefKind(IO &, RefKind O) { Kind = static_cast<uint8_t>(O); }
278 
denormalizellvm::yaml::NormalizedRefKind279   RefKind denormalize(IO &) { return static_cast<RefKind>(Kind); }
280 
281   uint8_t Kind = 0;
282 };
283 
284 template <> struct MappingTraits<Ref> {
mappingllvm::yaml::MappingTraits285   static void mapping(IO &IO, Ref &R) {
286     MappingNormalization<NormalizedRefKind, RefKind> NKind(IO, R.Kind);
287     IO.mapRequired("Kind", NKind->Kind);
288     IO.mapRequired("Location", R.Location);
289   }
290 };
291 
292 struct NormalizedSymbolRole {
NormalizedSymbolRolellvm::yaml::NormalizedSymbolRole293   NormalizedSymbolRole(IO &) {}
NormalizedSymbolRolellvm::yaml::NormalizedSymbolRole294   NormalizedSymbolRole(IO &IO, RelationKind R) {
295     Kind = static_cast<uint8_t>(R);
296   }
297 
denormalizellvm::yaml::NormalizedSymbolRole298   RelationKind denormalize(IO &IO) { return static_cast<RelationKind>(Kind); }
299 
300   uint8_t Kind = 0;
301 };
302 
303 template <> struct MappingTraits<SymbolID> {
mappingllvm::yaml::MappingTraits304   static void mapping(IO &IO, SymbolID &ID) {
305     MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, ID);
306     IO.mapRequired("ID", NSymbolID->HexString);
307   }
308 };
309 
310 template <> struct MappingTraits<Relation> {
mappingllvm::yaml::MappingTraits311   static void mapping(IO &IO, Relation &Relation) {
312     MappingNormalization<NormalizedSymbolRole, RelationKind> NRole(
313         IO, Relation.Predicate);
314     IO.mapRequired("Subject", Relation.Subject);
315     IO.mapRequired("Predicate", NRole->Kind);
316     IO.mapRequired("Object", Relation.Object);
317   }
318 };
319 
320 struct NormalizedSourceFlag {
NormalizedSourceFlagllvm::yaml::NormalizedSourceFlag321   NormalizedSourceFlag(IO &) {}
NormalizedSourceFlagllvm::yaml::NormalizedSourceFlag322   NormalizedSourceFlag(IO &, IncludeGraphNode::SourceFlag O) {
323     Flag = static_cast<uint8_t>(O);
324   }
325 
denormalizellvm::yaml::NormalizedSourceFlag326   IncludeGraphNode::SourceFlag denormalize(IO &) {
327     return static_cast<IncludeGraphNode::SourceFlag>(Flag);
328   }
329 
330   uint8_t Flag = 0;
331 };
332 
333 struct NormalizedFileDigest {
NormalizedFileDigestllvm::yaml::NormalizedFileDigest334   NormalizedFileDigest(IO &) {}
NormalizedFileDigestllvm::yaml::NormalizedFileDigest335   NormalizedFileDigest(IO &, const FileDigest &Digest) {
336     HexString = llvm::toHex(Digest);
337   }
338 
denormalizellvm::yaml::NormalizedFileDigest339   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> {
mappingllvm::yaml::MappingTraits354   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> {
mappingllvm::yaml::MappingTraits367   static void mapping(IO &IO, CompileCommandYAML &Cmd) {
368     IO.mapRequired("Directory", Cmd.Directory);
369     IO.mapRequired("CommandLine", Cmd.CommandLine);
370   }
371 };
372 
373 template <> struct MappingTraits<VariantEntry> {
mappingllvm::yaml::MappingTraits374   static void mapping(IO &IO, VariantEntry &Variant) {
375     if (IO.mapTag("!Symbol", Variant.Symbol.hasValue())) {
376       if (!IO.outputting())
377         Variant.Symbol.emplace();
378       MappingTraits<Symbol>::mapping(IO, *Variant.Symbol);
379     } else if (IO.mapTag("!Refs", Variant.Refs.hasValue())) {
380       if (!IO.outputting())
381         Variant.Refs.emplace();
382       MappingTraits<RefBundle>::mapping(IO, *Variant.Refs);
383     } else if (IO.mapTag("!Relations", Variant.Relation.hasValue())) {
384       if (!IO.outputting())
385         Variant.Relation.emplace();
386       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));
396     }
397   }
398 };
399 
400 } // namespace yaml
401 } // namespace llvm
402 
403 namespace clang {
404 namespace clangd {
405 
writeYAML(const IndexFileOut & O,llvm::raw_ostream & OS)406 void writeYAML(const IndexFileOut &O, llvm::raw_ostream &OS) {
407   llvm::yaml::Output Yout(OS);
408   for (const auto &Sym : *O.Symbols) {
409     VariantEntry Entry;
410     Entry.Symbol = Sym;
411     Yout << Entry;
412   }
413   if (O.Refs)
414     for (auto &Sym : *O.Refs) {
415       VariantEntry Entry;
416       Entry.Refs = Sym;
417       Yout << Entry;
418     }
419   if (O.Relations)
420     for (auto &R : *O.Relations) {
421       VariantEntry Entry;
422       Entry.Relation = R;
423       Yout << Entry;
424     }
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   }
437 }
438 
readYAML(llvm::StringRef Data)439 llvm::Expected<IndexFileIn> readYAML(llvm::StringRef Data) {
440   SymbolSlab::Builder Symbols;
441   RefSlab::Builder Refs;
442   RelationSlab::Builder Relations;
443   llvm::BumpPtrAllocator
444       Arena; // store the underlying data of Position::FileURI.
445   llvm::UniqueStringSaver Strings(Arena);
446   llvm::yaml::Input Yin(Data, &Strings);
447   IncludeGraph Sources;
448   llvm::Optional<tooling::CompileCommand> Cmd;
449   while (Yin.setCurrentDocument()) {
450     llvm::yaml::EmptyContext Ctx;
451     VariantEntry Variant;
452     yamlize(Yin, Variant, true, Ctx);
453     if (Yin.error())
454       return llvm::errorCodeToError(Yin.error());
455 
456     if (Variant.Symbol)
457       Symbols.insert(*Variant.Symbol);
458     if (Variant.Refs)
459       for (const auto &Ref : Variant.Refs->second)
460         Refs.insert(Variant.Refs->first, Ref);
461     if (Variant.Relation)
462       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;
474     Yin.nextDocument();
475   }
476 
477   IndexFileIn Result;
478   Result.Symbols.emplace(std::move(Symbols).build());
479   Result.Refs.emplace(std::move(Refs).build());
480   Result.Relations.emplace(std::move(Relations).build());
481   if (Sources.size())
482     Result.Sources = std::move(Sources);
483   Result.Cmd = std::move(Cmd);
484   return std::move(Result);
485 }
486 
toYAML(const Symbol & S)487 std::string toYAML(const Symbol &S) {
488   std::string Buf;
489   {
490     llvm::raw_string_ostream OS(Buf);
491     llvm::yaml::Output Yout(OS);
492     Symbol Sym = S; // copy: Yout<< requires mutability.
493     Yout << Sym;
494   }
495   return Buf;
496 }
497 
toYAML(const std::pair<SymbolID,llvm::ArrayRef<Ref>> & Data)498 std::string toYAML(const std::pair<SymbolID, llvm::ArrayRef<Ref>> &Data) {
499   RefBundle Refs = {Data.first, Data.second};
500   std::string Buf;
501   {
502     llvm::raw_string_ostream OS(Buf);
503     llvm::yaml::Output Yout(OS);
504     Yout << Refs;
505   }
506   return Buf;
507 }
508 
toYAML(const Relation & R)509 std::string toYAML(const Relation &R) {
510   std::string Buf;
511   {
512     llvm::raw_string_ostream OS(Buf);
513     llvm::yaml::Output Yout(OS);
514     Relation Rel = R; // copy: Yout<< requires mutability.
515     Yout << Rel;
516   }
517   return Buf;
518 }
519 
toYAML(const Ref & R)520 std::string toYAML(const Ref &R) {
521   std::string Buf;
522   {
523     llvm::raw_string_ostream OS(Buf);
524     llvm::yaml::Output Yout(OS);
525     Ref Reference = R; // copy: Yout<< requires mutability.
526     Yout << Reference;
527   }
528   return Buf;
529 }
530 
531 llvm::Expected<clangd::Symbol>
symbolFromYAML(StringRef YAML,llvm::UniqueStringSaver * Strings)532 symbolFromYAML(StringRef YAML, llvm::UniqueStringSaver *Strings) {
533   clangd::Symbol Deserialized;
534   llvm::yaml::Input YAMLInput(YAML, Strings);
535   if (YAMLInput.error())
536     return llvm::make_error<llvm::StringError>(
537         llvm::formatv("Unable to deserialize Symbol from YAML: {0}", YAML),
538         llvm::inconvertibleErrorCode());
539   YAMLInput >> Deserialized;
540   return Deserialized;
541 }
542 
refFromYAML(StringRef YAML,llvm::UniqueStringSaver * Strings)543 llvm::Expected<clangd::Ref> refFromYAML(StringRef YAML,
544                                         llvm::UniqueStringSaver *Strings) {
545   clangd::Ref Deserialized;
546   llvm::yaml::Input YAMLInput(YAML, Strings);
547   if (YAMLInput.error())
548     return llvm::make_error<llvm::StringError>(
549         llvm::formatv("Unable to deserialize Symbol from YAML: {0}", YAML),
550         llvm::inconvertibleErrorCode());
551   YAMLInput >> Deserialized;
552   return Deserialized;
553 }
554 
555 } // namespace clangd
556 } // namespace clang
557