xref: /llvm-project/clang-tools-extra/clang-doc/Serialize.cpp (revision b68a952ae1c06b78790eab758574d992159e33b8)
1ffe9f00cSFangrui Song //===-- Serialize.cpp - ClangDoc Serializer ---------------------*- C++ -*-===//
2e975a473SJulie Hockett //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e975a473SJulie Hockett //
7e975a473SJulie Hockett //===----------------------------------------------------------------------===//
8e975a473SJulie Hockett 
9e975a473SJulie Hockett #include "Serialize.h"
10e975a473SJulie Hockett #include "BitcodeWriter.h"
11e975a473SJulie Hockett #include "clang/AST/Comment.h"
12e975a473SJulie Hockett #include "clang/Index/USRGeneration.h"
13e191086bSBrett Wilson #include "clang/Lex/Lexer.h"
14e975a473SJulie Hockett #include "llvm/ADT/Hashing.h"
15e975a473SJulie Hockett #include "llvm/ADT/StringExtras.h"
16e975a473SJulie Hockett #include "llvm/Support/SHA1.h"
17e975a473SJulie Hockett 
18e975a473SJulie Hockett using clang::comments::FullComment;
19e975a473SJulie Hockett 
20e975a473SJulie Hockett namespace clang {
21e975a473SJulie Hockett namespace doc {
22e975a473SJulie Hockett namespace serialize {
23e975a473SJulie Hockett 
24e975a473SJulie Hockett SymbolID hashUSR(llvm::StringRef USR) {
25e975a473SJulie Hockett   return llvm::SHA1::hash(arrayRefFromStringRef(USR));
26e975a473SJulie Hockett }
27e975a473SJulie Hockett 
282c1c9a24SJulie Hockett template <typename T>
292c1c9a24SJulie Hockett static void
302c1c9a24SJulie Hockett populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
312c1c9a24SJulie Hockett                          const T *D, bool &IsAnonymousNamespace);
322c1c9a24SJulie Hockett 
3399baa10fSBrett Wilson static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D);
3499baa10fSBrett Wilson 
352c1c9a24SJulie Hockett // A function to extract the appropriate relative path for a given info's
362c1c9a24SJulie Hockett // documentation. The path returned is a composite of the parent namespaces.
372c1c9a24SJulie Hockett //
38b7ecf1c1SKazuaki Ishizaki // Example: Given the below, the directory path for class C info will be
392c1c9a24SJulie Hockett // <root>/A/B
402c1c9a24SJulie Hockett //
412c1c9a24SJulie Hockett // namespace A {
42dd5571d5SKazuaki Ishizaki // namespace B {
432c1c9a24SJulie Hockett //
442c1c9a24SJulie Hockett // class C {};
452c1c9a24SJulie Hockett //
462c1c9a24SJulie Hockett // }
472c1c9a24SJulie Hockett // }
482c1c9a24SJulie Hockett llvm::SmallString<128>
492c1c9a24SJulie Hockett getInfoRelativePath(const llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
502c1c9a24SJulie Hockett   llvm::SmallString<128> Path;
512c1c9a24SJulie Hockett   for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
522c1c9a24SJulie Hockett     llvm::sys::path::append(Path, R->Name);
532c1c9a24SJulie Hockett   return Path;
542c1c9a24SJulie Hockett }
552c1c9a24SJulie Hockett 
562c1c9a24SJulie Hockett llvm::SmallString<128> getInfoRelativePath(const Decl *D) {
572c1c9a24SJulie Hockett   llvm::SmallVector<Reference, 4> Namespaces;
582c1c9a24SJulie Hockett   // The third arg in populateParentNamespaces is a boolean passed by reference,
592c1c9a24SJulie Hockett   // its value is not relevant in here so it's not used anywhere besides the
602c1c9a24SJulie Hockett   // function call
612c1c9a24SJulie Hockett   bool B = true;
622c1c9a24SJulie Hockett   populateParentNamespaces(Namespaces, D, B);
632c1c9a24SJulie Hockett   return getInfoRelativePath(Namespaces);
642c1c9a24SJulie Hockett }
652c1c9a24SJulie Hockett 
66e975a473SJulie Hockett class ClangDocCommentVisitor
67e975a473SJulie Hockett     : public ConstCommentVisitor<ClangDocCommentVisitor> {
68e975a473SJulie Hockett public:
69e975a473SJulie Hockett   ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {}
70e975a473SJulie Hockett 
71e975a473SJulie Hockett   void parseComment(const comments::Comment *C);
72e975a473SJulie Hockett 
73e975a473SJulie Hockett   void visitTextComment(const TextComment *C);
74e975a473SJulie Hockett   void visitInlineCommandComment(const InlineCommandComment *C);
75e975a473SJulie Hockett   void visitHTMLStartTagComment(const HTMLStartTagComment *C);
76e975a473SJulie Hockett   void visitHTMLEndTagComment(const HTMLEndTagComment *C);
77e975a473SJulie Hockett   void visitBlockCommandComment(const BlockCommandComment *C);
78e975a473SJulie Hockett   void visitParamCommandComment(const ParamCommandComment *C);
79e975a473SJulie Hockett   void visitTParamCommandComment(const TParamCommandComment *C);
80e975a473SJulie Hockett   void visitVerbatimBlockComment(const VerbatimBlockComment *C);
81e975a473SJulie Hockett   void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
82e975a473SJulie Hockett   void visitVerbatimLineComment(const VerbatimLineComment *C);
83e975a473SJulie Hockett 
84e975a473SJulie Hockett private:
85e975a473SJulie Hockett   std::string getCommandName(unsigned CommandID) const;
86e975a473SJulie Hockett   bool isWhitespaceOnly(StringRef S) const;
87e975a473SJulie Hockett 
88e975a473SJulie Hockett   CommentInfo &CurrentCI;
89e975a473SJulie Hockett };
90e975a473SJulie Hockett 
91e975a473SJulie Hockett void ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
92e975a473SJulie Hockett   CurrentCI.Kind = C->getCommentKindName();
93e975a473SJulie Hockett   ConstCommentVisitor<ClangDocCommentVisitor>::visit(C);
94e975a473SJulie Hockett   for (comments::Comment *Child :
95e975a473SJulie Hockett        llvm::make_range(C->child_begin(), C->child_end())) {
961c705d9cSJonas Devlieghere     CurrentCI.Children.emplace_back(std::make_unique<CommentInfo>());
97e975a473SJulie Hockett     ClangDocCommentVisitor Visitor(*CurrentCI.Children.back());
98e975a473SJulie Hockett     Visitor.parseComment(Child);
99e975a473SJulie Hockett   }
100e975a473SJulie Hockett }
101e975a473SJulie Hockett 
102e975a473SJulie Hockett void ClangDocCommentVisitor::visitTextComment(const TextComment *C) {
103e975a473SJulie Hockett   if (!isWhitespaceOnly(C->getText()))
104e975a473SJulie Hockett     CurrentCI.Text = C->getText();
105e975a473SJulie Hockett }
106e975a473SJulie Hockett 
107e975a473SJulie Hockett void ClangDocCommentVisitor::visitInlineCommandComment(
108e975a473SJulie Hockett     const InlineCommandComment *C) {
109e975a473SJulie Hockett   CurrentCI.Name = getCommandName(C->getCommandID());
110e975a473SJulie Hockett   for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
111e975a473SJulie Hockett     CurrentCI.Args.push_back(C->getArgText(I));
112e975a473SJulie Hockett }
113e975a473SJulie Hockett 
114e975a473SJulie Hockett void ClangDocCommentVisitor::visitHTMLStartTagComment(
115e975a473SJulie Hockett     const HTMLStartTagComment *C) {
116e975a473SJulie Hockett   CurrentCI.Name = C->getTagName();
117e975a473SJulie Hockett   CurrentCI.SelfClosing = C->isSelfClosing();
118e975a473SJulie Hockett   for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) {
119e975a473SJulie Hockett     const HTMLStartTagComment::Attribute &Attr = C->getAttr(I);
120e975a473SJulie Hockett     CurrentCI.AttrKeys.push_back(Attr.Name);
121e975a473SJulie Hockett     CurrentCI.AttrValues.push_back(Attr.Value);
122e975a473SJulie Hockett   }
123e975a473SJulie Hockett }
124e975a473SJulie Hockett 
125e975a473SJulie Hockett void ClangDocCommentVisitor::visitHTMLEndTagComment(
126e975a473SJulie Hockett     const HTMLEndTagComment *C) {
127e975a473SJulie Hockett   CurrentCI.Name = C->getTagName();
128e975a473SJulie Hockett   CurrentCI.SelfClosing = true;
129e975a473SJulie Hockett }
130e975a473SJulie Hockett 
131e975a473SJulie Hockett void ClangDocCommentVisitor::visitBlockCommandComment(
132e975a473SJulie Hockett     const BlockCommandComment *C) {
133e975a473SJulie Hockett   CurrentCI.Name = getCommandName(C->getCommandID());
134e975a473SJulie Hockett   for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
135e975a473SJulie Hockett     CurrentCI.Args.push_back(C->getArgText(I));
136e975a473SJulie Hockett }
137e975a473SJulie Hockett 
138e975a473SJulie Hockett void ClangDocCommentVisitor::visitParamCommandComment(
139e975a473SJulie Hockett     const ParamCommandComment *C) {
140e975a473SJulie Hockett   CurrentCI.Direction =
141e975a473SJulie Hockett       ParamCommandComment::getDirectionAsString(C->getDirection());
142e975a473SJulie Hockett   CurrentCI.Explicit = C->isDirectionExplicit();
143e975a473SJulie Hockett   if (C->hasParamName())
144e975a473SJulie Hockett     CurrentCI.ParamName = C->getParamNameAsWritten();
145e975a473SJulie Hockett }
146e975a473SJulie Hockett 
147e975a473SJulie Hockett void ClangDocCommentVisitor::visitTParamCommandComment(
148e975a473SJulie Hockett     const TParamCommandComment *C) {
149e975a473SJulie Hockett   if (C->hasParamName())
150e975a473SJulie Hockett     CurrentCI.ParamName = C->getParamNameAsWritten();
151e975a473SJulie Hockett }
152e975a473SJulie Hockett 
153e975a473SJulie Hockett void ClangDocCommentVisitor::visitVerbatimBlockComment(
154e975a473SJulie Hockett     const VerbatimBlockComment *C) {
155e975a473SJulie Hockett   CurrentCI.Name = getCommandName(C->getCommandID());
156e975a473SJulie Hockett   CurrentCI.CloseName = C->getCloseName();
157e975a473SJulie Hockett }
158e975a473SJulie Hockett 
159e975a473SJulie Hockett void ClangDocCommentVisitor::visitVerbatimBlockLineComment(
160e975a473SJulie Hockett     const VerbatimBlockLineComment *C) {
161e975a473SJulie Hockett   if (!isWhitespaceOnly(C->getText()))
162e975a473SJulie Hockett     CurrentCI.Text = C->getText();
163e975a473SJulie Hockett }
164e975a473SJulie Hockett 
165e975a473SJulie Hockett void ClangDocCommentVisitor::visitVerbatimLineComment(
166e975a473SJulie Hockett     const VerbatimLineComment *C) {
167e975a473SJulie Hockett   if (!isWhitespaceOnly(C->getText()))
168e975a473SJulie Hockett     CurrentCI.Text = C->getText();
169e975a473SJulie Hockett }
170e975a473SJulie Hockett 
171e975a473SJulie Hockett bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const {
1726d9cd919SKazu Hirata   return llvm::all_of(S, isspace);
173e975a473SJulie Hockett }
174e975a473SJulie Hockett 
175e975a473SJulie Hockett std::string ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
176e975a473SJulie Hockett   const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
177e975a473SJulie Hockett   if (Info)
178e975a473SJulie Hockett     return Info->Name;
179e975a473SJulie Hockett   // TODO: Add parsing for \file command.
180e975a473SJulie Hockett   return "<not a builtin command>";
181e975a473SJulie Hockett }
182e975a473SJulie Hockett 
183e975a473SJulie Hockett // Serializing functions.
184e975a473SJulie Hockett 
185eaa7b324SBrett Wilson std::string getSourceCode(const Decl *D, const SourceRange &R) {
186eaa7b324SBrett Wilson   return Lexer::getSourceText(CharSourceRange::getTokenRange(R),
187eaa7b324SBrett Wilson                               D->getASTContext().getSourceManager(),
188eaa7b324SBrett Wilson                               D->getASTContext().getLangOpts())
189eaa7b324SBrett Wilson       .str();
190eaa7b324SBrett Wilson }
191eaa7b324SBrett Wilson 
192e975a473SJulie Hockett template <typename T> static std::string serialize(T &I) {
193e975a473SJulie Hockett   SmallString<2048> Buffer;
194e975a473SJulie Hockett   llvm::BitstreamWriter Stream(Buffer);
195e975a473SJulie Hockett   ClangDocBitcodeWriter Writer(Stream);
196e975a473SJulie Hockett   Writer.emitBlock(I);
197e975a473SJulie Hockett   return Buffer.str().str();
198e975a473SJulie Hockett }
199e975a473SJulie Hockett 
2008899c29bSJulie Hockett std::string serialize(std::unique_ptr<Info> &I) {
2018899c29bSJulie Hockett   switch (I->IT) {
2028899c29bSJulie Hockett   case InfoType::IT_namespace:
2038899c29bSJulie Hockett     return serialize(*static_cast<NamespaceInfo *>(I.get()));
2048899c29bSJulie Hockett   case InfoType::IT_record:
2058899c29bSJulie Hockett     return serialize(*static_cast<RecordInfo *>(I.get()));
2068899c29bSJulie Hockett   case InfoType::IT_enum:
2078899c29bSJulie Hockett     return serialize(*static_cast<EnumInfo *>(I.get()));
2088899c29bSJulie Hockett   case InfoType::IT_function:
2098899c29bSJulie Hockett     return serialize(*static_cast<FunctionInfo *>(I.get()));
2108899c29bSJulie Hockett   default:
2118899c29bSJulie Hockett     return "";
2128899c29bSJulie Hockett   }
2138899c29bSJulie Hockett }
2148899c29bSJulie Hockett 
215e975a473SJulie Hockett static void parseFullComment(const FullComment *C, CommentInfo &CI) {
216e975a473SJulie Hockett   ClangDocCommentVisitor Visitor(CI);
217e975a473SJulie Hockett   Visitor.parseComment(C);
218e975a473SJulie Hockett }
219e975a473SJulie Hockett 
220e975a473SJulie Hockett static SymbolID getUSRForDecl(const Decl *D) {
221e975a473SJulie Hockett   llvm::SmallString<128> USR;
222e975a473SJulie Hockett   if (index::generateUSRForDecl(D, USR))
223e975a473SJulie Hockett     return SymbolID();
224e975a473SJulie Hockett   return hashUSR(USR);
225e975a473SJulie Hockett }
226e975a473SJulie Hockett 
2274df84ac3SBrett Wilson static TagDecl *getTagDeclForType(const QualType &T) {
2284df84ac3SBrett Wilson   if (const TagDecl *D = T->getAsTagDecl())
2294df84ac3SBrett Wilson     return D->getDefinition();
2304df84ac3SBrett Wilson   return nullptr;
2314df84ac3SBrett Wilson }
2324df84ac3SBrett Wilson 
2334df84ac3SBrett Wilson static RecordDecl *getRecordDeclForType(const QualType &T) {
234b1f01e27SJulie Hockett   if (const RecordDecl *D = T->getAsRecordDecl())
235b1f01e27SJulie Hockett     return D->getDefinition();
236e975a473SJulie Hockett   return nullptr;
237e975a473SJulie Hockett }
238e975a473SJulie Hockett 
2392b932bc1SPaul Kirth TypeInfo getTypeInfoForType(const QualType &T, const PrintingPolicy &Policy) {
2404df84ac3SBrett Wilson   const TagDecl *TD = getTagDeclForType(T);
2414df84ac3SBrett Wilson   if (!TD)
2422b932bc1SPaul Kirth     return TypeInfo(Reference(SymbolID(), T.getAsString(Policy)));
2434df84ac3SBrett Wilson 
2444df84ac3SBrett Wilson   InfoType IT;
2454df84ac3SBrett Wilson   if (dyn_cast<EnumDecl>(TD)) {
2464df84ac3SBrett Wilson     IT = InfoType::IT_enum;
2474df84ac3SBrett Wilson   } else if (dyn_cast<RecordDecl>(TD)) {
2484df84ac3SBrett Wilson     IT = InfoType::IT_record;
2494df84ac3SBrett Wilson   } else {
2504df84ac3SBrett Wilson     IT = InfoType::IT_default;
2514df84ac3SBrett Wilson   }
2524df84ac3SBrett Wilson   return TypeInfo(Reference(getUSRForDecl(TD), TD->getNameAsString(), IT,
2532b932bc1SPaul Kirth                             T.getAsString(Policy), getInfoRelativePath(TD)));
2544df84ac3SBrett Wilson }
2554df84ac3SBrett Wilson 
256eb50a2e8SJulie Hockett static bool isPublic(const clang::AccessSpecifier AS,
257eb50a2e8SJulie Hockett                      const clang::Linkage Link) {
258eb50a2e8SJulie Hockett   if (AS == clang::AccessSpecifier::AS_private)
259eb50a2e8SJulie Hockett     return false;
26087759476SVlad Serebrennikov   else if ((Link == clang::Linkage::Module) ||
26187759476SVlad Serebrennikov            (Link == clang::Linkage::External))
262eb50a2e8SJulie Hockett     return true;
263eb50a2e8SJulie Hockett   return false; // otherwise, linkage is some form of internal linkage
264eb50a2e8SJulie Hockett }
265eb50a2e8SJulie Hockett 
266ba3d595fSDiego Astiazaran static bool shouldSerializeInfo(bool PublicOnly, bool IsInAnonymousNamespace,
267ba3d595fSDiego Astiazaran                                 const NamedDecl *D) {
268ba3d595fSDiego Astiazaran   bool IsAnonymousNamespace = false;
269ba3d595fSDiego Astiazaran   if (const auto *N = dyn_cast<NamespaceDecl>(D))
270ba3d595fSDiego Astiazaran     IsAnonymousNamespace = N->isAnonymousNamespace();
271ba3d595fSDiego Astiazaran   return !PublicOnly ||
272ba3d595fSDiego Astiazaran          (!IsInAnonymousNamespace && !IsAnonymousNamespace &&
273ba3d595fSDiego Astiazaran           isPublic(D->getAccessUnsafe(), D->getLinkageInternal()));
274ba3d595fSDiego Astiazaran }
275ba3d595fSDiego Astiazaran 
27621fb70c6SBrett Wilson // The InsertChild functions insert the given info into the given scope using
27721fb70c6SBrett Wilson // the method appropriate for that type. Some types are moved into the
27821fb70c6SBrett Wilson // appropriate vector, while other types have Reference objects generated to
27921fb70c6SBrett Wilson // refer to them.
28021fb70c6SBrett Wilson //
28121fb70c6SBrett Wilson // See MakeAndInsertIntoParent().
28221fb70c6SBrett Wilson static void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) {
28321fb70c6SBrett Wilson   Scope.Namespaces.emplace_back(Info.USR, Info.Name, InfoType::IT_namespace,
2844a68babdSBrett Wilson                                 Info.Name, getInfoRelativePath(Info.Namespace));
28521fb70c6SBrett Wilson }
28621fb70c6SBrett Wilson 
28721fb70c6SBrett Wilson static void InsertChild(ScopeChildren &Scope, const RecordInfo &Info) {
28821fb70c6SBrett Wilson   Scope.Records.emplace_back(Info.USR, Info.Name, InfoType::IT_record,
2894a68babdSBrett Wilson                              Info.Name, getInfoRelativePath(Info.Namespace));
29021fb70c6SBrett Wilson }
29121fb70c6SBrett Wilson 
29221fb70c6SBrett Wilson static void InsertChild(ScopeChildren &Scope, EnumInfo Info) {
29321fb70c6SBrett Wilson   Scope.Enums.push_back(std::move(Info));
29421fb70c6SBrett Wilson }
29521fb70c6SBrett Wilson 
29621fb70c6SBrett Wilson static void InsertChild(ScopeChildren &Scope, FunctionInfo Info) {
29721fb70c6SBrett Wilson   Scope.Functions.push_back(std::move(Info));
29821fb70c6SBrett Wilson }
29921fb70c6SBrett Wilson 
30021fb70c6SBrett Wilson static void InsertChild(ScopeChildren &Scope, TypedefInfo Info) {
30121fb70c6SBrett Wilson   Scope.Typedefs.push_back(std::move(Info));
30221fb70c6SBrett Wilson }
30321fb70c6SBrett Wilson 
30421fb70c6SBrett Wilson // Creates a parent of the correct type for the given child and inserts it into
30521fb70c6SBrett Wilson // that parent.
30621fb70c6SBrett Wilson //
30721fb70c6SBrett Wilson // This is complicated by the fact that namespaces and records are inserted by
30821fb70c6SBrett Wilson // reference (constructing a "Reference" object with that namespace/record's
30921fb70c6SBrett Wilson // info), while everything else is inserted by moving it directly into the child
31021fb70c6SBrett Wilson // vectors.
31121fb70c6SBrett Wilson //
31221fb70c6SBrett Wilson // For namespaces and records, explicitly specify a const& template parameter
31321fb70c6SBrett Wilson // when invoking this function:
31421fb70c6SBrett Wilson //   MakeAndInsertIntoParent<const Record&>(...);
31521fb70c6SBrett Wilson // Otherwise, specify an rvalue reference <EnumInfo&&> and move into the
31621fb70c6SBrett Wilson // parameter. Since each variant is used once, it's not worth having a more
31721fb70c6SBrett Wilson // elaborate system to automatically deduce this information.
31821fb70c6SBrett Wilson template <typename ChildType>
31921fb70c6SBrett Wilson std::unique_ptr<Info> MakeAndInsertIntoParent(ChildType Child) {
32021fb70c6SBrett Wilson   if (Child.Namespace.empty()) {
32121fb70c6SBrett Wilson     // Insert into unnamed parent namespace.
32221fb70c6SBrett Wilson     auto ParentNS = std::make_unique<NamespaceInfo>();
32321fb70c6SBrett Wilson     InsertChild(ParentNS->Children, std::forward<ChildType>(Child));
32421fb70c6SBrett Wilson     return ParentNS;
32521fb70c6SBrett Wilson   }
32621fb70c6SBrett Wilson 
32721fb70c6SBrett Wilson   switch (Child.Namespace[0].RefType) {
32821fb70c6SBrett Wilson   case InfoType::IT_namespace: {
32921fb70c6SBrett Wilson     auto ParentNS = std::make_unique<NamespaceInfo>();
33021fb70c6SBrett Wilson     ParentNS->USR = Child.Namespace[0].USR;
33121fb70c6SBrett Wilson     InsertChild(ParentNS->Children, std::forward<ChildType>(Child));
33221fb70c6SBrett Wilson     return ParentNS;
33321fb70c6SBrett Wilson   }
33421fb70c6SBrett Wilson   case InfoType::IT_record: {
33521fb70c6SBrett Wilson     auto ParentRec = std::make_unique<RecordInfo>();
33621fb70c6SBrett Wilson     ParentRec->USR = Child.Namespace[0].USR;
33721fb70c6SBrett Wilson     InsertChild(ParentRec->Children, std::forward<ChildType>(Child));
33821fb70c6SBrett Wilson     return ParentRec;
33921fb70c6SBrett Wilson   }
34021fb70c6SBrett Wilson   default:
34121fb70c6SBrett Wilson     llvm_unreachable("Invalid reference type for parent namespace");
34221fb70c6SBrett Wilson   }
34321fb70c6SBrett Wilson }
34421fb70c6SBrett Wilson 
345ba3d595fSDiego Astiazaran // There are two uses for this function.
346ba3d595fSDiego Astiazaran // 1) Getting the resulting mode of inheritance of a record.
347ba3d595fSDiego Astiazaran //    Example: class A {}; class B : private A {}; class C : public B {};
348ba3d595fSDiego Astiazaran //    It's explicit that C is publicly inherited from C and B is privately
349ba3d595fSDiego Astiazaran //    inherited from A. It's not explicit but C is also privately inherited from
350ba3d595fSDiego Astiazaran //    A. This is the AS that this function calculates. FirstAS is the
351ba3d595fSDiego Astiazaran //    inheritance mode of `class C : B` and SecondAS is the inheritance mode of
352ba3d595fSDiego Astiazaran //    `class B : A`.
353ba3d595fSDiego Astiazaran // 2) Getting the inheritance mode of an inherited attribute / method.
354ba3d595fSDiego Astiazaran //    Example : class A { public: int M; }; class B : private A {};
355ba3d595fSDiego Astiazaran //    Class B is inherited from class A, which has a public attribute. This
356ba3d595fSDiego Astiazaran //    attribute is now part of the derived class B but it's not public. This
357ba3d595fSDiego Astiazaran //    will be private because the inheritance is private. This is the AS that
358ba3d595fSDiego Astiazaran //    this function calculates. FirstAS is the inheritance mode and SecondAS is
359ba3d595fSDiego Astiazaran //    the AS of the attribute / method.
360ba3d595fSDiego Astiazaran static AccessSpecifier getFinalAccessSpecifier(AccessSpecifier FirstAS,
361ba3d595fSDiego Astiazaran                                                AccessSpecifier SecondAS) {
362ba3d595fSDiego Astiazaran   if (FirstAS == AccessSpecifier::AS_none ||
363ba3d595fSDiego Astiazaran       SecondAS == AccessSpecifier::AS_none)
364ba3d595fSDiego Astiazaran     return AccessSpecifier::AS_none;
365ba3d595fSDiego Astiazaran   if (FirstAS == AccessSpecifier::AS_private ||
366ba3d595fSDiego Astiazaran       SecondAS == AccessSpecifier::AS_private)
367ba3d595fSDiego Astiazaran     return AccessSpecifier::AS_private;
368ba3d595fSDiego Astiazaran   if (FirstAS == AccessSpecifier::AS_protected ||
369ba3d595fSDiego Astiazaran       SecondAS == AccessSpecifier::AS_protected)
370ba3d595fSDiego Astiazaran     return AccessSpecifier::AS_protected;
371ba3d595fSDiego Astiazaran   return AccessSpecifier::AS_public;
372ba3d595fSDiego Astiazaran }
373ba3d595fSDiego Astiazaran 
374ba3d595fSDiego Astiazaran // The Access parameter is only provided when parsing the field of an inherited
375ba3d595fSDiego Astiazaran // record, the access specification of the field depends on the inheritance mode
376ba3d595fSDiego Astiazaran static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly,
377ba3d595fSDiego Astiazaran                         AccessSpecifier Access = AccessSpecifier::AS_public) {
378e975a473SJulie Hockett   for (const FieldDecl *F : D->fields()) {
379ba3d595fSDiego Astiazaran     if (!shouldSerializeInfo(PublicOnly, /*IsInAnonymousNamespace=*/false, F))
380eb50a2e8SJulie Hockett       continue;
3814df84ac3SBrett Wilson 
3822b932bc1SPaul Kirth     auto &LO = F->getLangOpts();
383b59cd77cSJulie Hockett     // Use getAccessUnsafe so that we just get the default AS_none if it's not
384b59cd77cSJulie Hockett     // valid, as opposed to an assert.
3854df84ac3SBrett Wilson     MemberTypeInfo &NewMember = I.Members.emplace_back(
3862b932bc1SPaul Kirth         getTypeInfoForType(F->getTypeSourceInfo()->getType(), LO),
3874df84ac3SBrett Wilson         F->getNameAsString(),
388ba3d595fSDiego Astiazaran         getFinalAccessSpecifier(Access, F->getAccessUnsafe()));
3894df84ac3SBrett Wilson     populateMemberTypeInfo(NewMember, F);
390b59cd77cSJulie Hockett   }
391e975a473SJulie Hockett }
392e975a473SJulie Hockett 
393e975a473SJulie Hockett static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
394eaa7b324SBrett Wilson   for (const EnumConstantDecl *E : D->enumerators()) {
395eaa7b324SBrett Wilson     std::string ValueExpr;
396eaa7b324SBrett Wilson     if (const Expr *InitExpr = E->getInitExpr())
397eaa7b324SBrett Wilson       ValueExpr = getSourceCode(D, InitExpr->getSourceRange());
398eaa7b324SBrett Wilson     SmallString<16> ValueStr;
399eaa7b324SBrett Wilson     E->getInitVal().toString(ValueStr);
4005ef2456aSPeterChou1     I.Members.emplace_back(E->getNameAsString(), ValueStr.str(), ValueExpr);
4015ef2456aSPeterChou1     ASTContext &Context = E->getASTContext();
4025ef2456aSPeterChou1     if (RawComment *Comment =
4035ef2456aSPeterChou1             E->getASTContext().getRawCommentForDeclNoCache(E)) {
4045ef2456aSPeterChou1       CommentInfo CInfo;
4055ef2456aSPeterChou1       Comment->setAttached();
4065ef2456aSPeterChou1       if (comments::FullComment *Fc = Comment->parse(Context, nullptr, E)) {
4075ef2456aSPeterChou1         EnumValueInfo &Member = I.Members.back();
4085ef2456aSPeterChou1         Member.Description.emplace_back();
4095ef2456aSPeterChou1         parseFullComment(Fc, Member.Description.back());
4105ef2456aSPeterChou1       }
4115ef2456aSPeterChou1     }
412eaa7b324SBrett Wilson   }
413e975a473SJulie Hockett }
414e975a473SJulie Hockett 
415e975a473SJulie Hockett static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
4162b932bc1SPaul Kirth   auto &LO = D->getLangOpts();
417e975a473SJulie Hockett   for (const ParmVarDecl *P : D->parameters()) {
4184df84ac3SBrett Wilson     FieldTypeInfo &FieldInfo = I.Params.emplace_back(
4192b932bc1SPaul Kirth         getTypeInfoForType(P->getOriginalType(), LO), P->getNameAsString());
4204a68babdSBrett Wilson     FieldInfo.DefaultValue = getSourceCode(D, P->getDefaultArgRange());
421e191086bSBrett Wilson   }
422e975a473SJulie Hockett }
423e975a473SJulie Hockett 
424ba3d595fSDiego Astiazaran // TODO: Remove the serialization of Parents and VirtualParents, this
425ba3d595fSDiego Astiazaran // information is also extracted in the other definition of parseBases.
426e975a473SJulie Hockett static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
42773a4d54fSJulie Hockett   // Don't parse bases if this isn't a definition.
42873a4d54fSJulie Hockett   if (!D->isThisDeclarationADefinition())
42973a4d54fSJulie Hockett     return;
430e975a473SJulie Hockett   for (const CXXBaseSpecifier &B : D->bases()) {
431e975a473SJulie Hockett     if (B.isVirtual())
432e975a473SJulie Hockett       continue;
433b1f01e27SJulie Hockett     if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
434b1f01e27SJulie Hockett       const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
435b1f01e27SJulie Hockett       I.Parents.emplace_back(getUSRForDecl(D), B.getType().getAsString(),
4364a68babdSBrett Wilson                              InfoType::IT_record, B.getType().getAsString());
4374df84ac3SBrett Wilson     } else if (const RecordDecl *P = getRecordDeclForType(B.getType()))
438b59cd77cSJulie Hockett       I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
4394a68babdSBrett Wilson                              InfoType::IT_record, P->getQualifiedNameAsString(),
4404a68babdSBrett Wilson                              getInfoRelativePath(P));
441e975a473SJulie Hockett     else
4420afc6085SBrett Wilson       I.Parents.emplace_back(SymbolID(), B.getType().getAsString());
443e975a473SJulie Hockett   }
444e975a473SJulie Hockett   for (const CXXBaseSpecifier &B : D->vbases()) {
4454df84ac3SBrett Wilson     if (const RecordDecl *P = getRecordDeclForType(B.getType()))
4464a68babdSBrett Wilson       I.VirtualParents.emplace_back(
4474a68babdSBrett Wilson           getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record,
4484a68babdSBrett Wilson           P->getQualifiedNameAsString(), getInfoRelativePath(P));
449e975a473SJulie Hockett     else
4500afc6085SBrett Wilson       I.VirtualParents.emplace_back(SymbolID(), B.getType().getAsString());
451e975a473SJulie Hockett   }
452e975a473SJulie Hockett }
453e975a473SJulie Hockett 
454e975a473SJulie Hockett template <typename T>
455e975a473SJulie Hockett static void
456e975a473SJulie Hockett populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
4572c1c9a24SJulie Hockett                          const T *D, bool &IsInAnonymousNamespace) {
45821fb70c6SBrett Wilson   const DeclContext *DC = D->getDeclContext();
45921fb70c6SBrett Wilson   do {
460d900ef0aSJulie Hockett     if (const auto *N = dyn_cast<NamespaceDecl>(DC)) {
461d900ef0aSJulie Hockett       std::string Namespace;
462d900ef0aSJulie Hockett       if (N->isAnonymousNamespace()) {
463d900ef0aSJulie Hockett         Namespace = "@nonymous_namespace";
4642c1c9a24SJulie Hockett         IsInAnonymousNamespace = true;
465d900ef0aSJulie Hockett       } else
466d900ef0aSJulie Hockett         Namespace = N->getNameAsString();
467d900ef0aSJulie Hockett       Namespaces.emplace_back(getUSRForDecl(N), Namespace,
4684a68babdSBrett Wilson                               InfoType::IT_namespace,
4694a68babdSBrett Wilson                               N->getQualifiedNameAsString());
470d900ef0aSJulie Hockett     } else if (const auto *N = dyn_cast<RecordDecl>(DC))
471b59cd77cSJulie Hockett       Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
4724a68babdSBrett Wilson                               InfoType::IT_record,
4734a68babdSBrett Wilson                               N->getQualifiedNameAsString());
474e975a473SJulie Hockett     else if (const auto *N = dyn_cast<FunctionDecl>(DC))
475b59cd77cSJulie Hockett       Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
4764a68babdSBrett Wilson                               InfoType::IT_function,
4774a68babdSBrett Wilson                               N->getQualifiedNameAsString());
478e975a473SJulie Hockett     else if (const auto *N = dyn_cast<EnumDecl>(DC))
479b59cd77cSJulie Hockett       Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
4804a68babdSBrett Wilson                               InfoType::IT_enum, N->getQualifiedNameAsString());
48121fb70c6SBrett Wilson   } while ((DC = DC->getParent()));
482b46131e5SDiego Astiazaran   // The global namespace should be added to the list of namespaces if the decl
483b46131e5SDiego Astiazaran   // corresponds to a Record and if it doesn't have any namespace (because this
484b46131e5SDiego Astiazaran   // means it's in the global namespace). Also if its outermost namespace is a
485b46131e5SDiego Astiazaran   // record because that record matches the previous condition mentioned.
48662e48ed1SKazu Hirata   if ((Namespaces.empty() && isa<RecordDecl>(D)) ||
487b46131e5SDiego Astiazaran       (!Namespaces.empty() && Namespaces.back().RefType == InfoType::IT_record))
488b46131e5SDiego Astiazaran     Namespaces.emplace_back(SymbolID(), "GlobalNamespace",
489b46131e5SDiego Astiazaran                             InfoType::IT_namespace);
490e975a473SJulie Hockett }
491e975a473SJulie Hockett 
4924a68babdSBrett Wilson void PopulateTemplateParameters(std::optional<TemplateInfo> &TemplateInfo,
4934a68babdSBrett Wilson                                 const clang::Decl *D) {
4944a68babdSBrett Wilson   if (const TemplateParameterList *ParamList =
4954a68babdSBrett Wilson           D->getDescribedTemplateParams()) {
4964a68babdSBrett Wilson     if (!TemplateInfo) {
4974a68babdSBrett Wilson       TemplateInfo.emplace();
4984a68babdSBrett Wilson     }
4994a68babdSBrett Wilson     for (const NamedDecl *ND : *ParamList) {
5004a68babdSBrett Wilson       TemplateInfo->Params.emplace_back(
5014a68babdSBrett Wilson           getSourceCode(ND, ND->getSourceRange()));
5024a68babdSBrett Wilson     }
5034a68babdSBrett Wilson   }
5044a68babdSBrett Wilson }
5054a68babdSBrett Wilson 
5064a68babdSBrett Wilson TemplateParamInfo TemplateArgumentToInfo(const clang::Decl *D,
5074a68babdSBrett Wilson                                          const TemplateArgument &Arg) {
5084a68babdSBrett Wilson   // The TemplateArgument's pretty printing handles all the normal cases
5094a68babdSBrett Wilson   // well enough for our requirements.
5104a68babdSBrett Wilson   std::string Str;
5114a68babdSBrett Wilson   llvm::raw_string_ostream Stream(Str);
5124a68babdSBrett Wilson   Arg.print(PrintingPolicy(D->getLangOpts()), Stream, false);
5134a68babdSBrett Wilson   return TemplateParamInfo(Str);
5144a68babdSBrett Wilson }
5154a68babdSBrett Wilson 
516e975a473SJulie Hockett template <typename T>
517d900ef0aSJulie Hockett static void populateInfo(Info &I, const T *D, const FullComment *C,
518d900ef0aSJulie Hockett                          bool &IsInAnonymousNamespace) {
519e975a473SJulie Hockett   I.USR = getUSRForDecl(D);
520e975a473SJulie Hockett   I.Name = D->getNameAsString();
521d900ef0aSJulie Hockett   populateParentNamespaces(I.Namespace, D, IsInAnonymousNamespace);
522e975a473SJulie Hockett   if (C) {
523e975a473SJulie Hockett     I.Description.emplace_back();
524e975a473SJulie Hockett     parseFullComment(C, I.Description.back());
525e975a473SJulie Hockett   }
526e975a473SJulie Hockett }
527e975a473SJulie Hockett 
528e975a473SJulie Hockett template <typename T>
529e975a473SJulie Hockett static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
530d900ef0aSJulie Hockett                                int LineNumber, StringRef Filename,
531665e9676SDiego Astiazaran                                bool IsFileInRootDir,
532d900ef0aSJulie Hockett                                bool &IsInAnonymousNamespace) {
533d900ef0aSJulie Hockett   populateInfo(I, D, C, IsInAnonymousNamespace);
534e975a473SJulie Hockett   if (D->isThisDeclarationADefinition())
535665e9676SDiego Astiazaran     I.DefLoc.emplace(LineNumber, Filename, IsFileInRootDir);
536e975a473SJulie Hockett   else
537665e9676SDiego Astiazaran     I.Loc.emplace_back(LineNumber, Filename, IsFileInRootDir);
538e975a473SJulie Hockett }
539e975a473SJulie Hockett 
540e975a473SJulie Hockett static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
541e975a473SJulie Hockett                                  const FullComment *FC, int LineNumber,
542665e9676SDiego Astiazaran                                  StringRef Filename, bool IsFileInRootDir,
543d900ef0aSJulie Hockett                                  bool &IsInAnonymousNamespace) {
544665e9676SDiego Astiazaran   populateSymbolInfo(I, D, FC, LineNumber, Filename, IsFileInRootDir,
545665e9676SDiego Astiazaran                      IsInAnonymousNamespace);
5462b932bc1SPaul Kirth   auto &LO = D->getLangOpts();
5472b932bc1SPaul Kirth   I.ReturnType = getTypeInfoForType(D->getReturnType(), LO);
548e975a473SJulie Hockett   parseParameters(I, D);
5494a68babdSBrett Wilson 
5504a68babdSBrett Wilson   PopulateTemplateParameters(I.Template, D);
5514a68babdSBrett Wilson 
5524a68babdSBrett Wilson   // Handle function template specializations.
5534a68babdSBrett Wilson   if (const FunctionTemplateSpecializationInfo *FTSI =
5544a68babdSBrett Wilson           D->getTemplateSpecializationInfo()) {
5554a68babdSBrett Wilson     if (!I.Template)
5564a68babdSBrett Wilson       I.Template.emplace();
5574a68babdSBrett Wilson     I.Template->Specialization.emplace();
5584a68babdSBrett Wilson     auto &Specialization = *I.Template->Specialization;
5594a68babdSBrett Wilson 
5604a68babdSBrett Wilson     Specialization.SpecializationOf = getUSRForDecl(FTSI->getTemplate());
5614a68babdSBrett Wilson 
5624a68babdSBrett Wilson     // Template parameters to the specialization.
5634a68babdSBrett Wilson     if (FTSI->TemplateArguments) {
5644a68babdSBrett Wilson       for (const TemplateArgument &Arg : FTSI->TemplateArguments->asArray()) {
5654a68babdSBrett Wilson         Specialization.Params.push_back(TemplateArgumentToInfo(D, Arg));
5664a68babdSBrett Wilson       }
5674a68babdSBrett Wilson     }
5684a68babdSBrett Wilson   }
569e975a473SJulie Hockett }
570e975a473SJulie Hockett 
57199baa10fSBrett Wilson static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) {
57299baa10fSBrett Wilson   assert(D && "Expect non-null FieldDecl in populateMemberTypeInfo");
57399baa10fSBrett Wilson 
57499baa10fSBrett Wilson   ASTContext& Context = D->getASTContext();
57599baa10fSBrett Wilson   // TODO investigate whether we can use ASTContext::getCommentForDecl instead
57699baa10fSBrett Wilson   // of this logic. See also similar code in Mapper.cpp.
57799baa10fSBrett Wilson   RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
57899baa10fSBrett Wilson   if (!Comment)
57999baa10fSBrett Wilson     return;
58099baa10fSBrett Wilson 
58199baa10fSBrett Wilson   Comment->setAttached();
58299baa10fSBrett Wilson   if (comments::FullComment *fc = Comment->parse(Context, nullptr, D)) {
58399baa10fSBrett Wilson     I.Description.emplace_back();
58499baa10fSBrett Wilson     parseFullComment(fc, I.Description.back());
58599baa10fSBrett Wilson   }
58699baa10fSBrett Wilson }
58799baa10fSBrett Wilson 
588ba3d595fSDiego Astiazaran static void
589ba3d595fSDiego Astiazaran parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
590ba3d595fSDiego Astiazaran            bool PublicOnly, bool IsParent,
591ba3d595fSDiego Astiazaran            AccessSpecifier ParentAccess = AccessSpecifier::AS_public) {
592ba3d595fSDiego Astiazaran   // Don't parse bases if this isn't a definition.
593ba3d595fSDiego Astiazaran   if (!D->isThisDeclarationADefinition())
594ba3d595fSDiego Astiazaran     return;
595ba3d595fSDiego Astiazaran   for (const CXXBaseSpecifier &B : D->bases()) {
596ba3d595fSDiego Astiazaran     if (const RecordType *Ty = B.getType()->getAs<RecordType>()) {
597ba3d595fSDiego Astiazaran       if (const CXXRecordDecl *Base =
598ba3d595fSDiego Astiazaran               cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition())) {
599ba3d595fSDiego Astiazaran         // Initialized without USR and name, this will be set in the following
600ba3d595fSDiego Astiazaran         // if-else stmt.
601ba3d595fSDiego Astiazaran         BaseRecordInfo BI(
602ba3d595fSDiego Astiazaran             {}, "", getInfoRelativePath(Base), B.isVirtual(),
603ba3d595fSDiego Astiazaran             getFinalAccessSpecifier(ParentAccess, B.getAccessSpecifier()),
604ba3d595fSDiego Astiazaran             IsParent);
605ba3d595fSDiego Astiazaran         if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
606ba3d595fSDiego Astiazaran           const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
607ba3d595fSDiego Astiazaran           BI.USR = getUSRForDecl(D);
608ba3d595fSDiego Astiazaran           BI.Name = B.getType().getAsString();
609ba3d595fSDiego Astiazaran         } else {
610ba3d595fSDiego Astiazaran           BI.USR = getUSRForDecl(Base);
611ba3d595fSDiego Astiazaran           BI.Name = Base->getNameAsString();
612ba3d595fSDiego Astiazaran         }
613ba3d595fSDiego Astiazaran         parseFields(BI, Base, PublicOnly, BI.Access);
614ba3d595fSDiego Astiazaran         for (const auto &Decl : Base->decls())
615ba3d595fSDiego Astiazaran           if (const auto *MD = dyn_cast<CXXMethodDecl>(Decl)) {
616ba3d595fSDiego Astiazaran             // Don't serialize private methods
617ba3d595fSDiego Astiazaran             if (MD->getAccessUnsafe() == AccessSpecifier::AS_private ||
618ba3d595fSDiego Astiazaran                 !MD->isUserProvided())
619ba3d595fSDiego Astiazaran               continue;
620ba3d595fSDiego Astiazaran             FunctionInfo FI;
621ba3d595fSDiego Astiazaran             FI.IsMethod = true;
622ba3d595fSDiego Astiazaran             // The seventh arg in populateFunctionInfo is a boolean passed by
623ba3d595fSDiego Astiazaran             // reference, its value is not relevant in here so it's not used
624ba3d595fSDiego Astiazaran             // anywhere besides the function call.
625ba3d595fSDiego Astiazaran             bool IsInAnonymousNamespace;
626ba3d595fSDiego Astiazaran             populateFunctionInfo(FI, MD, /*FullComment=*/{}, /*LineNumber=*/{},
627ba3d595fSDiego Astiazaran                                  /*FileName=*/{}, IsFileInRootDir,
628ba3d595fSDiego Astiazaran                                  IsInAnonymousNamespace);
629ba3d595fSDiego Astiazaran             FI.Access =
630ba3d595fSDiego Astiazaran                 getFinalAccessSpecifier(BI.Access, MD->getAccessUnsafe());
63121fb70c6SBrett Wilson             BI.Children.Functions.emplace_back(std::move(FI));
632ba3d595fSDiego Astiazaran           }
633ba3d595fSDiego Astiazaran         I.Bases.emplace_back(std::move(BI));
634ba3d595fSDiego Astiazaran         // Call this function recursively to get the inherited classes of
635ba3d595fSDiego Astiazaran         // this base; these new bases will also get stored in the original
636ba3d595fSDiego Astiazaran         // RecordInfo: I.
637ba3d595fSDiego Astiazaran         parseBases(I, Base, IsFileInRootDir, PublicOnly, false,
638ba3d595fSDiego Astiazaran                    I.Bases.back().Access);
639ba3d595fSDiego Astiazaran       }
640ba3d595fSDiego Astiazaran     }
641ba3d595fSDiego Astiazaran   }
642ba3d595fSDiego Astiazaran }
643ba3d595fSDiego Astiazaran 
644097aedc9SJulie Hockett std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
645097aedc9SJulie Hockett emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
646665e9676SDiego Astiazaran          llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
6471c705d9cSJonas Devlieghere   auto I = std::make_unique<NamespaceInfo>();
648d900ef0aSJulie Hockett   bool IsInAnonymousNamespace = false;
649d900ef0aSJulie Hockett   populateInfo(*I, D, FC, IsInAnonymousNamespace);
650ba3d595fSDiego Astiazaran   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
651097aedc9SJulie Hockett     return {};
652ba3d595fSDiego Astiazaran 
653d900ef0aSJulie Hockett   I->Name = D->isAnonymousNamespace()
654d900ef0aSJulie Hockett                 ? llvm::SmallString<16>("@nonymous_namespace")
655d900ef0aSJulie Hockett                 : I->Name;
6562c1c9a24SJulie Hockett   I->Path = getInfoRelativePath(I->Namespace);
657097aedc9SJulie Hockett   if (I->Namespace.empty() && I->USR == SymbolID())
658097aedc9SJulie Hockett     return {std::unique_ptr<Info>{std::move(I)}, nullptr};
659097aedc9SJulie Hockett 
66021fb70c6SBrett Wilson   // Namespaces are inserted into the parent by reference, so we need to return
66121fb70c6SBrett Wilson   // both the parent and the record itself.
66221fb70c6SBrett Wilson   return {std::move(I), MakeAndInsertIntoParent<const NamespaceInfo &>(*I)};
663e975a473SJulie Hockett }
664e975a473SJulie Hockett 
665097aedc9SJulie Hockett std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
666097aedc9SJulie Hockett emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
667665e9676SDiego Astiazaran          llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
6681c705d9cSJonas Devlieghere   auto I = std::make_unique<RecordInfo>();
669d900ef0aSJulie Hockett   bool IsInAnonymousNamespace = false;
670665e9676SDiego Astiazaran   populateSymbolInfo(*I, D, FC, LineNumber, File, IsFileInRootDir,
671665e9676SDiego Astiazaran                      IsInAnonymousNamespace);
672ba3d595fSDiego Astiazaran   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
673097aedc9SJulie Hockett     return {};
674d900ef0aSJulie Hockett 
6758899c29bSJulie Hockett   I->TagType = D->getTagKind();
6768899c29bSJulie Hockett   parseFields(*I, D, PublicOnly);
677b1f01e27SJulie Hockett   if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
678b1f01e27SJulie Hockett     if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl()) {
679b1f01e27SJulie Hockett       I->Name = TD->getNameAsString();
680b1f01e27SJulie Hockett       I->IsTypeDef = true;
681b1f01e27SJulie Hockett     }
682ba3d595fSDiego Astiazaran     // TODO: remove first call to parseBases, that function should be deleted
6838899c29bSJulie Hockett     parseBases(*I, C);
684ba3d595fSDiego Astiazaran     parseBases(*I, C, IsFileInRootDir, PublicOnly, true);
685b1f01e27SJulie Hockett   }
6862c1c9a24SJulie Hockett   I->Path = getInfoRelativePath(I->Namespace);
687097aedc9SJulie Hockett 
6884a68babdSBrett Wilson   PopulateTemplateParameters(I->Template, D);
6894a68babdSBrett Wilson 
6904a68babdSBrett Wilson   // Full and partial specializations.
6914a68babdSBrett Wilson   if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
6924a68babdSBrett Wilson     if (!I->Template)
6934a68babdSBrett Wilson       I->Template.emplace();
6944a68babdSBrett Wilson     I->Template->Specialization.emplace();
6954a68babdSBrett Wilson     auto &Specialization = *I->Template->Specialization;
6964a68babdSBrett Wilson 
6974a68babdSBrett Wilson     // What this is a specialization of.
6984a68babdSBrett Wilson     auto SpecOf = CTSD->getSpecializedTemplateOrPartial();
699*b68a952aSKazu Hirata     if (auto *CTD = dyn_cast<ClassTemplateDecl *>(SpecOf))
700*b68a952aSKazu Hirata       Specialization.SpecializationOf = getUSRForDecl(CTD);
701*b68a952aSKazu Hirata     else if (auto *CTPSD =
702*b68a952aSKazu Hirata                  dyn_cast<ClassTemplatePartialSpecializationDecl *>(SpecOf))
703*b68a952aSKazu Hirata       Specialization.SpecializationOf = getUSRForDecl(CTPSD);
7044a68babdSBrett Wilson 
7054a68babdSBrett Wilson     // Parameters to the specilization. For partial specializations, get the
7064a68babdSBrett Wilson     // parameters "as written" from the ClassTemplatePartialSpecializationDecl
7074a68babdSBrett Wilson     // because the non-explicit template parameters will have generated internal
7084a68babdSBrett Wilson     // placeholder names rather than the names the user typed that match the
7094a68babdSBrett Wilson     // template parameters.
7104a68babdSBrett Wilson     if (const ClassTemplatePartialSpecializationDecl *CTPSD =
7114a68babdSBrett Wilson             dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
7124a68babdSBrett Wilson       if (const ASTTemplateArgumentListInfo *AsWritten =
7134a68babdSBrett Wilson               CTPSD->getTemplateArgsAsWritten()) {
7144a68babdSBrett Wilson         for (unsigned i = 0; i < AsWritten->getNumTemplateArgs(); i++) {
7154a68babdSBrett Wilson           Specialization.Params.emplace_back(
7164a68babdSBrett Wilson               getSourceCode(D, (*AsWritten)[i].getSourceRange()));
7174a68babdSBrett Wilson         }
7184a68babdSBrett Wilson       }
7194a68babdSBrett Wilson     } else {
7204a68babdSBrett Wilson       for (const TemplateArgument &Arg : CTSD->getTemplateArgs().asArray()) {
7214a68babdSBrett Wilson         Specialization.Params.push_back(TemplateArgumentToInfo(D, Arg));
7224a68babdSBrett Wilson       }
7234a68babdSBrett Wilson     }
7244a68babdSBrett Wilson   }
7254a68babdSBrett Wilson 
72621fb70c6SBrett Wilson   // Records are inserted into the parent by reference, so we need to return
72721fb70c6SBrett Wilson   // both the parent and the record itself.
72821fb70c6SBrett Wilson   auto Parent = MakeAndInsertIntoParent<const RecordInfo &>(*I);
72921fb70c6SBrett Wilson   return {std::move(I), std::move(Parent)};
730097aedc9SJulie Hockett }
731097aedc9SJulie Hockett 
732097aedc9SJulie Hockett std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
733097aedc9SJulie Hockett emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
734665e9676SDiego Astiazaran          llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
7358899c29bSJulie Hockett   FunctionInfo Func;
736d900ef0aSJulie Hockett   bool IsInAnonymousNamespace = false;
737665e9676SDiego Astiazaran   populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir,
738665e9676SDiego Astiazaran                        IsInAnonymousNamespace);
7396a29ae4bSDiego Astiazaran   Func.Access = clang::AccessSpecifier::AS_none;
740ba3d595fSDiego Astiazaran   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
741097aedc9SJulie Hockett     return {};
742d900ef0aSJulie Hockett 
74321fb70c6SBrett Wilson   // Info is wrapped in its parent scope so is returned in the second position.
74421fb70c6SBrett Wilson   return {nullptr, MakeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
745e975a473SJulie Hockett }
746e975a473SJulie Hockett 
747097aedc9SJulie Hockett std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
748097aedc9SJulie Hockett emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
749665e9676SDiego Astiazaran          llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
7508899c29bSJulie Hockett   FunctionInfo Func;
751d900ef0aSJulie Hockett   bool IsInAnonymousNamespace = false;
752665e9676SDiego Astiazaran   populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir,
753665e9676SDiego Astiazaran                        IsInAnonymousNamespace);
754ba3d595fSDiego Astiazaran   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
755097aedc9SJulie Hockett     return {};
756d900ef0aSJulie Hockett 
7578899c29bSJulie Hockett   Func.IsMethod = true;
7588899c29bSJulie Hockett 
759b1f01e27SJulie Hockett   const NamedDecl *Parent = nullptr;
760b1f01e27SJulie Hockett   if (const auto *SD =
761b1f01e27SJulie Hockett           dyn_cast<ClassTemplateSpecializationDecl>(D->getParent()))
762b1f01e27SJulie Hockett     Parent = SD->getSpecializedTemplate();
763b1f01e27SJulie Hockett   else
764b1f01e27SJulie Hockett     Parent = D->getParent();
765b1f01e27SJulie Hockett 
766b1f01e27SJulie Hockett   SymbolID ParentUSR = getUSRForDecl(Parent);
767b1f01e27SJulie Hockett   Func.Parent =
7684a68babdSBrett Wilson       Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record,
7694a68babdSBrett Wilson                 Parent->getQualifiedNameAsString()};
7708899c29bSJulie Hockett   Func.Access = D->getAccess();
7718899c29bSJulie Hockett 
77221fb70c6SBrett Wilson   // Info is wrapped in its parent scope so is returned in the second position.
77321fb70c6SBrett Wilson   return {nullptr, MakeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
77421fb70c6SBrett Wilson }
77521fb70c6SBrett Wilson 
77621fb70c6SBrett Wilson std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
77721fb70c6SBrett Wilson emitInfo(const TypedefDecl *D, const FullComment *FC, int LineNumber,
77821fb70c6SBrett Wilson          StringRef File, bool IsFileInRootDir, bool PublicOnly) {
77921fb70c6SBrett Wilson   TypedefInfo Info;
78021fb70c6SBrett Wilson 
78121fb70c6SBrett Wilson   bool IsInAnonymousNamespace = false;
78221fb70c6SBrett Wilson   populateInfo(Info, D, FC, IsInAnonymousNamespace);
78321fb70c6SBrett Wilson   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
78421fb70c6SBrett Wilson     return {};
78521fb70c6SBrett Wilson 
78621fb70c6SBrett Wilson   Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir);
7872b932bc1SPaul Kirth   auto &LO = D->getLangOpts();
7882b932bc1SPaul Kirth   Info.Underlying = getTypeInfoForType(D->getUnderlyingType(), LO);
78921fb70c6SBrett Wilson   if (Info.Underlying.Type.Name.empty()) {
79021fb70c6SBrett Wilson     // Typedef for an unnamed type. This is like "typedef struct { } Foo;"
79121fb70c6SBrett Wilson     // The record serializer explicitly checks for this syntax and constructs
79221fb70c6SBrett Wilson     // a record with that name, so we don't want to emit a duplicate here.
79321fb70c6SBrett Wilson     return {};
79421fb70c6SBrett Wilson   }
79521fb70c6SBrett Wilson   Info.IsUsing = false;
79621fb70c6SBrett Wilson 
79721fb70c6SBrett Wilson   // Info is wrapped in its parent scope so is returned in the second position.
79821fb70c6SBrett Wilson   return {nullptr, MakeAndInsertIntoParent<TypedefInfo &&>(std::move(Info))};
79921fb70c6SBrett Wilson }
80021fb70c6SBrett Wilson 
80121fb70c6SBrett Wilson // A type alias is a C++ "using" declaration for a type. It gets mapped to a
80221fb70c6SBrett Wilson // TypedefInfo with the IsUsing flag set.
80321fb70c6SBrett Wilson std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
80421fb70c6SBrett Wilson emitInfo(const TypeAliasDecl *D, const FullComment *FC, int LineNumber,
80521fb70c6SBrett Wilson          StringRef File, bool IsFileInRootDir, bool PublicOnly) {
80621fb70c6SBrett Wilson   TypedefInfo Info;
80721fb70c6SBrett Wilson 
80821fb70c6SBrett Wilson   bool IsInAnonymousNamespace = false;
80921fb70c6SBrett Wilson   populateInfo(Info, D, FC, IsInAnonymousNamespace);
81021fb70c6SBrett Wilson   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
81121fb70c6SBrett Wilson     return {};
81221fb70c6SBrett Wilson 
81321fb70c6SBrett Wilson   Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir);
8142b932bc1SPaul Kirth   auto &LO = D->getLangOpts();
8152b932bc1SPaul Kirth   Info.Underlying = getTypeInfoForType(D->getUnderlyingType(), LO);
81621fb70c6SBrett Wilson   Info.IsUsing = true;
81721fb70c6SBrett Wilson 
81821fb70c6SBrett Wilson   // Info is wrapped in its parent scope so is returned in the second position.
81921fb70c6SBrett Wilson   return {nullptr, MakeAndInsertIntoParent<TypedefInfo &&>(std::move(Info))};
820e975a473SJulie Hockett }
821e975a473SJulie Hockett 
822097aedc9SJulie Hockett std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
823097aedc9SJulie Hockett emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
824665e9676SDiego Astiazaran          llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
8258899c29bSJulie Hockett   EnumInfo Enum;
826d900ef0aSJulie Hockett   bool IsInAnonymousNamespace = false;
827665e9676SDiego Astiazaran   populateSymbolInfo(Enum, D, FC, LineNumber, File, IsFileInRootDir,
828665e9676SDiego Astiazaran                      IsInAnonymousNamespace);
829ba3d595fSDiego Astiazaran   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
830097aedc9SJulie Hockett     return {};
831d900ef0aSJulie Hockett 
8328899c29bSJulie Hockett   Enum.Scoped = D->isScoped();
8334a68babdSBrett Wilson   if (D->isFixed()) {
8344a68babdSBrett Wilson     auto Name = D->getIntegerType().getAsString();
8354a68babdSBrett Wilson     Enum.BaseType = TypeInfo(Name, Name);
8364a68babdSBrett Wilson   }
8378899c29bSJulie Hockett   parseEnumerators(Enum, D);
8388899c29bSJulie Hockett 
83921fb70c6SBrett Wilson   // Info is wrapped in its parent scope so is returned in the second position.
84021fb70c6SBrett Wilson   return {nullptr, MakeAndInsertIntoParent<EnumInfo &&>(std::move(Enum))};
841e975a473SJulie Hockett }
842e975a473SJulie Hockett 
843e975a473SJulie Hockett } // namespace serialize
844e975a473SJulie Hockett } // namespace doc
845e975a473SJulie Hockett } // namespace clang
846