blob: 26f22a9b8527a4025a7580113e14b0eb644ff947 [file] [log] [blame]
Fangrui Songffe9f002019-03-01 09:52:53 +00001//===-- Serialize.cpp - ClangDoc Serializer ---------------------*- C++ -*-===//
Julie Hockette975a472018-03-22 23:34:46 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Julie Hockette975a472018-03-22 23:34:46 +00006//
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
17using clang::comments::FullComment;
18
19namespace clang {
20namespace doc {
21namespace serialize {
22
23SymbolID hashUSR(llvm::StringRef USR) {
24 return llvm::SHA1::hash(arrayRefFromStringRef(USR));
25}
26
Julie Hockett2c1c9a22019-07-12 18:32:00 +000027template <typename T>
28static void
29populateParentNamespaces(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// }
45llvm::SmallString<128>
46getInfoRelativePath(const llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
Julie Hockett2c1c9a22019-07-12 18:32:00 +000047 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
53llvm::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
Julie Hockette975a472018-03-22 23:34:46 +000063class ClangDocCommentVisitor
64 : public ConstCommentVisitor<ClangDocCommentVisitor> {
65public:
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
81private:
82 std::string getCommandName(unsigned CommandID) const;
83 bool isWhitespaceOnly(StringRef S) const;
84
85 CommentInfo &CurrentCI;
86};
87
88void ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
89 CurrentCI.Kind = C->getCommentKindName();
90 ConstCommentVisitor<ClangDocCommentVisitor>::visit(C);
91 for (comments::Comment *Child :
92 llvm::make_range(C->child_begin(), C->child_end())) {
93 CurrentCI.Children.emplace_back(llvm::make_unique<CommentInfo>());
94 ClangDocCommentVisitor Visitor(*CurrentCI.Children.back());
95 Visitor.parseComment(Child);
96 }
97}
98
99void ClangDocCommentVisitor::visitTextComment(const TextComment *C) {
100 if (!isWhitespaceOnly(C->getText()))
101 CurrentCI.Text = C->getText();
102}
103
104void ClangDocCommentVisitor::visitInlineCommandComment(
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
111void ClangDocCommentVisitor::visitHTMLStartTagComment(
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
122void ClangDocCommentVisitor::visitHTMLEndTagComment(
123 const HTMLEndTagComment *C) {
124 CurrentCI.Name = C->getTagName();
125 CurrentCI.SelfClosing = true;
126}
127
128void ClangDocCommentVisitor::visitBlockCommandComment(
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
135void ClangDocCommentVisitor::visitParamCommandComment(
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
144void ClangDocCommentVisitor::visitTParamCommandComment(
145 const TParamCommandComment *C) {
146 if (C->hasParamName())
147 CurrentCI.ParamName = C->getParamNameAsWritten();
148}
149
150void ClangDocCommentVisitor::visitVerbatimBlockComment(
151 const VerbatimBlockComment *C) {
152 CurrentCI.Name = getCommandName(C->getCommandID());
153 CurrentCI.CloseName = C->getCloseName();
154}
155
156void ClangDocCommentVisitor::visitVerbatimBlockLineComment(
157 const VerbatimBlockLineComment *C) {
158 if (!isWhitespaceOnly(C->getText()))
159 CurrentCI.Text = C->getText();
160}
161
162void ClangDocCommentVisitor::visitVerbatimLineComment(
163 const VerbatimLineComment *C) {
164 if (!isWhitespaceOnly(C->getText()))
165 CurrentCI.Text = C->getText();
166}
167
168bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const {
169 return std::all_of(S.begin(), S.end(), isspace);
170}
171
172std::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
182template <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
Julie Hockett8899c292018-08-02 20:10:17 +0000190std::string serialize(std::unique_ptr<Info> &I) {
191 switch (I->IT) {
192 case InfoType::IT_namespace:
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()));
198 case InfoType::IT_function:
199 return serialize(*static_cast<FunctionInfo *>(I.get()));
200 default:
201 return "";
202 }
203}
204
Julie Hockette975a472018-03-22 23:34:46 +0000205static void parseFullComment(const FullComment *C, CommentInfo &CI) {
206 ClangDocCommentVisitor Visitor(CI);
207 Visitor.parseComment(C);
208}
209
210static 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
217static RecordDecl *getDeclForType(const QualType &T) {
Julie Hockettb1f01e22019-06-24 19:31:02 +0000218 if (const RecordDecl *D = T->getAsRecordDecl())
219 return D->getDefinition();
220 return nullptr;
Julie Hockette975a472018-03-22 23:34:46 +0000221}
222
Julie Hocketteb50a2e2018-07-20 18:49:55 +0000223static 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
233static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly) {
Julie Hockette975a472018-03-22 23:34:46 +0000234 for (const FieldDecl *F : D->fields()) {
Julie Hocketteb50a2e2018-07-20 18:49:55 +0000235 if (PublicOnly && !isPublic(F->getAccessUnsafe(), F->getLinkageInternal()))
236 continue;
Julie Hockette975a472018-03-22 23:34:46 +0000237 if (const auto *T = getDeclForType(F->getTypeSourceInfo()->getType())) {
Julie Hockettb59cd772018-05-04 17:02:13 +0000238 // Use getAccessUnsafe so that we just get the default AS_none if it's not
239 // valid, as opposed to an assert.
240 if (const auto *N = dyn_cast<EnumDecl>(T)) {
241 I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000242 InfoType::IT_enum, getInfoRelativePath(N),
243 F->getNameAsString(), N->getAccessUnsafe());
Julie Hockettb59cd772018-05-04 17:02:13 +0000244 continue;
245 } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
246 I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000247 InfoType::IT_record, getInfoRelativePath(N),
248 F->getNameAsString(), N->getAccessUnsafe());
Julie Hockettb59cd772018-05-04 17:02:13 +0000249 continue;
250 }
Julie Hockette975a472018-03-22 23:34:46 +0000251 }
Julie Hockettb59cd772018-05-04 17:02:13 +0000252 I.Members.emplace_back(F->getTypeSourceInfo()->getType().getAsString(),
253 F->getNameAsString(), F->getAccessUnsafe());
Julie Hockette975a472018-03-22 23:34:46 +0000254 }
255}
256
257static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
258 for (const EnumConstantDecl *E : D->enumerators())
259 I.Members.emplace_back(E->getNameAsString());
260}
261
262static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
263 for (const ParmVarDecl *P : D->parameters()) {
Julie Hockette975a472018-03-22 23:34:46 +0000264 if (const auto *T = getDeclForType(P->getOriginalType())) {
Julie Hockettb59cd772018-05-04 17:02:13 +0000265 if (const auto *N = dyn_cast<EnumDecl>(T)) {
266 I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000267 InfoType::IT_enum, getInfoRelativePath(N),
268 P->getNameAsString());
Julie Hockettb59cd772018-05-04 17:02:13 +0000269 continue;
270 } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
271 I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000272 InfoType::IT_record, getInfoRelativePath(N),
273 P->getNameAsString());
Julie Hockettb59cd772018-05-04 17:02:13 +0000274 continue;
275 }
Julie Hockette975a472018-03-22 23:34:46 +0000276 }
Julie Hockettb59cd772018-05-04 17:02:13 +0000277 I.Params.emplace_back(P->getOriginalType().getAsString(),
278 P->getNameAsString());
Julie Hockette975a472018-03-22 23:34:46 +0000279 }
280}
281
282static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
Julie Hockett73a4d542018-10-03 18:25:27 +0000283 // Don't parse bases if this isn't a definition.
284 if (!D->isThisDeclarationADefinition())
285 return;
Julie Hockette975a472018-03-22 23:34:46 +0000286 for (const CXXBaseSpecifier &B : D->bases()) {
287 if (B.isVirtual())
288 continue;
Julie Hockettb1f01e22019-06-24 19:31:02 +0000289 if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
290 const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
291 I.Parents.emplace_back(getUSRForDecl(D), B.getType().getAsString(),
292 InfoType::IT_record);
293 } else if (const RecordDecl *P = getDeclForType(B.getType()))
Julie Hockettb59cd772018-05-04 17:02:13 +0000294 I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000295 InfoType::IT_record, getInfoRelativePath(P));
Julie Hockette975a472018-03-22 23:34:46 +0000296 else
297 I.Parents.emplace_back(B.getType().getAsString());
298 }
299 for (const CXXBaseSpecifier &B : D->vbases()) {
300 if (const auto *P = getDeclForType(B.getType()))
Julie Hockettb59cd772018-05-04 17:02:13 +0000301 I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000302 InfoType::IT_record,
303 getInfoRelativePath(P));
Julie Hockette975a472018-03-22 23:34:46 +0000304 else
305 I.VirtualParents.emplace_back(B.getType().getAsString());
306 }
307}
308
309template <typename T>
310static void
311populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000312 const T *D, bool &IsInAnonymousNamespace) {
Julie Hockette975a472018-03-22 23:34:46 +0000313 const auto *DC = dyn_cast<DeclContext>(D);
314 while ((DC = DC->getParent())) {
Julie Hockettd900ef02019-06-28 19:07:56 +0000315 if (const auto *N = dyn_cast<NamespaceDecl>(DC)) {
316 std::string Namespace;
317 if (N->isAnonymousNamespace()) {
318 Namespace = "@nonymous_namespace";
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000319 IsInAnonymousNamespace = true;
Julie Hockettd900ef02019-06-28 19:07:56 +0000320 } else
321 Namespace = N->getNameAsString();
322 Namespaces.emplace_back(getUSRForDecl(N), Namespace,
Julie Hockettb59cd772018-05-04 17:02:13 +0000323 InfoType::IT_namespace);
Julie Hockettd900ef02019-06-28 19:07:56 +0000324 } else if (const auto *N = dyn_cast<RecordDecl>(DC))
Julie Hockettb59cd772018-05-04 17:02:13 +0000325 Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
326 InfoType::IT_record);
Julie Hockette975a472018-03-22 23:34:46 +0000327 else if (const auto *N = dyn_cast<FunctionDecl>(DC))
Julie Hockettb59cd772018-05-04 17:02:13 +0000328 Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
329 InfoType::IT_function);
Julie Hockette975a472018-03-22 23:34:46 +0000330 else if (const auto *N = dyn_cast<EnumDecl>(DC))
Julie Hockettb59cd772018-05-04 17:02:13 +0000331 Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
332 InfoType::IT_enum);
Julie Hockette975a472018-03-22 23:34:46 +0000333 }
334}
335
336template <typename T>
Julie Hockettd900ef02019-06-28 19:07:56 +0000337static void populateInfo(Info &I, const T *D, const FullComment *C,
338 bool &IsInAnonymousNamespace) {
Julie Hockette975a472018-03-22 23:34:46 +0000339 I.USR = getUSRForDecl(D);
340 I.Name = D->getNameAsString();
Julie Hockettd900ef02019-06-28 19:07:56 +0000341 populateParentNamespaces(I.Namespace, D, IsInAnonymousNamespace);
Julie Hockette975a472018-03-22 23:34:46 +0000342 if (C) {
343 I.Description.emplace_back();
344 parseFullComment(C, I.Description.back());
345 }
346}
347
348template <typename T>
349static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
Julie Hockettd900ef02019-06-28 19:07:56 +0000350 int LineNumber, StringRef Filename,
Diego Astiazaran665e9672019-08-09 17:49:41 +0000351 bool IsFileInRootDir,
Julie Hockettd900ef02019-06-28 19:07:56 +0000352 bool &IsInAnonymousNamespace) {
353 populateInfo(I, D, C, IsInAnonymousNamespace);
Julie Hockette975a472018-03-22 23:34:46 +0000354 if (D->isThisDeclarationADefinition())
Diego Astiazaran665e9672019-08-09 17:49:41 +0000355 I.DefLoc.emplace(LineNumber, Filename, IsFileInRootDir);
Julie Hockette975a472018-03-22 23:34:46 +0000356 else
Diego Astiazaran665e9672019-08-09 17:49:41 +0000357 I.Loc.emplace_back(LineNumber, Filename, IsFileInRootDir);
Julie Hockette975a472018-03-22 23:34:46 +0000358}
359
360static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
361 const FullComment *FC, int LineNumber,
Diego Astiazaran665e9672019-08-09 17:49:41 +0000362 StringRef Filename, bool IsFileInRootDir,
Julie Hockettd900ef02019-06-28 19:07:56 +0000363 bool &IsInAnonymousNamespace) {
Diego Astiazaran665e9672019-08-09 17:49:41 +0000364 populateSymbolInfo(I, D, FC, LineNumber, Filename, IsFileInRootDir,
365 IsInAnonymousNamespace);
Julie Hockette975a472018-03-22 23:34:46 +0000366 if (const auto *T = getDeclForType(D->getReturnType())) {
Julie Hockette975a472018-03-22 23:34:46 +0000367 if (dyn_cast<EnumDecl>(T))
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000368 I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(),
369 InfoType::IT_enum, getInfoRelativePath(T));
Julie Hockette975a472018-03-22 23:34:46 +0000370 else if (dyn_cast<RecordDecl>(T))
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000371 I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(),
372 InfoType::IT_record, getInfoRelativePath(T));
Julie Hockette975a472018-03-22 23:34:46 +0000373 } else {
Julie Hockettb59cd772018-05-04 17:02:13 +0000374 I.ReturnType = TypeInfo(D->getReturnType().getAsString());
Julie Hockette975a472018-03-22 23:34:46 +0000375 }
376 parseParameters(I, D);
377}
378
Julie Hockett097aedc2019-07-02 19:59:56 +0000379std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
380emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
Diego Astiazaran665e9672019-08-09 17:49:41 +0000381 llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
Julie Hockettd900ef02019-06-28 19:07:56 +0000382 auto I = llvm::make_unique<NamespaceInfo>();
383 bool IsInAnonymousNamespace = false;
384 populateInfo(*I, D, FC, IsInAnonymousNamespace);
385 if (PublicOnly && ((IsInAnonymousNamespace || D->isAnonymousNamespace()) ||
Julie Hocketteb50a2e2018-07-20 18:49:55 +0000386 !isPublic(D->getAccess(), D->getLinkageInternal())))
Julie Hockett097aedc2019-07-02 19:59:56 +0000387 return {};
Julie Hockettd900ef02019-06-28 19:07:56 +0000388 I->Name = D->isAnonymousNamespace()
389 ? llvm::SmallString<16>("@nonymous_namespace")
390 : I->Name;
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000391 I->Path = getInfoRelativePath(I->Namespace);
Julie Hockett097aedc2019-07-02 19:59:56 +0000392 if (I->Namespace.empty() && I->USR == SymbolID())
393 return {std::unique_ptr<Info>{std::move(I)}, nullptr};
394
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000395 auto ParentI = llvm::make_unique<NamespaceInfo>();
396 ParentI->USR = I->Namespace.empty() ? SymbolID() : I->Namespace[0].USR;
397 ParentI->ChildNamespaces.emplace_back(I->USR, I->Name,
398 InfoType::IT_namespace);
399 if (I->Namespace.empty())
400 ParentI->Path = getInfoRelativePath(ParentI->Namespace);
Julie Hockett097aedc2019-07-02 19:59:56 +0000401 return {std::unique_ptr<Info>{std::move(I)},
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000402 std::unique_ptr<Info>{std::move(ParentI)}};
Julie Hockette975a472018-03-22 23:34:46 +0000403}
404
Julie Hockett097aedc2019-07-02 19:59:56 +0000405std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
406emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
Diego Astiazaran665e9672019-08-09 17:49:41 +0000407 llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
Julie Hockett8899c292018-08-02 20:10:17 +0000408 auto I = llvm::make_unique<RecordInfo>();
Julie Hockettd900ef02019-06-28 19:07:56 +0000409 bool IsInAnonymousNamespace = false;
Diego Astiazaran665e9672019-08-09 17:49:41 +0000410 populateSymbolInfo(*I, D, FC, LineNumber, File, IsFileInRootDir,
411 IsInAnonymousNamespace);
Julie Hockettd900ef02019-06-28 19:07:56 +0000412 if (PublicOnly && ((IsInAnonymousNamespace ||
413 !isPublic(D->getAccess(), D->getLinkageInternal()))))
Julie Hockett097aedc2019-07-02 19:59:56 +0000414 return {};
Julie Hockettd900ef02019-06-28 19:07:56 +0000415
Julie Hockett8899c292018-08-02 20:10:17 +0000416 I->TagType = D->getTagKind();
417 parseFields(*I, D, PublicOnly);
Julie Hockettb1f01e22019-06-24 19:31:02 +0000418 if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
419 if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl()) {
420 I->Name = TD->getNameAsString();
421 I->IsTypeDef = true;
422 }
Julie Hockett8899c292018-08-02 20:10:17 +0000423 parseBases(*I, C);
Julie Hockettb1f01e22019-06-24 19:31:02 +0000424 }
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000425 I->Path = getInfoRelativePath(I->Namespace);
Julie Hockett097aedc2019-07-02 19:59:56 +0000426
427 if (I->Namespace.empty()) {
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000428 auto ParentI = llvm::make_unique<NamespaceInfo>();
429 ParentI->USR = SymbolID();
430 ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
431 ParentI->Path = getInfoRelativePath(ParentI->Namespace);
Julie Hockett097aedc2019-07-02 19:59:56 +0000432 return {std::unique_ptr<Info>{std::move(I)},
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000433 std::unique_ptr<Info>{std::move(ParentI)}};
Julie Hockett097aedc2019-07-02 19:59:56 +0000434 }
435
436 switch (I->Namespace[0].RefType) {
437 case InfoType::IT_namespace: {
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000438 auto ParentI = llvm::make_unique<NamespaceInfo>();
439 ParentI->USR = I->Namespace[0].USR;
440 ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
Julie Hockett097aedc2019-07-02 19:59:56 +0000441 return {std::unique_ptr<Info>{std::move(I)},
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000442 std::unique_ptr<Info>{std::move(ParentI)}};
Julie Hockett097aedc2019-07-02 19:59:56 +0000443 }
444 case InfoType::IT_record: {
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000445 auto ParentI = llvm::make_unique<RecordInfo>();
446 ParentI->USR = I->Namespace[0].USR;
447 ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
Julie Hockett097aedc2019-07-02 19:59:56 +0000448 return {std::unique_ptr<Info>{std::move(I)},
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000449 std::unique_ptr<Info>{std::move(ParentI)}};
Julie Hockett097aedc2019-07-02 19:59:56 +0000450 }
451 default:
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000452 llvm_unreachable("Invalid reference type for parent namespace");
Julie Hockett097aedc2019-07-02 19:59:56 +0000453 }
Julie Hockette975a472018-03-22 23:34:46 +0000454}
455
Julie Hockett097aedc2019-07-02 19:59:56 +0000456std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
457emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
Diego Astiazaran665e9672019-08-09 17:49:41 +0000458 llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
Julie Hockett8899c292018-08-02 20:10:17 +0000459 FunctionInfo Func;
Julie Hockettd900ef02019-06-28 19:07:56 +0000460 bool IsInAnonymousNamespace = false;
Diego Astiazaran665e9672019-08-09 17:49:41 +0000461 populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir,
462 IsInAnonymousNamespace);
Julie Hockettd900ef02019-06-28 19:07:56 +0000463 if (PublicOnly && ((IsInAnonymousNamespace ||
464 !isPublic(D->getAccess(), D->getLinkageInternal()))))
Julie Hockett097aedc2019-07-02 19:59:56 +0000465 return {};
Julie Hockettd900ef02019-06-28 19:07:56 +0000466
Julie Hockett8899c292018-08-02 20:10:17 +0000467 Func.Access = clang::AccessSpecifier::AS_none;
468
469 // Wrap in enclosing scope
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000470 auto ParentI = llvm::make_unique<NamespaceInfo>();
Julie Hockett8899c292018-08-02 20:10:17 +0000471 if (!Func.Namespace.empty())
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000472 ParentI->USR = Func.Namespace[0].USR;
Julie Hockett8899c292018-08-02 20:10:17 +0000473 else
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000474 ParentI->USR = SymbolID();
475 if (Func.Namespace.empty())
476 ParentI->Path = getInfoRelativePath(ParentI->Namespace);
477 ParentI->ChildFunctions.emplace_back(std::move(Func));
478 // Info is wrapped in its parent scope so it's returned in the second position
479 return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
Julie Hockette975a472018-03-22 23:34:46 +0000480}
481
Julie Hockett097aedc2019-07-02 19:59:56 +0000482std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
483emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
Diego Astiazaran665e9672019-08-09 17:49:41 +0000484 llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
Julie Hockett8899c292018-08-02 20:10:17 +0000485 FunctionInfo Func;
Julie Hockettd900ef02019-06-28 19:07:56 +0000486 bool IsInAnonymousNamespace = false;
Diego Astiazaran665e9672019-08-09 17:49:41 +0000487 populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir,
488 IsInAnonymousNamespace);
Julie Hockettd900ef02019-06-28 19:07:56 +0000489 if (PublicOnly && ((IsInAnonymousNamespace ||
490 !isPublic(D->getAccess(), D->getLinkageInternal()))))
Julie Hockett097aedc2019-07-02 19:59:56 +0000491 return {};
Julie Hockettd900ef02019-06-28 19:07:56 +0000492
Julie Hockett8899c292018-08-02 20:10:17 +0000493 Func.IsMethod = true;
494
Julie Hockettb1f01e22019-06-24 19:31:02 +0000495 const NamedDecl *Parent = nullptr;
496 if (const auto *SD =
497 dyn_cast<ClassTemplateSpecializationDecl>(D->getParent()))
498 Parent = SD->getSpecializedTemplate();
499 else
500 Parent = D->getParent();
501
502 SymbolID ParentUSR = getUSRForDecl(Parent);
503 Func.Parent =
504 Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record};
Julie Hockett8899c292018-08-02 20:10:17 +0000505 Func.Access = D->getAccess();
506
507 // Wrap in enclosing scope
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000508 auto ParentI = llvm::make_unique<RecordInfo>();
509 ParentI->USR = ParentUSR;
510 if (Func.Namespace.empty())
511 ParentI->Path = getInfoRelativePath(ParentI->Namespace);
512 ParentI->ChildFunctions.emplace_back(std::move(Func));
Julie Hockett097aedc2019-07-02 19:59:56 +0000513 // Info is wrapped in its parent scope so it's returned in the second position
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000514 return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
Julie Hockette975a472018-03-22 23:34:46 +0000515}
516
Julie Hockett097aedc2019-07-02 19:59:56 +0000517std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
518emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
Diego Astiazaran665e9672019-08-09 17:49:41 +0000519 llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) {
Julie Hockett8899c292018-08-02 20:10:17 +0000520 EnumInfo Enum;
Julie Hockettd900ef02019-06-28 19:07:56 +0000521 bool IsInAnonymousNamespace = false;
Diego Astiazaran665e9672019-08-09 17:49:41 +0000522 populateSymbolInfo(Enum, D, FC, LineNumber, File, IsFileInRootDir,
523 IsInAnonymousNamespace);
Julie Hockettd900ef02019-06-28 19:07:56 +0000524 if (PublicOnly && ((IsInAnonymousNamespace ||
525 !isPublic(D->getAccess(), D->getLinkageInternal()))))
Julie Hockett097aedc2019-07-02 19:59:56 +0000526 return {};
Julie Hockettd900ef02019-06-28 19:07:56 +0000527
Julie Hockett8899c292018-08-02 20:10:17 +0000528 Enum.Scoped = D->isScoped();
529 parseEnumerators(Enum, D);
530
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000531 // Put in global namespace
532 if (Enum.Namespace.empty()) {
533 auto ParentI = llvm::make_unique<NamespaceInfo>();
534 ParentI->USR = SymbolID();
535 ParentI->ChildEnums.emplace_back(std::move(Enum));
536 ParentI->Path = getInfoRelativePath(ParentI->Namespace);
537 // Info is wrapped in its parent scope so it's returned in the second
538 // position
539 return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
Julie Hockett8899c292018-08-02 20:10:17 +0000540 }
541
Julie Hockett2c1c9a22019-07-12 18:32:00 +0000542 // Wrap in enclosing scope
543 switch (Enum.Namespace[0].RefType) {
544 case InfoType::IT_namespace: {
545 auto ParentI = llvm::make_unique<NamespaceInfo>();
546 ParentI->USR = Enum.Namespace[0].USR;
547 ParentI->ChildEnums.emplace_back(std::move(Enum));
548 // Info is wrapped in its parent scope so it's returned in the second
549 // position
550 return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
551 }
552 case InfoType::IT_record: {
553 auto ParentI = llvm::make_unique<RecordInfo>();
554 ParentI->USR = Enum.Namespace[0].USR;
555 ParentI->ChildEnums.emplace_back(std::move(Enum));
556 // Info is wrapped in its parent scope so it's returned in the second
557 // position
558 return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
559 }
560 default:
561 llvm_unreachable("Invalid reference type for parent namespace");
562 }
Julie Hockette975a472018-03-22 23:34:46 +0000563}
564
565} // namespace serialize
566} // namespace doc
567} // namespace clang