clang-tools  8.0.0
YAMLSerialization.cpp
Go to the documentation of this file.
1 //===--- SymbolYAML.cpp ------------------------------------------*- C++-*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // A YAML index file is a sequence of tagged entries.
11 // Each entry either encodes a Symbol or the list of references to a symbol
12 // (a "ref bundle").
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "Index.h"
17 #include "Serialization.h"
18 #include "Trace.h"
19 #include "dex/Dex.h"
20 #include "llvm/ADT/Optional.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/Support/Allocator.h"
24 #include "llvm/Support/Errc.h"
25 #include "llvm/Support/MemoryBuffer.h"
26 #include "llvm/Support/StringSaver.h"
27 #include "llvm/Support/YAMLTraits.h"
28 #include "llvm/Support/raw_ostream.h"
29 #include <cstdint>
30 
31 LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Symbol::IncludeHeaderWithReferences)
32 LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Ref)
33 
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>
38 struct VariantEntry {
39  llvm::Optional<clang::clangd::Symbol> Symbol;
40  llvm::Optional<RefBundle> Refs;
41 };
42 // A class helps YAML to serialize the 32-bit encoded position (Line&Column),
43 // as YAMLIO can't directly map bitfields.
44 struct YPosition {
45  uint32_t Line;
46  uint32_t Column;
47 };
48 
49 } // namespace
50 namespace llvm {
51 namespace yaml {
52 
53 using clang::clangd::Ref;
61 using clang::index::SymbolLanguage;
62 
63 // Helper to (de)serialize the SymbolID. We serialize it as a hex string.
66  NormalizedSymbolID(IO &, const SymbolID &ID) {
67  llvm::raw_string_ostream OS(HexString);
68  OS << ID;
69  }
70 
72  auto ID = SymbolID::fromStr(HexString);
73  if (!ID) {
74  I.setError(llvm::toString(ID.takeError()));
75  return SymbolID();
76  }
77  return *ID;
78  }
79 
80  std::string HexString;
81 };
82 
86  Flag = static_cast<uint8_t>(F);
87  }
88 
90  return static_cast<Symbol::SymbolFlag>(Flag);
91  }
92 
93  uint8_t Flag = 0;
94 };
95 
99  Origin = static_cast<uint8_t>(O);
100  }
101 
102  SymbolOrigin denormalize(IO &) { return static_cast<SymbolOrigin>(Origin); }
103 
104  uint8_t Origin = 0;
105 };
106 
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);
111  }
112 };
113 
118  P.Line = Pos.line();
119  P.Column = Pos.column();
120  }
121 
123  Position Pos;
124  Pos.setLine(P.Line);
125  Pos.setColumn(P.Column);
126  return Pos;
127  }
128  YPosition P;
129 };
130 
133  NormalizedFileURI(IO &, const char *FileURI) { URI = FileURI; }
134 
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();
141  }
142 
143  std::string URI;
144 };
145 
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);
157  }
158 };
159 
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);
165  }
166 };
167 
168 template <>
169 struct MappingTraits<clang::clangd::Symbol::IncludeHeaderWithReferences> {
170  static void mapping(IO &io,
172  io.mapRequired("Header", Inc.IncludeHeader);
173  io.mapRequired("References", Inc.References);
174  }
175 };
176 
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  MappingNormalization<NormalizedSymbolOrigin, SymbolOrigin> NSymbolOrigin(
183  IO, Sym.Origin);
184  IO.mapRequired("ID", NSymbolID->HexString);
185  IO.mapRequired("Name", Sym.Name);
186  IO.mapRequired("Scope", Sym.Scope);
187  IO.mapRequired("SymInfo", Sym.SymInfo);
188  IO.mapOptional("CanonicalDeclaration", Sym.CanonicalDeclaration,
189  SymbolLocation());
190  IO.mapOptional("Definition", Sym.Definition, SymbolLocation());
191  IO.mapOptional("References", Sym.References, 0u);
192  IO.mapOptional("Origin", NSymbolOrigin->Origin);
193  IO.mapOptional("Flags", NSymbolFlag->Flag);
194  IO.mapOptional("Signature", Sym.Signature);
195  IO.mapOptional("CompletionSnippetSuffix", Sym.CompletionSnippetSuffix);
196  IO.mapOptional("Documentation", Sym.Documentation);
197  IO.mapOptional("ReturnType", Sym.ReturnType);
198  IO.mapOptional("Type", Sym.Type);
199  IO.mapOptional("IncludeHeaders", Sym.IncludeHeaders);
200  }
201 };
202 
203 template <> struct ScalarEnumerationTraits<SymbolLanguage> {
204  static void enumeration(IO &IO, SymbolLanguage &Value) {
205  IO.enumCase(Value, "C", SymbolLanguage::C);
206  IO.enumCase(Value, "Cpp", SymbolLanguage::CXX);
207  IO.enumCase(Value, "ObjC", SymbolLanguage::ObjC);
208  IO.enumCase(Value, "Swift", SymbolLanguage::Swift);
209  }
210 };
211 
212 template <> struct ScalarEnumerationTraits<SymbolKind> {
213  static void enumeration(IO &IO, SymbolKind &Value) {
214 #define DEFINE_ENUM(name) IO.enumCase(Value, #name, SymbolKind::name)
215 
217  DEFINE_ENUM(Function);
218  DEFINE_ENUM(Module);
219  DEFINE_ENUM(Namespace);
220  DEFINE_ENUM(NamespaceAlias);
221  DEFINE_ENUM(Macro);
222  DEFINE_ENUM(Enum);
223  DEFINE_ENUM(Struct);
224  DEFINE_ENUM(Class);
225  DEFINE_ENUM(Protocol);
226  DEFINE_ENUM(Extension);
227  DEFINE_ENUM(Union);
228  DEFINE_ENUM(TypeAlias);
229  DEFINE_ENUM(Function);
230  DEFINE_ENUM(Variable);
231  DEFINE_ENUM(Field);
232  DEFINE_ENUM(EnumConstant);
233  DEFINE_ENUM(InstanceMethod);
234  DEFINE_ENUM(ClassMethod);
235  DEFINE_ENUM(StaticMethod);
236  DEFINE_ENUM(InstanceProperty);
237  DEFINE_ENUM(ClassProperty);
238  DEFINE_ENUM(StaticProperty);
239  DEFINE_ENUM(Constructor);
240  DEFINE_ENUM(Destructor);
241  DEFINE_ENUM(ConversionFunction);
242  DEFINE_ENUM(Parameter);
243  DEFINE_ENUM(Using);
244 
245 #undef DEFINE_ENUM
246  }
247 };
248 
249 template <> struct MappingTraits<RefBundle> {
250  static void mapping(IO &IO, RefBundle &Refs) {
251  MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO,
252  Refs.first);
253  IO.mapRequired("ID", NSymbolID->HexString);
254  IO.mapRequired("References", Refs.second);
255  }
256 };
257 
260  NormalizedRefKind(IO &, RefKind O) { Kind = static_cast<uint8_t>(O); }
261 
262  RefKind denormalize(IO &) { return static_cast<RefKind>(Kind); }
263 
264  uint8_t Kind = 0;
265 };
266 
267 template <> struct MappingTraits<Ref> {
268  static void mapping(IO &IO, Ref &R) {
269  MappingNormalization<NormalizedRefKind, RefKind> NKind(IO, R.Kind);
270  IO.mapRequired("Kind", NKind->Kind);
271  IO.mapRequired("Location", R.Location);
272  }
273 };
274 
275 template <> struct MappingTraits<VariantEntry> {
276  static void mapping(IO &IO, VariantEntry &Variant) {
277  if (IO.mapTag("!Symbol", Variant.Symbol.hasValue())) {
278  if (!IO.outputting())
279  Variant.Symbol.emplace();
280  MappingTraits<Symbol>::mapping(IO, *Variant.Symbol);
281  } else if (IO.mapTag("!Refs", Variant.Refs.hasValue())) {
282  if (!IO.outputting())
283  Variant.Refs.emplace();
284  MappingTraits<RefBundle>::mapping(IO, *Variant.Refs);
285  }
286  }
287 };
288 
289 } // namespace yaml
290 } // namespace llvm
291 
292 namespace clang {
293 namespace clangd {
294 
295 void writeYAML(const IndexFileOut &O, llvm::raw_ostream &OS) {
296  llvm::yaml::Output Yout(OS);
297  for (const auto &Sym : *O.Symbols) {
298  VariantEntry Entry;
299  Entry.Symbol = Sym;
300  Yout << Entry;
301  }
302  if (O.Refs)
303  for (auto &Sym : *O.Refs) {
304  VariantEntry Entry;
305  Entry.Refs = Sym;
306  Yout << Entry;
307  }
308 }
309 
310 llvm::Expected<IndexFileIn> readYAML(llvm::StringRef Data) {
311  SymbolSlab::Builder Symbols;
312  RefSlab::Builder Refs;
313  llvm::BumpPtrAllocator
314  Arena; // store the underlying data of Position::FileURI.
315  llvm::UniqueStringSaver Strings(Arena);
316  llvm::yaml::Input Yin(Data, &Strings);
317  while (Yin.setCurrentDocument()) {
318  llvm::yaml::EmptyContext Ctx;
319  VariantEntry Variant;
320  yamlize(Yin, Variant, true, Ctx);
321  if (Yin.error())
322  return llvm::errorCodeToError(Yin.error());
323 
324  if (Variant.Symbol)
325  Symbols.insert(*Variant.Symbol);
326  if (Variant.Refs)
327  for (const auto &Ref : Variant.Refs->second)
328  Refs.insert(Variant.Refs->first, Ref);
329  Yin.nextDocument();
330  }
331 
333  Result.Symbols.emplace(std::move(Symbols).build());
334  Result.Refs.emplace(std::move(Refs).build());
335  return std::move(Result);
336 }
337 
338 std::string toYAML(const Symbol &S) {
339  std::string Buf;
340  {
341  llvm::raw_string_ostream OS(Buf);
342  llvm::yaml::Output Yout(OS);
343  Symbol Sym = S; // copy: Yout<< requires mutability.
344  Yout << Sym;
345  }
346  return Buf;
347 }
348 
349 std::string toYAML(const std::pair<SymbolID, llvm::ArrayRef<Ref>> &Data) {
350  RefBundle Refs = {Data.first, Data.second};
351  std::string Buf;
352  {
353  llvm::raw_string_ostream OS(Buf);
354  llvm::yaml::Output Yout(OS);
355  Yout << Refs;
356  }
357  return Buf;
358 }
359 
360 } // namespace clangd
361 } // namespace clang
llvm::Expected< IndexFileIn > readYAML(llvm::StringRef)
llvm::Optional< SymbolSlab > Symbols
Definition: Serialization.h:41
Symbol::SymbolFlag denormalize(IO &)
Some operations such as code completion produce a set of candidates.
void setColumn(uint32_t Column)
Definition: Index.cpp:29
static void mapping(IO &io, SymbolInfo &SymInfo)
This defines Dex - a symbol index implementation based on query iterators over symbol tokens...
static void mapping(IO &io, clang::clangd::Symbol::IncludeHeaderWithReferences &Inc)
unsigned References
The number of translation units that reference this symbol and include this header.
Definition: Index.h:224
void writeYAML(const IndexFileOut &, llvm::raw_ostream &)
clang::find_all_symbols::SymbolInfo::SymbolKind SymbolKind
Definition: SymbolInfo.cpp:22
void insert(const Symbol &S)
Definition: Index.cpp:91
static llvm::StringRef toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K)
int Column
static void enumeration(IO &IO, SymbolKind &Value)
llvm::StringRef Scope
Definition: Index.h:168
static void mapping(IO &IO, Ref &R)
const SymbolSlab * Symbols
Definition: Serialization.h:51
unsigned References
Definition: Index.h:183
static void mapping(IO &IO, Symbol &Sym)
index::SymbolInfo SymInfo
Definition: Index.h:164
BindArgumentKind Kind
llvm::BumpPtrAllocator Arena
SymbolLocation Definition
Definition: Index.h:171
Context Ctx
clang::find_all_symbols::SymbolInfo SymbolInfo
NormalizedSymbolFlag(IO &, Symbol::SymbolFlag F)
llvm::SmallVector< IncludeHeaderWithReferences, 1 > IncludeHeaders
One Symbol can potentially be incuded via different headers.
Definition: Index.h:231
SymbolFlag Flags
Definition: Index.h:248
llvm::StringRef Signature
A brief description of the symbol that can be appended in the completion candidate list...
Definition: Index.h:189
SymbolLocation Location
Definition: Index.h:375
static void enumeration(IO &IO, SymbolLanguage &Value)
llvm::StringRef Documentation
Documentation including comment for the symbol declaration.
Definition: Index.h:196
SymbolLocation CanonicalDeclaration
Definition: Index.h:180
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
std::string toYAML(const std::pair< SymbolID, llvm::ArrayRef< Ref >> &Data)
Position Pos
static void mapping(IO &IO, SymbolLocation &Value)
std::vector< llvm::StringRef > Strings
NormalizedPosition(IO &, const Position &Pos)
llvm::Optional< RefSlab > Refs
Definition: Serialization.h:42
llvm::StringRef IncludeHeader
This can be either a URI of the header to be #include&#39;d for this symbol, or a literal header quoted w...
Definition: Index.h:221
Position Start
The symbol range, using half-open range [Start, End).
Definition: Index.h:61
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::StringRef Name
Definition: Index.h:166
static void mapping(IO &IO, RefBundle &Refs)
NormalizedSymbolID(IO &, const SymbolID &ID)
NormalizedSymbolOrigin(IO &, SymbolOrigin O)
static void mapping(IO &IO, VariantEntry &Variant)
void insert(const SymbolID &ID, const Ref &S)
Definition: Index.cpp:135
llvm::StringRef CompletionSnippetSuffix
What to insert when completing this symbol, after the symbol name.
Definition: Index.h:194
#define DEFINE_ENUM(name)
static void mapping(IO &IO, YPosition &Value)
llvm::StringRef Type
Raw representation of the OpaqueType of the symbol, used for scoring purposes.
Definition: Index.h:205
SymbolOrigin Origin
Where this symbol came from. Usually an index provides a constant value.
Definition: Index.h:185
NormalizedFileURI(IO &, const char *FileURI)
const char * FileURI
Definition: Index.h:72
llvm::StringRef ReturnType
Type when this symbol is used in an expression.
Definition: Index.h:200
std::array< uint8_t, 20 > SymbolID
RefKind Kind
Definition: Index.h:376