Serialize.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  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. #include "Serialize.h"
  9. #include "BitcodeWriter.h"
  10. #include "clang/AST/Comment.h"
  11. #include "clang/Index/USRGeneration.h"
  12. #include "clang/Lex/Lexer.h"
  13. #include "llvm/ADT/Hashing.h"
  14. #include "llvm/ADT/StringExtras.h"
  15. #include "llvm/Support/SHA1.h"
  16. using clang::comments::FullComment;
  17. namespace clang {
  18. namespace doc {
  19. namespace serialize {
  20. SymbolID hashUSR(llvm::StringRef USR) {
  21. return llvm::SHA1::hash(arrayRefFromStringRef(USR));
  22. }
  23. template <typename T>
  24. static void
  25. populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
  26. const T *D, bool &IsAnonymousNamespace);
  27. static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D);
  28. // A function to extract the appropriate relative path for a given info's
  29. // documentation. The path returned is a composite of the parent namespaces.
  30. //
  31. // Example: Given the below, the directory path for class C info will be
  32. // <root>/A/B
  33. //
  34. // namespace A {
  35. // namespace B {
  36. //
  37. // class C {};
  38. //
  39. // }
  40. // }
  41. llvm::SmallString<128>
  42. getInfoRelativePath(const llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
  43. llvm::SmallString<128> Path;
  44. for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
  45. llvm::sys::path::append(Path, R->Name);
  46. return Path;
  47. }
  48. llvm::SmallString<128> getInfoRelativePath(const Decl *D) {
  49. llvm::SmallVector<Reference, 4> Namespaces;
  50. // The third arg in populateParentNamespaces is a boolean passed by reference,
  51. // its value is not relevant in here so it's not used anywhere besides the
  52. // function call
  53. bool B = true;
  54. populateParentNamespaces(Namespaces, D, B);
  55. return getInfoRelativePath(Namespaces);
  56. }
  57. class ClangDocCommentVisitor
  58. : public ConstCommentVisitor<ClangDocCommentVisitor> {
  59. public:
  60. ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {}
  61. void parseComment(const comments::Comment *C);
  62. void visitTextComment(const TextComment *C);
  63. void visitInlineCommandComment(const InlineCommandComment *C);
  64. void visitHTMLStartTagComment(const HTMLStartTagComment *C);
  65. void visitHTMLEndTagComment(const HTMLEndTagComment *C);
  66. void visitBlockCommandComment(const BlockCommandComment *C);
  67. void visitParamCommandComment(const ParamCommandComment *C);
  68. void visitTParamCommandComment(const TParamCommandComment *C);
  69. void visitVerbatimBlockComment(const VerbatimBlockComment *C);
  70. void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
  71. void visitVerbatimLineComment(const VerbatimLineComment *C);
  72. private:
  73. std::string getCommandName(unsigned CommandID) const;
  74. bool isWhitespaceOnly(StringRef S) const;
  75. CommentInfo &CurrentCI;
  76. };
  77. void ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
  78. CurrentCI.Kind = C->getCommentKindName();
  79. ConstCommentVisitor<ClangDocCommentVisitor>::visit(C);
  80. for (comments::Comment *Child :
  81. llvm::make_range(C->child_begin(), C->child_end())) {
  82. CurrentCI.Children.emplace_back(std::make_unique<CommentInfo>());
  83. ClangDocCommentVisitor Visitor(*CurrentCI.Children.back());
  84. Visitor.parseComment(Child);
  85. }
  86. }
  87. void ClangDocCommentVisitor::visitTextComment(const TextComment *C) {
  88. if (!isWhitespaceOnly(C->getText()))
  89. CurrentCI.Text = C->getText();
  90. }
  91. void ClangDocCommentVisitor::visitInlineCommandComment(
  92. const InlineCommandComment *C) {
  93. CurrentCI.Name = getCommandName(C->getCommandID());
  94. for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
  95. CurrentCI.Args.push_back(C->getArgText(I));
  96. }
  97. void ClangDocCommentVisitor::visitHTMLStartTagComment(
  98. const HTMLStartTagComment *C) {
  99. CurrentCI.Name = C->getTagName();
  100. CurrentCI.SelfClosing = C->isSelfClosing();
  101. for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) {
  102. const HTMLStartTagComment::Attribute &Attr = C->getAttr(I);
  103. CurrentCI.AttrKeys.push_back(Attr.Name);
  104. CurrentCI.AttrValues.push_back(Attr.Value);
  105. }
  106. }
  107. void ClangDocCommentVisitor::visitHTMLEndTagComment(
  108. const HTMLEndTagComment *C) {
  109. CurrentCI.Name = C->getTagName();
  110. CurrentCI.SelfClosing = true;
  111. }
  112. void ClangDocCommentVisitor::visitBlockCommandComment(
  113. const BlockCommandComment *C) {
  114. CurrentCI.Name = getCommandName(C->getCommandID());
  115. for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
  116. CurrentCI.Args.push_back(C->getArgText(I));
  117. }
  118. void ClangDocCommentVisitor::visitParamCommandComment(
  119. const ParamCommandComment *C) {
  120. CurrentCI.Direction =
  121. ParamCommandComment::getDirectionAsString(C->getDirection());
  122. CurrentCI.Explicit = C->isDirectionExplicit();
  123. if (C->hasParamName())
  124. CurrentCI.ParamName = C->getParamNameAsWritten();
  125. }
  126. void ClangDocCommentVisitor::visitTParamCommandComment(
  127. const TParamCommandComment *C) {
  128. if (C->hasParamName())
  129. CurrentCI.ParamName = C->getParamNameAsWritten();
  130. }
  131. void ClangDocCommentVisitor::visitVerbatimBlockComment(
  132. const VerbatimBlockComment *C) {
  133. CurrentCI.Name = getCommandName(C->getCommandID());
  134. CurrentCI.CloseName = C->getCloseName();
  135. }
  136. void ClangDocCommentVisitor::visitVerbatimBlockLineComment(
  137. const VerbatimBlockLineComment *C) {
  138. if (!isWhitespaceOnly(C->getText()))
  139. CurrentCI.Text = C->getText();
  140. }
  141. void ClangDocCommentVisitor::visitVerbatimLineComment(
  142. const VerbatimLineComment *C) {
  143. if (!isWhitespaceOnly(C->getText()))
  144. CurrentCI.Text = C->getText();
  145. }
  146. bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const {
  147. return llvm::all_of(S, isspace);
  148. }
  149. std::string ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
  150. const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
  151. if (Info)
  152. return Info->Name;
  153. // TODO: Add parsing for \file command.
  154. return "<not a builtin command>";
  155. }
  156. // Serializing functions.
  157. std::string getSourceCode(const Decl *D, const SourceRange &R) {
  158. return Lexer::getSourceText(CharSourceRange::getTokenRange(R),
  159. D->getASTContext().getSourceManager(),
  160. D->getASTContext().getLangOpts())
  161. .str();
  162. }
  163. template <typename T> static std::string serialize(T &I) {
  164. SmallString<2048> Buffer;
  165. llvm::BitstreamWriter Stream(Buffer);
  166. ClangDocBitcodeWriter Writer(Stream);
  167. Writer.emitBlock(I);
  168. return Buffer.str().str();
  169. }
  170. std::string serialize(std::unique_ptr<Info> &I) {
  171. switch (I->IT) {
  172. case InfoType::IT_namespace:
  173. return serialize(*static_cast<NamespaceInfo *>(I.get()));
  174. case InfoType::IT_record:
  175. return serialize(*static_cast<RecordInfo *>(I.get()));
  176. case InfoType::IT_enum:
  177. return serialize(*static_cast<EnumInfo *>(I.get()));
  178. case InfoType::IT_function:
  179. return serialize(*static_cast<FunctionInfo *>(I.get()));
  180. default:
  181. return "";
  182. }
  183. }
  184. static void parseFullComment(const FullComment *C, CommentInfo &CI) {
  185. ClangDocCommentVisitor Visitor(CI);
  186. Visitor.parseComment(C);
  187. }
  188. static SymbolID getUSRForDecl(const Decl *D) {
  189. llvm::SmallString<128> USR;
  190. if (index::generateUSRForDecl(D, USR))
  191. return SymbolID();
  192. return hashUSR(USR);
  193. }
  194. static TagDecl *getTagDeclForType(const QualType &T) {
  195. if (const TagDecl *D = T->getAsTagDecl())
  196. return D->getDefinition();
  197. return nullptr;
  198. }
  199. static RecordDecl *getRecordDeclForType(const QualType &T) {
  200. if (const RecordDecl *D = T->getAsRecordDecl())
  201. return D->getDefinition();
  202. return nullptr;
  203. }
  204. TypeInfo getTypeInfoForType(const QualType &T) {
  205. const TagDecl *TD = getTagDeclForType(T);
  206. if (!TD)
  207. return TypeInfo(Reference(SymbolID(), T.getAsString()));
  208. InfoType IT;
  209. if (dyn_cast<EnumDecl>(TD)) {
  210. IT = InfoType::IT_enum;
  211. } else if (dyn_cast<RecordDecl>(TD)) {
  212. IT = InfoType::IT_record;
  213. } else {
  214. IT = InfoType::IT_default;
  215. }
  216. return TypeInfo(Reference(getUSRForDecl(TD), TD->getNameAsString(), IT,
  217. T.getAsString(), getInfoRelativePath(TD)));
  218. }
  219. static bool isPublic(const clang::AccessSpecifier AS,
  220. const clang::Linkage Link) {
  221. if (AS == clang::AccessSpecifier::AS_private)
  222. return false;
  223. else if ((Link == clang::Linkage::ModuleLinkage) ||
  224. (Link == clang::Linkage::ExternalLinkage))
  225. return true;
  226. return false; // otherwise, linkage is some form of internal linkage
  227. }
  228. static bool shouldSerializeInfo(bool PublicOnly, bool IsInAnonymousNamespace,
  229. const NamedDecl *D) {
  230. bool IsAnonymousNamespace = false;
  231. if (const auto *N = dyn_cast<NamespaceDecl>(D))
  232. IsAnonymousNamespace = N->isAnonymousNamespace();
  233. return !PublicOnly ||
  234. (!IsInAnonymousNamespace && !IsAnonymousNamespace &&
  235. isPublic(D->getAccessUnsafe(), D->getLinkageInternal()));
  236. }
  237. // The InsertChild functions insert the given info into the given scope using
  238. // the method appropriate for that type. Some types are moved into the
  239. // appropriate vector, while other types have Reference objects generated to
  240. // refer to them.
  241. //
  242. // See MakeAndInsertIntoParent().
  243. static void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) {
  244. Scope.Namespaces.emplace_back(Info.USR, Info.Name, InfoType::IT_namespace,
  245. Info.Name, getInfoRelativePath(Info.Namespace));
  246. }
  247. static void InsertChild(ScopeChildren &Scope, const RecordInfo &Info) {
  248. Scope.Records.emplace_back(Info.USR, Info.Name, InfoType::IT_record,
  249. Info.Name, getInfoRelativePath(Info.Namespace));
  250. }
  251. static void InsertChild(ScopeChildren &Scope, EnumInfo Info) {
  252. Scope.Enums.push_back(std::move(Info));
  253. }
  254. static void InsertChild(ScopeChildren &Scope, FunctionInfo Info) {
  255. Scope.Functions.push_back(std::move(Info));
  256. }
  257. static void InsertChild(ScopeChildren &Scope, TypedefInfo Info) {
  258. Scope.Typedefs.push_back(std::move(Info));
  259. }
  260. // Creates a parent of the correct type for the given child and inserts it into
  261. // that parent.
  262. //
  263. // This is complicated by the fact that namespaces and records are inserted by
  264. // reference (constructing a "Reference" object with that namespace/record's
  265. // info), while everything else is inserted by moving it directly into the child
  266. // vectors.
  267. //
  268. // For namespaces and records, explicitly specify a const& template parameter
  269. // when invoking this function:
  270. // MakeAndInsertIntoParent<const Record&>(...);
  271. // Otherwise, specify an rvalue reference <EnumInfo&&> and move into the
  272. // parameter. Since each variant is used once, it's not worth having a more
  273. // elaborate system to automatically deduce this information.
  274. template <typename ChildType>
  275. std::unique_ptr<Info> MakeAndInsertIntoParent(ChildType Child) {
  276. if (Child.Namespace.empty()) {
  277. // Insert into unnamed parent namespace.
  278. auto ParentNS = std::make_unique<NamespaceInfo>();
  279. InsertChild(ParentNS->Children, std::forward<ChildType>(Child));
  280. return ParentNS;
  281. }
  282. switch (Child.Namespace[0].RefType) {
  283. case InfoType::IT_namespace: {
  284. auto ParentNS = std::make_unique<NamespaceInfo>();
  285. ParentNS->USR = Child.Namespace[0].USR;
  286. InsertChild(ParentNS->Children, std::forward<ChildType>(Child));
  287. return ParentNS;
  288. }
  289. case InfoType::IT_record: {
  290. auto ParentRec = std::make_unique<RecordInfo>();
  291. ParentRec->USR = Child.Namespace[0].USR;
  292. InsertChild(ParentRec->Children, std::forward<ChildType>(Child));
  293. return ParentRec;
  294. }
  295. default:
  296. llvm_unreachable("Invalid reference type for parent namespace");
  297. }
  298. }
  299. // There are two uses for this function.
  300. // 1) Getting the resulting mode of inheritance of a record.
  301. // Example: class A {}; class B : private A {}; class C : public B {};
  302. // It's explicit that C is publicly inherited from C and B is privately
  303. // inherited from A. It's not explicit but C is also privately inherited from
  304. // A. This is the AS that this function calculates. FirstAS is the
  305. // inheritance mode of `class C : B` and SecondAS is the inheritance mode of
  306. // `class B : A`.
  307. // 2) Getting the inheritance mode of an inherited attribute / method.
  308. // Example : class A { public: int M; }; class B : private A {};
  309. // Class B is inherited from class A, which has a public attribute. This
  310. // attribute is now part of the derived class B but it's not public. This
  311. // will be private because the inheritance is private. This is the AS that
  312. // this function calculates. FirstAS is the inheritance mode and SecondAS is
  313. // the AS of the attribute / method.
  314. static AccessSpecifier getFinalAccessSpecifier(AccessSpecifier FirstAS,
  315. AccessSpecifier SecondAS) {
  316. if (FirstAS == AccessSpecifier::AS_none ||
  317. SecondAS == AccessSpecifier::AS_none)
  318. return AccessSpecifier::AS_none;
  319. if (FirstAS == AccessSpecifier::AS_private ||
  320. SecondAS == AccessSpecifier::AS_private)
  321. return AccessSpecifier::AS_private;
  322. if (FirstAS == AccessSpecifier::AS_protected ||
  323. SecondAS == AccessSpecifier::AS_protected)
  324. return AccessSpecifier::AS_protected;
  325. return AccessSpecifier::AS_public;
  326. }
  327. // The Access parameter is only provided when parsing the field of an inherited
  328. // record, the access specification of the field depends on the inheritance mode
  329. static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly,
  330. AccessSpecifier Access = AccessSpecifier::AS_public) {
  331. for (const FieldDecl *F : D->fields()) {
  332. if (!shouldSerializeInfo(PublicOnly, /*IsInAnonymousNamespace=*/false, F))
  333. continue;
  334. // Use getAccessUnsafe so that we just get the default AS_none if it's not
  335. // valid, as opposed to an assert.
  336. MemberTypeInfo &NewMember = I.Members.emplace_back(
  337. getTypeInfoForType(F->getTypeSourceInfo()->getType()),
  338. F->getNameAsString(),
  339. getFinalAccessSpecifier(Access, F->getAccessUnsafe()));
  340. populateMemberTypeInfo(NewMember, F);
  341. }
  342. }
  343. static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
  344. for (const EnumConstantDecl *E : D->enumerators()) {
  345. std::string ValueExpr;
  346. if (const Expr *InitExpr = E->getInitExpr())
  347. ValueExpr = getSourceCode(D, InitExpr->getSourceRange());
  348. SmallString<16> ValueStr;
  349. E->getInitVal().toString(ValueStr);
  350. I.Members.emplace_back(E->getNameAsString(), ValueStr, ValueExpr);
  351. }
  352. }
  353. static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
  354. for (const ParmVarDecl *P : D->parameters()) {
  355. FieldTypeInfo &FieldInfo = I.Params.emplace_back(
  356. getTypeInfoForType(P->getOriginalType()), P->getNameAsString());
  357. FieldInfo.DefaultValue = getSourceCode(D, P->getDefaultArgRange());
  358. }
  359. }
  360. // TODO: Remove the serialization of Parents and VirtualParents, this
  361. // information is also extracted in the other definition of parseBases.
  362. static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
  363. // Don't parse bases if this isn't a definition.
  364. if (!D->isThisDeclarationADefinition())
  365. return;
  366. for (const CXXBaseSpecifier &B : D->bases()) {
  367. if (B.isVirtual())
  368. continue;
  369. if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
  370. const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
  371. I.Parents.emplace_back(getUSRForDecl(D), B.getType().getAsString(),
  372. InfoType::IT_record, B.getType().getAsString());
  373. } else if (const RecordDecl *P = getRecordDeclForType(B.getType()))
  374. I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
  375. InfoType::IT_record, P->getQualifiedNameAsString(),
  376. getInfoRelativePath(P));
  377. else
  378. I.Parents.emplace_back(SymbolID(), B.getType().getAsString());
  379. }
  380. for (const CXXBaseSpecifier &B : D->vbases()) {
  381. if (const RecordDecl *P = getRecordDeclForType(B.getType()))
  382. I.VirtualParents.emplace_back(
  383. getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record,
  384. P->getQualifiedNameAsString(), getInfoRelativePath(P));
  385. else
  386. I.VirtualParents.emplace_back(SymbolID(), B.getType().getAsString());
  387. }
  388. }
  389. template <typename T>
  390. static void
  391. populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
  392. const T *D, bool &IsInAnonymousNamespace) {
  393. const DeclContext *DC = D->getDeclContext();
  394. do {
  395. if (const auto *N = dyn_cast<NamespaceDecl>(DC)) {
  396. std::string Namespace;
  397. if (N->isAnonymousNamespace()) {
  398. Namespace = "@nonymous_namespace";
  399. IsInAnonymousNamespace = true;
  400. } else
  401. Namespace = N->getNameAsString();
  402. Namespaces.emplace_back(getUSRForDecl(N), Namespace,
  403. InfoType::IT_namespace,
  404. N->getQualifiedNameAsString());
  405. } else if (const auto *N = dyn_cast<RecordDecl>(DC))
  406. Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
  407. InfoType::IT_record,
  408. N->getQualifiedNameAsString());
  409. else if (const auto *N = dyn_cast<FunctionDecl>(DC))
  410. Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
  411. InfoType::IT_function,
  412. N->getQualifiedNameAsString());
  413. else if (const auto *N = dyn_cast<EnumDecl>(DC))
  414. Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
  415. InfoType::IT_enum, N->getQualifiedNameAsString());
  416. } while ((DC = DC->getParent()));
  417. // The global namespace should be added to the list of namespaces if the decl
  418. // corresponds to a Record and if it doesn't have any namespace (because this
  419. // means it's in the global namespace). Also if its outermost namespace is a
  420. // record because that record matches the previous condition mentioned.
  421. if ((Namespaces.empty() && isa<RecordDecl>(D)) ||
  422. (!Namespaces.empty() && Namespaces.back().RefType == InfoType::IT_record))
  423. Namespaces.emplace_back(SymbolID(), "GlobalNamespace",
  424. InfoType::IT_namespace);
  425. }
  426. void PopulateTemplateParameters(std::optional<TemplateInfo> &TemplateInfo,
  427. const clang::Decl *D) {
  428. if (const TemplateParameterList *ParamList =
  429. D->getDescribedTemplateParams()) {
  430. if (!TemplateInfo) {
  431. TemplateInfo.emplace();
  432. }
  433. for (const NamedDecl *ND : *ParamList) {
  434. TemplateInfo->Params.emplace_back(
  435. getSourceCode(ND, ND->getSourceRange()));
  436. }
  437. }
  438. }
  439. TemplateParamInfo TemplateArgumentToInfo(const clang::Decl *D,
  440. const TemplateArgument &Arg) {
  441. // The TemplateArgument's pretty printing handles all the normal cases
  442. // well enough for our requirements.
  443. std::string Str;
  444. llvm::raw_string_ostream Stream(Str);
  445. Arg.print(PrintingPolicy(D->getLangOpts()), Stream, false);
  446. return TemplateParamInfo(Str);
  447. }
  448. template <typename T>
  449. static void populateInfo(Info &I, const T *D, const FullComment *C,
  450. bool &IsInAnonymousNamespace) {
  451. I.USR = getUSRForDecl(D);
  452. I.Name = D->getNameAsString();
  453. populateParentNamespaces(I.Namespace, D, IsInAnonymousNamespace);
  454. if (C) {
  455. I.Description.emplace_back();
  456. parseFullComment(C, I.Description.back());
  457. }
  458. }
  459. template <typename T>
  460. static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
  461. int LineNumber, StringRef Filename,
  462. bool IsFileInRootDir,
  463. bool &IsInAnonymousNamespace) {
  464. populateInfo(I, D, C, IsInAnonymousNamespace);
  465. if (D->isThisDeclarationADefinition())
  466. I.DefLoc.emplace(LineNumber, Filename, IsFileInRootDir);
  467. else
  468. I.Loc.emplace_back(LineNumber, Filename, IsFileInRootDir);
  469. }
  470. static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
  471. const FullComment *FC, int LineNumber,
  472. StringRef Filename, bool IsFileInRootDir,
  473. bool &IsInAnonymousNamespace) {
  474. populateSymbolInfo(I, D, FC, LineNumber, Filename, IsFileInRootDir,
  475. IsInAnonymousNamespace);
  476. I.ReturnType = getTypeInfoForType(D->getReturnType());
  477. parseParameters(I, D);
  478. PopulateTemplateParameters(I.Template, D);
  479. // Handle function template specializations.
  480. if (const FunctionTemplateSpecializationInfo *FTSI =
  481. D->getTemplateSpecializationInfo()) {
  482. if (!I.Template)
  483. I.Template.emplace();
  484. I.Template->Specialization.emplace();
  485. auto &Specialization = *I.Template->Specialization;
  486. Specialization.SpecializationOf = getUSRForDecl(FTSI->getTemplate());
  487. // Template parameters to the specialization.
  488. if (FTSI->TemplateArguments) {
  489. for (const TemplateArgument &Arg : FTSI->TemplateArguments->asArray()) {
  490. Specialization.Params.push_back(TemplateArgumentToInfo(D, Arg));
  491. }
  492. }
  493. }
  494. }
  495. static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) {
  496. assert(D && "Expect non-null FieldDecl in populateMemberTypeInfo");
  497. ASTContext& Context = D->getASTContext();
  498. // TODO investigate whether we can use ASTContext::getCommentForDecl instead
  499. // of this logic. See also similar code in Mapper.cpp.
  500. RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
  501. if (!Comment)
  502. return;
  503. Comment->setAttached();
  504. if (comments::FullComment* fc = Comment->parse(Context, nullptr, D)) {
  505. I.Description.emplace_back();
  506. parseFullComment(fc, I.Description.back());
  507. }
  508. }
  509. static void
  510. parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
  511. bool PublicOnly, bool IsParent,
  512. AccessSpecifier ParentAccess = AccessSpecifier::AS_public) {
  513. // Don't parse bases if this isn't a definition.
  514. if (!D->isThisDeclarationADefinition())
  515. return;
  516. for (const CXXBaseSpecifier &B : D->bases()) {
  517. if (const RecordType *Ty = B.getType()->getAs<RecordType>()) {
  518. if (const CXXRecordDecl *Base =
  519. cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition())) {
  520. // Initialized without USR and name, this will be set in the following
  521. // if-else stmt.
  522. BaseRecordInfo BI(
  523. {}, "", getInfoRelativePath(Base), B.isVirtual(),
  524. getFinalAccessSpecifier(ParentAccess, B.getAccessSpecifier()),
  525. IsParent);
  526. if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
  527. const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
  528. BI.USR = getUSRForDecl(D);
  529. BI.Name = B.getType().getAsString();
  530. } else {
  531. BI.USR = getUSRForDecl(Base);
  532. BI.Name = Base->getNameAsString();
  533. }
  534. parseFields(BI, Base, PublicOnly, BI.Access);
  535. for (const auto &Decl : Base->decls())
  536. if (const auto *MD = dyn_cast<CXXMethodDecl>(Decl)) {
  537. // Don't serialize private methods
  538. if (MD->getAccessUnsafe() == AccessSpecifier::AS_private ||
  539. !MD->isUserProvided())
  540. continue;
  541. FunctionInfo FI;
  542. FI.IsMethod = true;
  543. // The seventh arg in populateFunctionInfo is a boolean passed by
  544. // reference, its value is not relevant in here so it's not used
  545. // anywhere besides the function call.
  546. bool IsInAnonymousNamespace;
  547. populateFunctionInfo(FI, MD, /*FullComment=*/{}, /*LineNumber=*/{},
  548. /*FileName=*/{}, IsFileInRootDir,
  549. IsInAnonymousNamespace);
  550. FI.Access =
  551. getFinalAccessSpecifier(BI.Access, MD->getAccessUnsafe());
  552. BI.Children.Functions.emplace_back(std::move(FI));
  553. }
  554. I.Bases.emplace_back(std::move(BI));
  555. // Call this function recursively to get the inherited classes of
  556. // this base; these new bases will also get stored in the original
  557. // RecordInfo: I.
  558. parseBases(I, Base, IsFileInRootDir, PublicOnly, false,
  559. I.Bases.back().Access);
  560. }
  561. }
  562. }
  563. }
  564. std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
  565. emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
  566. llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
  567. auto I = std::make_unique<NamespaceInfo>();
  568. bool IsInAnonymousNamespace = false;
  569. populateInfo(*I, D, FC, IsInAnonymousNamespace);
  570. if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
  571. return {};
  572. I->Name = D->isAnonymousNamespace()
  573. ? llvm::SmallString<16>("@nonymous_namespace")
  574. : I->Name;
  575. I->Path = getInfoRelativePath(I->Namespace);
  576. if (I->Namespace.empty() && I->USR == SymbolID())
  577. return {std::unique_ptr<Info>{std::move(I)}, nullptr};
  578. // Namespaces are inserted into the parent by reference, so we need to return
  579. // both the parent and the record itself.
  580. return {std::move(I), MakeAndInsertIntoParent<const NamespaceInfo &>(*I)};
  581. }
  582. std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
  583. emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
  584. llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
  585. auto I = std::make_unique<RecordInfo>();
  586. bool IsInAnonymousNamespace = false;
  587. populateSymbolInfo(*I, D, FC, LineNumber, File, IsFileInRootDir,
  588. IsInAnonymousNamespace);
  589. if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
  590. return {};
  591. I->TagType = D->getTagKind();
  592. parseFields(*I, D, PublicOnly);
  593. if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
  594. if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl()) {
  595. I->Name = TD->getNameAsString();
  596. I->IsTypeDef = true;
  597. }
  598. // TODO: remove first call to parseBases, that function should be deleted
  599. parseBases(*I, C);
  600. parseBases(*I, C, IsFileInRootDir, PublicOnly, true);
  601. }
  602. I->Path = getInfoRelativePath(I->Namespace);
  603. PopulateTemplateParameters(I->Template, D);
  604. // Full and partial specializations.
  605. if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
  606. if (!I->Template)
  607. I->Template.emplace();
  608. I->Template->Specialization.emplace();
  609. auto &Specialization = *I->Template->Specialization;
  610. // What this is a specialization of.
  611. auto SpecOf = CTSD->getSpecializedTemplateOrPartial();
  612. if (SpecOf.is<ClassTemplateDecl *>()) {
  613. Specialization.SpecializationOf =
  614. getUSRForDecl(SpecOf.get<ClassTemplateDecl *>());
  615. } else if (SpecOf.is<ClassTemplatePartialSpecializationDecl *>()) {
  616. Specialization.SpecializationOf =
  617. getUSRForDecl(SpecOf.get<ClassTemplatePartialSpecializationDecl *>());
  618. }
  619. // Parameters to the specilization. For partial specializations, get the
  620. // parameters "as written" from the ClassTemplatePartialSpecializationDecl
  621. // because the non-explicit template parameters will have generated internal
  622. // placeholder names rather than the names the user typed that match the
  623. // template parameters.
  624. if (const ClassTemplatePartialSpecializationDecl *CTPSD =
  625. dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
  626. if (const ASTTemplateArgumentListInfo *AsWritten =
  627. CTPSD->getTemplateArgsAsWritten()) {
  628. for (unsigned i = 0; i < AsWritten->getNumTemplateArgs(); i++) {
  629. Specialization.Params.emplace_back(
  630. getSourceCode(D, (*AsWritten)[i].getSourceRange()));
  631. }
  632. }
  633. } else {
  634. for (const TemplateArgument &Arg : CTSD->getTemplateArgs().asArray()) {
  635. Specialization.Params.push_back(TemplateArgumentToInfo(D, Arg));
  636. }
  637. }
  638. }
  639. // Records are inserted into the parent by reference, so we need to return
  640. // both the parent and the record itself.
  641. auto Parent = MakeAndInsertIntoParent<const RecordInfo &>(*I);
  642. return {std::move(I), std::move(Parent)};
  643. }
  644. std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
  645. emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
  646. llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
  647. FunctionInfo Func;
  648. bool IsInAnonymousNamespace = false;
  649. populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir,
  650. IsInAnonymousNamespace);
  651. Func.Access = clang::AccessSpecifier::AS_none;
  652. if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
  653. return {};
  654. // Info is wrapped in its parent scope so is returned in the second position.
  655. return {nullptr, MakeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
  656. }
  657. std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
  658. emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
  659. llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
  660. FunctionInfo Func;
  661. bool IsInAnonymousNamespace = false;
  662. populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir,
  663. IsInAnonymousNamespace);
  664. if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
  665. return {};
  666. Func.IsMethod = true;
  667. const NamedDecl *Parent = nullptr;
  668. if (const auto *SD =
  669. dyn_cast<ClassTemplateSpecializationDecl>(D->getParent()))
  670. Parent = SD->getSpecializedTemplate();
  671. else
  672. Parent = D->getParent();
  673. SymbolID ParentUSR = getUSRForDecl(Parent);
  674. Func.Parent =
  675. Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record,
  676. Parent->getQualifiedNameAsString()};
  677. Func.Access = D->getAccess();
  678. // Info is wrapped in its parent scope so is returned in the second position.
  679. return {nullptr, MakeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
  680. }
  681. std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
  682. emitInfo(const TypedefDecl *D, const FullComment *FC, int LineNumber,
  683. StringRef File, bool IsFileInRootDir, bool PublicOnly) {
  684. TypedefInfo Info;
  685. bool IsInAnonymousNamespace = false;
  686. populateInfo(Info, D, FC, IsInAnonymousNamespace);
  687. if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
  688. return {};
  689. Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir);
  690. Info.Underlying = getTypeInfoForType(D->getUnderlyingType());
  691. if (Info.Underlying.Type.Name.empty()) {
  692. // Typedef for an unnamed type. This is like "typedef struct { } Foo;"
  693. // The record serializer explicitly checks for this syntax and constructs
  694. // a record with that name, so we don't want to emit a duplicate here.
  695. return {};
  696. }
  697. Info.IsUsing = false;
  698. // Info is wrapped in its parent scope so is returned in the second position.
  699. return {nullptr, MakeAndInsertIntoParent<TypedefInfo &&>(std::move(Info))};
  700. }
  701. // A type alias is a C++ "using" declaration for a type. It gets mapped to a
  702. // TypedefInfo with the IsUsing flag set.
  703. std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
  704. emitInfo(const TypeAliasDecl *D, const FullComment *FC, int LineNumber,
  705. StringRef File, bool IsFileInRootDir, bool PublicOnly) {
  706. TypedefInfo Info;
  707. bool IsInAnonymousNamespace = false;
  708. populateInfo(Info, D, FC, IsInAnonymousNamespace);
  709. if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
  710. return {};
  711. Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir);
  712. Info.Underlying = getTypeInfoForType(D->getUnderlyingType());
  713. Info.IsUsing = true;
  714. // Info is wrapped in its parent scope so is returned in the second position.
  715. return {nullptr, MakeAndInsertIntoParent<TypedefInfo &&>(std::move(Info))};
  716. }
  717. std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
  718. emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
  719. llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
  720. EnumInfo Enum;
  721. bool IsInAnonymousNamespace = false;
  722. populateSymbolInfo(Enum, D, FC, LineNumber, File, IsFileInRootDir,
  723. IsInAnonymousNamespace);
  724. if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
  725. return {};
  726. Enum.Scoped = D->isScoped();
  727. if (D->isFixed()) {
  728. auto Name = D->getIntegerType().getAsString();
  729. Enum.BaseType = TypeInfo(Name, Name);
  730. }
  731. parseEnumerators(Enum, D);
  732. // Info is wrapped in its parent scope so is returned in the second position.
  733. return {nullptr, MakeAndInsertIntoParent<EnumInfo &&>(std::move(Enum))};
  734. }
  735. } // namespace serialize
  736. } // namespace doc
  737. } // namespace clang