clang-tools  10.0.0svn
Serialize.cpp
Go to the documentation of this file.
1 //===-- Serialize.cpp - ClangDoc Serializer ---------------------*- 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 #include "Serialize.h"
10 #include "BitcodeWriter.h"
11 #include "clang/AST/Comment.h"
12 #include "clang/Index/USRGeneration.h"
13 #include "llvm/ADT/Hashing.h"
14 #include "llvm/ADT/StringExtras.h"
15 #include "llvm/Support/SHA1.h"
16 
17 using clang::comments::FullComment;
18 
19 namespace clang {
20 namespace doc {
21 namespace serialize {
22 
23 SymbolID hashUSR(llvm::StringRef USR) {
24  return llvm::SHA1::hash(arrayRefFromStringRef(USR));
25 }
26 
27 template <typename T>
28 static void
29 populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
30  const T *D, bool &IsAnonymousNamespace);
31 
32 // A function to extract the appropriate relative path for a given info's
33 // documentation. The path returned is a composite of the parent namespaces.
34 //
35 // Example: Given the below, the diretory path for class C info will be
36 // <root>/A/B
37 //
38 // namespace A {
39 // namesapce B {
40 //
41 // class C {};
42 //
43 // }
44 // }
45 llvm::SmallString<128>
46 getInfoRelativePath(const llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
47  llvm::SmallString<128> Path;
48  for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
49  llvm::sys::path::append(Path, R->Name);
50  return Path;
51 }
52 
53 llvm::SmallString<128> getInfoRelativePath(const Decl *D) {
54  llvm::SmallVector<Reference, 4> Namespaces;
55  // The third arg in populateParentNamespaces is a boolean passed by reference,
56  // its value is not relevant in here so it's not used anywhere besides the
57  // function call
58  bool B = true;
59  populateParentNamespaces(Namespaces, D, B);
60  return getInfoRelativePath(Namespaces);
61 }
62 
64  : public ConstCommentVisitor<ClangDocCommentVisitor> {
65 public:
66  ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {}
67 
68  void parseComment(const comments::Comment *C);
69 
70  void visitTextComment(const TextComment *C);
71  void visitInlineCommandComment(const InlineCommandComment *C);
72  void visitHTMLStartTagComment(const HTMLStartTagComment *C);
73  void visitHTMLEndTagComment(const HTMLEndTagComment *C);
74  void visitBlockCommandComment(const BlockCommandComment *C);
75  void visitParamCommandComment(const ParamCommandComment *C);
76  void visitTParamCommandComment(const TParamCommandComment *C);
77  void visitVerbatimBlockComment(const VerbatimBlockComment *C);
78  void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
79  void visitVerbatimLineComment(const VerbatimLineComment *C);
80 
81 private:
82  std::string getCommandName(unsigned CommandID) const;
83  bool isWhitespaceOnly(StringRef S) const;
84 
85  CommentInfo &CurrentCI;
86 };
87 
88 void ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
89  CurrentCI.Kind = C->getCommentKindName();
91  for (comments::Comment *Child :
92  llvm::make_range(C->child_begin(), C->child_end())) {
93  CurrentCI.Children.emplace_back(std::make_unique<CommentInfo>());
94  ClangDocCommentVisitor Visitor(*CurrentCI.Children.back());
95  Visitor.parseComment(Child);
96  }
97 }
98 
99 void ClangDocCommentVisitor::visitTextComment(const TextComment *C) {
100  if (!isWhitespaceOnly(C->getText()))
101  CurrentCI.Text = C->getText();
102 }
103 
105  const InlineCommandComment *C) {
106  CurrentCI.Name = getCommandName(C->getCommandID());
107  for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
108  CurrentCI.Args.push_back(C->getArgText(I));
109 }
110 
112  const HTMLStartTagComment *C) {
113  CurrentCI.Name = C->getTagName();
114  CurrentCI.SelfClosing = C->isSelfClosing();
115  for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) {
116  const HTMLStartTagComment::Attribute &Attr = C->getAttr(I);
117  CurrentCI.AttrKeys.push_back(Attr.Name);
118  CurrentCI.AttrValues.push_back(Attr.Value);
119  }
120 }
121 
123  const HTMLEndTagComment *C) {
124  CurrentCI.Name = C->getTagName();
125  CurrentCI.SelfClosing = true;
126 }
127 
129  const BlockCommandComment *C) {
130  CurrentCI.Name = getCommandName(C->getCommandID());
131  for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
132  CurrentCI.Args.push_back(C->getArgText(I));
133 }
134 
136  const ParamCommandComment *C) {
137  CurrentCI.Direction =
138  ParamCommandComment::getDirectionAsString(C->getDirection());
139  CurrentCI.Explicit = C->isDirectionExplicit();
140  if (C->hasParamName())
141  CurrentCI.ParamName = C->getParamNameAsWritten();
142 }
143 
145  const TParamCommandComment *C) {
146  if (C->hasParamName())
147  CurrentCI.ParamName = C->getParamNameAsWritten();
148 }
149 
151  const VerbatimBlockComment *C) {
152  CurrentCI.Name = getCommandName(C->getCommandID());
153  CurrentCI.CloseName = C->getCloseName();
154 }
155 
157  const VerbatimBlockLineComment *C) {
158  if (!isWhitespaceOnly(C->getText()))
159  CurrentCI.Text = C->getText();
160 }
161 
163  const VerbatimLineComment *C) {
164  if (!isWhitespaceOnly(C->getText()))
165  CurrentCI.Text = C->getText();
166 }
167 
168 bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const {
169  return std::all_of(S.begin(), S.end(), isspace);
170 }
171 
172 std::string ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
173  const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
174  if (Info)
175  return Info->Name;
176  // TODO: Add parsing for \file command.
177  return "<not a builtin command>";
178 }
179 
180 // Serializing functions.
181 
182 template <typename T> static std::string serialize(T &I) {
183  SmallString<2048> Buffer;
184  llvm::BitstreamWriter Stream(Buffer);
185  ClangDocBitcodeWriter Writer(Stream);
186  Writer.emitBlock(I);
187  return Buffer.str().str();
188 }
189 
190 std::string serialize(std::unique_ptr<Info> &I) {
191  switch (I->IT) {
193  return serialize(*static_cast<NamespaceInfo *>(I.get()));
194  case InfoType::IT_record:
195  return serialize(*static_cast<RecordInfo *>(I.get()));
196  case InfoType::IT_enum:
197  return serialize(*static_cast<EnumInfo *>(I.get()));
199  return serialize(*static_cast<FunctionInfo *>(I.get()));
200  default:
201  return "";
202  }
203 }
204 
205 static void parseFullComment(const FullComment *C, CommentInfo &CI) {
206  ClangDocCommentVisitor Visitor(CI);
207  Visitor.parseComment(C);
208 }
209 
210 static SymbolID getUSRForDecl(const Decl *D) {
211  llvm::SmallString<128> USR;
212  if (index::generateUSRForDecl(D, USR))
213  return SymbolID();
214  return hashUSR(USR);
215 }
216 
217 static RecordDecl *getDeclForType(const QualType &T) {
218  if (const RecordDecl *D = T->getAsRecordDecl())
219  return D->getDefinition();
220  return nullptr;
221 }
222 
223 static bool isPublic(const clang::AccessSpecifier AS,
224  const clang::Linkage Link) {
225  if (AS == clang::AccessSpecifier::AS_private)
226  return false;
227  else if ((Link == clang::Linkage::ModuleLinkage) ||
228  (Link == clang::Linkage::ExternalLinkage))
229  return true;
230  return false; // otherwise, linkage is some form of internal linkage
231 }
232 
233 static bool shouldSerializeInfo(bool PublicOnly, bool IsInAnonymousNamespace,
234  const NamedDecl *D) {
235  bool IsAnonymousNamespace = false;
236  if (const auto *N = dyn_cast<NamespaceDecl>(D))
237  IsAnonymousNamespace = N->isAnonymousNamespace();
238  return !PublicOnly ||
239  (!IsInAnonymousNamespace && !IsAnonymousNamespace &&
240  isPublic(D->getAccessUnsafe(), D->getLinkageInternal()));
241 }
242 
243 // There are two uses for this function.
244 // 1) Getting the resulting mode of inheritance of a record.
245 // Example: class A {}; class B : private A {}; class C : public B {};
246 // It's explicit that C is publicly inherited from C and B is privately
247 // inherited from A. It's not explicit but C is also privately inherited from
248 // A. This is the AS that this function calculates. FirstAS is the
249 // inheritance mode of `class C : B` and SecondAS is the inheritance mode of
250 // `class B : A`.
251 // 2) Getting the inheritance mode of an inherited attribute / method.
252 // Example : class A { public: int M; }; class B : private A {};
253 // Class B is inherited from class A, which has a public attribute. This
254 // attribute is now part of the derived class B but it's not public. This
255 // will be private because the inheritance is private. This is the AS that
256 // this function calculates. FirstAS is the inheritance mode and SecondAS is
257 // the AS of the attribute / method.
258 static AccessSpecifier getFinalAccessSpecifier(AccessSpecifier FirstAS,
259  AccessSpecifier SecondAS) {
260  if (FirstAS == AccessSpecifier::AS_none ||
261  SecondAS == AccessSpecifier::AS_none)
262  return AccessSpecifier::AS_none;
263  if (FirstAS == AccessSpecifier::AS_private ||
264  SecondAS == AccessSpecifier::AS_private)
265  return AccessSpecifier::AS_private;
266  if (FirstAS == AccessSpecifier::AS_protected ||
267  SecondAS == AccessSpecifier::AS_protected)
268  return AccessSpecifier::AS_protected;
269  return AccessSpecifier::AS_public;
270 }
271 
272 // The Access parameter is only provided when parsing the field of an inherited
273 // record, the access specification of the field depends on the inheritance mode
274 static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly,
275  AccessSpecifier Access = AccessSpecifier::AS_public) {
276  for (const FieldDecl *F : D->fields()) {
277  if (!shouldSerializeInfo(PublicOnly, /*IsInAnonymousNamespace=*/false, F))
278  continue;
279  if (const auto *T = getDeclForType(F->getTypeSourceInfo()->getType())) {
280  // Use getAccessUnsafe so that we just get the default AS_none if it's not
281  // valid, as opposed to an assert.
282  if (const auto *N = dyn_cast<EnumDecl>(T)) {
283  I.Members.emplace_back(
284  getUSRForDecl(T), N->getNameAsString(), InfoType::IT_enum,
285  getInfoRelativePath(N), F->getNameAsString(),
286  getFinalAccessSpecifier(Access, N->getAccessUnsafe()));
287  continue;
288  } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
289  I.Members.emplace_back(
290  getUSRForDecl(T), N->getNameAsString(), InfoType::IT_record,
291  getInfoRelativePath(N), F->getNameAsString(),
292  getFinalAccessSpecifier(Access, N->getAccessUnsafe()));
293  continue;
294  }
295  }
296  I.Members.emplace_back(
297  F->getTypeSourceInfo()->getType().getAsString(), F->getNameAsString(),
298  getFinalAccessSpecifier(Access, F->getAccessUnsafe()));
299  }
300 }
301 
302 static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
303  for (const EnumConstantDecl *E : D->enumerators())
304  I.Members.emplace_back(E->getNameAsString());
305 }
306 
307 static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
308  for (const ParmVarDecl *P : D->parameters()) {
309  if (const auto *T = getDeclForType(P->getOriginalType())) {
310  if (const auto *N = dyn_cast<EnumDecl>(T)) {
311  I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
313  P->getNameAsString());
314  continue;
315  } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
316  I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
318  P->getNameAsString());
319  continue;
320  }
321  }
322  I.Params.emplace_back(P->getOriginalType().getAsString(),
323  P->getNameAsString());
324  }
325 }
326 
327 // TODO: Remove the serialization of Parents and VirtualParents, this
328 // information is also extracted in the other definition of parseBases.
329 static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
330  // Don't parse bases if this isn't a definition.
331  if (!D->isThisDeclarationADefinition())
332  return;
333  for (const CXXBaseSpecifier &B : D->bases()) {
334  if (B.isVirtual())
335  continue;
336  if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
337  const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
338  I.Parents.emplace_back(getUSRForDecl(D), B.getType().getAsString(),
340  } else if (const RecordDecl *P = getDeclForType(B.getType()))
341  I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
343  else
344  I.Parents.emplace_back(B.getType().getAsString());
345  }
346  for (const CXXBaseSpecifier &B : D->vbases()) {
347  if (const auto *P = getDeclForType(B.getType()))
348  I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
351  else
352  I.VirtualParents.emplace_back(B.getType().getAsString());
353  }
354 }
355 
356 template <typename T>
357 static void
358 populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
359  const T *D, bool &IsInAnonymousNamespace) {
360  const auto *DC = dyn_cast<DeclContext>(D);
361  while ((DC = DC->getParent())) {
362  if (const auto *N = dyn_cast<NamespaceDecl>(DC)) {
363  std::string Namespace;
364  if (N->isAnonymousNamespace()) {
365  Namespace = "@nonymous_namespace";
366  IsInAnonymousNamespace = true;
367  } else
368  Namespace = N->getNameAsString();
369  Namespaces.emplace_back(getUSRForDecl(N), Namespace,
371  } else if (const auto *N = dyn_cast<RecordDecl>(DC))
372  Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
374  else if (const auto *N = dyn_cast<FunctionDecl>(DC))
375  Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
377  else if (const auto *N = dyn_cast<EnumDecl>(DC))
378  Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
380  }
381  // The global namespace should be added to the list of namespaces if the decl
382  // corresponds to a Record and if it doesn't have any namespace (because this
383  // means it's in the global namespace). Also if its outermost namespace is a
384  // record because that record matches the previous condition mentioned.
385  if ((Namespaces.empty() && dyn_cast<RecordDecl>(D)) ||
386  (!Namespaces.empty() && Namespaces.back().RefType == InfoType::IT_record))
387  Namespaces.emplace_back(SymbolID(), "GlobalNamespace",
389 }
390 
391 template <typename T>
392 static void populateInfo(Info &I, const T *D, const FullComment *C,
393  bool &IsInAnonymousNamespace) {
394  I.USR = getUSRForDecl(D);
395  I.Name = D->getNameAsString();
396  populateParentNamespaces(I.Namespace, D, IsInAnonymousNamespace);
397  if (C) {
398  I.Description.emplace_back();
399  parseFullComment(C, I.Description.back());
400  }
401 }
402 
403 template <typename T>
404 static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
405  int LineNumber, StringRef Filename,
406  bool IsFileInRootDir,
407  bool &IsInAnonymousNamespace) {
408  populateInfo(I, D, C, IsInAnonymousNamespace);
409  if (D->isThisDeclarationADefinition())
410  I.DefLoc.emplace(LineNumber, Filename, IsFileInRootDir);
411  else
412  I.Loc.emplace_back(LineNumber, Filename, IsFileInRootDir);
413 }
414 
415 static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
416  const FullComment *FC, int LineNumber,
417  StringRef Filename, bool IsFileInRootDir,
418  bool &IsInAnonymousNamespace) {
419  populateSymbolInfo(I, D, FC, LineNumber, Filename, IsFileInRootDir,
420  IsInAnonymousNamespace);
421  if (const auto *T = getDeclForType(D->getReturnType())) {
422  if (dyn_cast<EnumDecl>(T))
423  I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(),
425  else if (dyn_cast<RecordDecl>(T))
426  I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(),
428  } else {
429  I.ReturnType = TypeInfo(D->getReturnType().getAsString());
430  }
431  parseParameters(I, D);
432 }
433 
434 static void
435 parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
436  bool PublicOnly, bool IsParent,
437  AccessSpecifier ParentAccess = AccessSpecifier::AS_public) {
438  // Don't parse bases if this isn't a definition.
439  if (!D->isThisDeclarationADefinition())
440  return;
441  for (const CXXBaseSpecifier &B : D->bases()) {
442  if (const RecordType *Ty = B.getType()->getAs<RecordType>()) {
443  if (const CXXRecordDecl *Base =
444  cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition())) {
445  // Initialized without USR and name, this will be set in the following
446  // if-else stmt.
447  BaseRecordInfo BI(
448  {}, "", getInfoRelativePath(Base), B.isVirtual(),
449  getFinalAccessSpecifier(ParentAccess, B.getAccessSpecifier()),
450  IsParent);
451  if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
452  const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
453  BI.USR = getUSRForDecl(D);
454  BI.Name = B.getType().getAsString();
455  } else {
456  BI.USR = getUSRForDecl(Base);
457  BI.Name = Base->getNameAsString();
458  }
459  parseFields(BI, Base, PublicOnly, BI.Access);
460  for (const auto &Decl : Base->decls())
461  if (const auto *MD = dyn_cast<CXXMethodDecl>(Decl)) {
462  // Don't serialize private methods
463  if (MD->getAccessUnsafe() == AccessSpecifier::AS_private ||
464  !MD->isUserProvided())
465  continue;
466  FunctionInfo FI;
467  FI.IsMethod = true;
468  // The seventh arg in populateFunctionInfo is a boolean passed by
469  // reference, its value is not relevant in here so it's not used
470  // anywhere besides the function call.
471  bool IsInAnonymousNamespace;
472  populateFunctionInfo(FI, MD, /*FullComment=*/{}, /*LineNumber=*/{},
473  /*FileName=*/{}, IsFileInRootDir,
474  IsInAnonymousNamespace);
475  FI.Access =
476  getFinalAccessSpecifier(BI.Access, MD->getAccessUnsafe());
477  BI.ChildFunctions.emplace_back(std::move(FI));
478  }
479  I.Bases.emplace_back(std::move(BI));
480  // Call this function recursively to get the inherited classes of
481  // this base; these new bases will also get stored in the original
482  // RecordInfo: I.
483  parseBases(I, Base, IsFileInRootDir, PublicOnly, false,
484  I.Bases.back().Access);
485  }
486  }
487  }
488 }
489 
490 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
491 emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
492  llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
493  auto I = std::make_unique<NamespaceInfo>();
494  bool IsInAnonymousNamespace = false;
495  populateInfo(*I, D, FC, IsInAnonymousNamespace);
496  if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
497  return {};
498 
499  I->Name = D->isAnonymousNamespace()
500  ? llvm::SmallString<16>("@nonymous_namespace")
501  : I->Name;
502  I->Path = getInfoRelativePath(I->Namespace);
503  if (I->Namespace.empty() && I->USR == SymbolID())
504  return {std::unique_ptr<Info>{std::move(I)}, nullptr};
505 
506  auto ParentI = std::make_unique<NamespaceInfo>();
507  ParentI->USR = I->Namespace.empty() ? SymbolID() : I->Namespace[0].USR;
508  ParentI->ChildNamespaces.emplace_back(I->USR, I->Name, InfoType::IT_namespace,
509  getInfoRelativePath(I->Namespace));
510  if (I->Namespace.empty())
511  ParentI->Path = getInfoRelativePath(ParentI->Namespace);
512  return {std::unique_ptr<Info>{std::move(I)},
513  std::unique_ptr<Info>{std::move(ParentI)}};
514 }
515 
516 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
517 emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
518  llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
519  auto I = std::make_unique<RecordInfo>();
520  bool IsInAnonymousNamespace = false;
521  populateSymbolInfo(*I, D, FC, LineNumber, File, IsFileInRootDir,
522  IsInAnonymousNamespace);
523  if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
524  return {};
525 
526  I->TagType = D->getTagKind();
527  parseFields(*I, D, PublicOnly);
528  if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
529  if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl()) {
530  I->Name = TD->getNameAsString();
531  I->IsTypeDef = true;
532  }
533  // TODO: remove first call to parseBases, that function should be deleted
534  parseBases(*I, C);
535  parseBases(*I, C, IsFileInRootDir, PublicOnly, true);
536  }
537  I->Path = getInfoRelativePath(I->Namespace);
538 
539  switch (I->Namespace[0].RefType) {
540  case InfoType::IT_namespace: {
541  auto ParentI = std::make_unique<NamespaceInfo>();
542  ParentI->USR = I->Namespace[0].USR;
543  ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record,
544  getInfoRelativePath(I->Namespace));
545  return {std::unique_ptr<Info>{std::move(I)},
546  std::unique_ptr<Info>{std::move(ParentI)}};
547  }
548  case InfoType::IT_record: {
549  auto ParentI = std::make_unique<RecordInfo>();
550  ParentI->USR = I->Namespace[0].USR;
551  ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record,
552  getInfoRelativePath(I->Namespace));
553  return {std::unique_ptr<Info>{std::move(I)},
554  std::unique_ptr<Info>{std::move(ParentI)}};
555  }
556  default:
557  llvm_unreachable("Invalid reference type for parent namespace");
558  }
559 }
560 
561 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
562 emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
563  llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
564  FunctionInfo Func;
565  bool IsInAnonymousNamespace = false;
566  populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir,
567  IsInAnonymousNamespace);
568  Func.Access = clang::AccessSpecifier::AS_none;
569  if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
570  return {};
571 
572  // Wrap in enclosing scope
573  auto ParentI = std::make_unique<NamespaceInfo>();
574  if (!Func.Namespace.empty())
575  ParentI->USR = Func.Namespace[0].USR;
576  else
577  ParentI->USR = SymbolID();
578  if (Func.Namespace.empty())
579  ParentI->Path = getInfoRelativePath(ParentI->Namespace);
580  ParentI->ChildFunctions.emplace_back(std::move(Func));
581  // Info is wrapped in its parent scope so it's returned in the second position
582  return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
583 }
584 
585 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
586 emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
587  llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
588  FunctionInfo Func;
589  bool IsInAnonymousNamespace = false;
590  populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir,
591  IsInAnonymousNamespace);
592  if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
593  return {};
594 
595  Func.IsMethod = true;
596 
597  const NamedDecl *Parent = nullptr;
598  if (const auto *SD =
599  dyn_cast<ClassTemplateSpecializationDecl>(D->getParent()))
600  Parent = SD->getSpecializedTemplate();
601  else
602  Parent = D->getParent();
603 
604  SymbolID ParentUSR = getUSRForDecl(Parent);
605  Func.Parent =
606  Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record};
607  Func.Access = D->getAccess();
608 
609  // Wrap in enclosing scope
610  auto ParentI = std::make_unique<RecordInfo>();
611  ParentI->USR = ParentUSR;
612  ParentI->ChildFunctions.emplace_back(std::move(Func));
613  // Info is wrapped in its parent scope so it's returned in the second position
614  return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
615 }
616 
617 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
618 emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
619  llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
620  EnumInfo Enum;
621  bool IsInAnonymousNamespace = false;
622  populateSymbolInfo(Enum, D, FC, LineNumber, File, IsFileInRootDir,
623  IsInAnonymousNamespace);
624  if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
625  return {};
626 
627  Enum.Scoped = D->isScoped();
628  parseEnumerators(Enum, D);
629 
630  // Put in global namespace
631  if (Enum.Namespace.empty()) {
632  auto ParentI = std::make_unique<NamespaceInfo>();
633  ParentI->USR = SymbolID();
634  ParentI->ChildEnums.emplace_back(std::move(Enum));
635  ParentI->Path = getInfoRelativePath(ParentI->Namespace);
636  // Info is wrapped in its parent scope so it's returned in the second
637  // position
638  return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
639  }
640 
641  // Wrap in enclosing scope
642  switch (Enum.Namespace[0].RefType) {
643  case InfoType::IT_namespace: {
644  auto ParentI = std::make_unique<NamespaceInfo>();
645  ParentI->USR = Enum.Namespace[0].USR;
646  ParentI->ChildEnums.emplace_back(std::move(Enum));
647  // Info is wrapped in its parent scope so it's returned in the second
648  // position
649  return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
650  }
651  case InfoType::IT_record: {
652  auto ParentI = std::make_unique<RecordInfo>();
653  ParentI->USR = Enum.Namespace[0].USR;
654  ParentI->ChildEnums.emplace_back(std::move(Enum));
655  // Info is wrapped in its parent scope so it's returned in the second
656  // position
657  return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
658  }
659  default:
660  llvm_unreachable("Invalid reference type for parent namespace");
661  }
662 }
663 
664 } // namespace serialize
665 } // namespace doc
666 } // namespace clang
llvm::SmallVector< Reference, 4 > Namespace
static void parseFullComment(const FullComment *C, CommentInfo &CI)
Definition: Serialize.cpp:205
std::vector< BaseRecordInfo > Bases
static bool shouldSerializeInfo(bool PublicOnly, bool IsInAnonymousNamespace, const NamedDecl *D)
Definition: Serialize.cpp:233
void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C)
Definition: Serialize.cpp:156
void visitParamCommandComment(const ParamCommandComment *C)
Definition: Serialize.cpp:135
const Node * Parent
void emitBlock(const NamespaceInfo &I)
llvm::Optional< Location > DefLoc
std::vector< FunctionInfo > ChildFunctions
std::pair< std::unique_ptr< Info >, std::unique_ptr< Info > > emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber, llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly)
Definition: Serialize.cpp:491
void visitVerbatimBlockComment(const VerbatimBlockComment *C)
Definition: Serialize.cpp:150
llvm::SmallVector< Location, 2 > Loc
llvm::SmallString< 128 > getInfoRelativePath(const llvm::SmallVectorImpl< doc::Reference > &Namespaces)
Definition: Serialize.cpp:46
static void parseBases(RecordInfo &I, const CXXRecordDecl *D)
Definition: Serialize.cpp:329
static RecordDecl * getDeclForType(const QualType &T)
Definition: Serialize.cpp:217
static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C, int LineNumber, StringRef Filename, bool IsFileInRootDir, bool &IsInAnonymousNamespace)
Definition: Serialize.cpp:404
std::vector< HeaderHandle > Path
void parseComment(const comments::Comment *C)
Definition: Serialize.cpp:88
std::string serialize(std::unique_ptr< Info > &I)
Definition: Serialize.cpp:190
static llvm::cl::opt< bool > PublicOnly("public", llvm::cl::desc("Document only public declarations."), llvm::cl::init(false), llvm::cl::cat(ClangDocCategory))
static std::string serialize(T &I)
Definition: Serialize.cpp:182
llvm::SmallVector< Reference, 4 > VirtualParents
void visitHTMLStartTagComment(const HTMLStartTagComment *C)
Definition: Serialize.cpp:111
llvm::SmallVector< FieldTypeInfo, 4 > Params
static void parseEnumerators(EnumInfo &I, const EnumDecl *D)
Definition: Serialize.cpp:302
std::string Filename
Filename as a string.
llvm::SmallVector< SmallString< 16 >, 4 > Members
llvm::SmallVector< SmallString< 16 >, 4 > AttrValues
std::vector< CommentInfo > Description
void visitHTMLEndTagComment(const HTMLEndTagComment *C)
Definition: Serialize.cpp:122
void visitTParamCommandComment(const TParamCommandComment *C)
Definition: Serialize.cpp:144
llvm::SmallVector< SmallString< 16 >, 4 > Args
static void populateParentNamespaces(llvm::SmallVector< Reference, 4 > &Namespaces, const T *D, bool &IsAnonymousNamespace)
Definition: Serialize.cpp:358
SmallString< 16 > Name
const Decl * D
Definition: XRefs.cpp:849
A base struct for Infos.
static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly, AccessSpecifier Access=AccessSpecifier::AS_public)
Definition: Serialize.cpp:274
llvm::SmallVector< Reference, 4 > Parents
void visitTextComment(const TextComment *C)
Definition: Serialize.cpp:99
SmallString< 16 > ParamName
static bool isPublic(const clang::AccessSpecifier AS, const clang::Linkage Link)
Definition: Serialize.cpp:223
static AccessSpecifier getFinalAccessSpecifier(AccessSpecifier FirstAS, AccessSpecifier SecondAS)
Definition: Serialize.cpp:258
llvm::SmallVector< SmallString< 16 >, 4 > AttrKeys
static void parseParameters(FunctionInfo &I, const FunctionDecl *D)
Definition: Serialize.cpp:307
SmallString< 16 > Name
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for MD output.")
static SymbolID getUSRForDecl(const Decl *D)
Definition: Serialize.cpp:210
SmallString< 16 > CloseName
static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, const FullComment *FC, int LineNumber, StringRef Filename, bool IsFileInRootDir, bool &IsInAnonymousNamespace)
Definition: Serialize.cpp:415
void visitBlockCommandComment(const BlockCommandComment *C)
Definition: Serialize.cpp:128
SmallString< 8 > Direction
void visitInlineCommandComment(const InlineCommandComment *C)
Definition: Serialize.cpp:104
llvm::SmallVector< MemberTypeInfo, 4 > Members
SmallString< 16 > Kind
std::unique_ptr< GlobalCompilationDatabase > Base
QualType TypeInfo
static void populateInfo(Info &I, const T *D, const FullComment *C, bool &IsInAnonymousNamespace)
Definition: Serialize.cpp:392
std::vector< std::unique_ptr< CommentInfo > > Children
SmallString< 64 > Text
std::array< uint8_t, 20 > SymbolID
void visitVerbatimLineComment(const VerbatimLineComment *C)
Definition: Serialize.cpp:162
SymbolID hashUSR(llvm::StringRef USR)
Definition: Serialize.cpp:23