blob: 462918bae855dcdd52394d115f2fe133852e3ccf [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
27class ClangDocCommentVisitor
28 : public ConstCommentVisitor<ClangDocCommentVisitor> {
29public:
30 ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {}
31
32 void parseComment(const comments::Comment *C);
33
34 void visitTextComment(const TextComment *C);
35 void visitInlineCommandComment(const InlineCommandComment *C);
36 void visitHTMLStartTagComment(const HTMLStartTagComment *C);
37 void visitHTMLEndTagComment(const HTMLEndTagComment *C);
38 void visitBlockCommandComment(const BlockCommandComment *C);
39 void visitParamCommandComment(const ParamCommandComment *C);
40 void visitTParamCommandComment(const TParamCommandComment *C);
41 void visitVerbatimBlockComment(const VerbatimBlockComment *C);
42 void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
43 void visitVerbatimLineComment(const VerbatimLineComment *C);
44
45private:
46 std::string getCommandName(unsigned CommandID) const;
47 bool isWhitespaceOnly(StringRef S) const;
48
49 CommentInfo &CurrentCI;
50};
51
52void ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
53 CurrentCI.Kind = C->getCommentKindName();
54 ConstCommentVisitor<ClangDocCommentVisitor>::visit(C);
55 for (comments::Comment *Child :
56 llvm::make_range(C->child_begin(), C->child_end())) {
57 CurrentCI.Children.emplace_back(llvm::make_unique<CommentInfo>());
58 ClangDocCommentVisitor Visitor(*CurrentCI.Children.back());
59 Visitor.parseComment(Child);
60 }
61}
62
63void ClangDocCommentVisitor::visitTextComment(const TextComment *C) {
64 if (!isWhitespaceOnly(C->getText()))
65 CurrentCI.Text = C->getText();
66}
67
68void ClangDocCommentVisitor::visitInlineCommandComment(
69 const InlineCommandComment *C) {
70 CurrentCI.Name = getCommandName(C->getCommandID());
71 for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
72 CurrentCI.Args.push_back(C->getArgText(I));
73}
74
75void ClangDocCommentVisitor::visitHTMLStartTagComment(
76 const HTMLStartTagComment *C) {
77 CurrentCI.Name = C->getTagName();
78 CurrentCI.SelfClosing = C->isSelfClosing();
79 for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) {
80 const HTMLStartTagComment::Attribute &Attr = C->getAttr(I);
81 CurrentCI.AttrKeys.push_back(Attr.Name);
82 CurrentCI.AttrValues.push_back(Attr.Value);
83 }
84}
85
86void ClangDocCommentVisitor::visitHTMLEndTagComment(
87 const HTMLEndTagComment *C) {
88 CurrentCI.Name = C->getTagName();
89 CurrentCI.SelfClosing = true;
90}
91
92void ClangDocCommentVisitor::visitBlockCommandComment(
93 const BlockCommandComment *C) {
94 CurrentCI.Name = getCommandName(C->getCommandID());
95 for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
96 CurrentCI.Args.push_back(C->getArgText(I));
97}
98
99void ClangDocCommentVisitor::visitParamCommandComment(
100 const ParamCommandComment *C) {
101 CurrentCI.Direction =
102 ParamCommandComment::getDirectionAsString(C->getDirection());
103 CurrentCI.Explicit = C->isDirectionExplicit();
104 if (C->hasParamName())
105 CurrentCI.ParamName = C->getParamNameAsWritten();
106}
107
108void ClangDocCommentVisitor::visitTParamCommandComment(
109 const TParamCommandComment *C) {
110 if (C->hasParamName())
111 CurrentCI.ParamName = C->getParamNameAsWritten();
112}
113
114void ClangDocCommentVisitor::visitVerbatimBlockComment(
115 const VerbatimBlockComment *C) {
116 CurrentCI.Name = getCommandName(C->getCommandID());
117 CurrentCI.CloseName = C->getCloseName();
118}
119
120void ClangDocCommentVisitor::visitVerbatimBlockLineComment(
121 const VerbatimBlockLineComment *C) {
122 if (!isWhitespaceOnly(C->getText()))
123 CurrentCI.Text = C->getText();
124}
125
126void ClangDocCommentVisitor::visitVerbatimLineComment(
127 const VerbatimLineComment *C) {
128 if (!isWhitespaceOnly(C->getText()))
129 CurrentCI.Text = C->getText();
130}
131
132bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const {
133 return std::all_of(S.begin(), S.end(), isspace);
134}
135
136std::string ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
137 const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
138 if (Info)
139 return Info->Name;
140 // TODO: Add parsing for \file command.
141 return "<not a builtin command>";
142}
143
144// Serializing functions.
145
146template <typename T> static std::string serialize(T &I) {
147 SmallString<2048> Buffer;
148 llvm::BitstreamWriter Stream(Buffer);
149 ClangDocBitcodeWriter Writer(Stream);
150 Writer.emitBlock(I);
151 return Buffer.str().str();
152}
153
Julie Hockett8899c292018-08-02 20:10:17 +0000154std::string serialize(std::unique_ptr<Info> &I) {
155 switch (I->IT) {
156 case InfoType::IT_namespace:
157 return serialize(*static_cast<NamespaceInfo *>(I.get()));
158 case InfoType::IT_record:
159 return serialize(*static_cast<RecordInfo *>(I.get()));
160 case InfoType::IT_enum:
161 return serialize(*static_cast<EnumInfo *>(I.get()));
162 case InfoType::IT_function:
163 return serialize(*static_cast<FunctionInfo *>(I.get()));
164 default:
165 return "";
166 }
167}
168
Julie Hockette975a472018-03-22 23:34:46 +0000169static void parseFullComment(const FullComment *C, CommentInfo &CI) {
170 ClangDocCommentVisitor Visitor(CI);
171 Visitor.parseComment(C);
172}
173
174static SymbolID getUSRForDecl(const Decl *D) {
175 llvm::SmallString<128> USR;
176 if (index::generateUSRForDecl(D, USR))
177 return SymbolID();
178 return hashUSR(USR);
179}
180
181static RecordDecl *getDeclForType(const QualType &T) {
Julie Hockettb1f01e22019-06-24 19:31:02 +0000182 if (const RecordDecl *D = T->getAsRecordDecl())
183 return D->getDefinition();
184 return nullptr;
Julie Hockette975a472018-03-22 23:34:46 +0000185}
186
Julie Hocketteb50a2e2018-07-20 18:49:55 +0000187static bool isPublic(const clang::AccessSpecifier AS,
188 const clang::Linkage Link) {
189 if (AS == clang::AccessSpecifier::AS_private)
190 return false;
191 else if ((Link == clang::Linkage::ModuleLinkage) ||
192 (Link == clang::Linkage::ExternalLinkage))
193 return true;
194 return false; // otherwise, linkage is some form of internal linkage
195}
196
197static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly) {
Julie Hockette975a472018-03-22 23:34:46 +0000198 for (const FieldDecl *F : D->fields()) {
Julie Hocketteb50a2e2018-07-20 18:49:55 +0000199 if (PublicOnly && !isPublic(F->getAccessUnsafe(), F->getLinkageInternal()))
200 continue;
Julie Hockette975a472018-03-22 23:34:46 +0000201 if (const auto *T = getDeclForType(F->getTypeSourceInfo()->getType())) {
Julie Hockettb59cd772018-05-04 17:02:13 +0000202 // Use getAccessUnsafe so that we just get the default AS_none if it's not
203 // valid, as opposed to an assert.
204 if (const auto *N = dyn_cast<EnumDecl>(T)) {
205 I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
206 InfoType::IT_enum, F->getNameAsString(),
207 N->getAccessUnsafe());
208 continue;
209 } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
210 I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
211 InfoType::IT_record, F->getNameAsString(),
212 N->getAccessUnsafe());
213 continue;
214 }
Julie Hockette975a472018-03-22 23:34:46 +0000215 }
Julie Hockettb59cd772018-05-04 17:02:13 +0000216 I.Members.emplace_back(F->getTypeSourceInfo()->getType().getAsString(),
217 F->getNameAsString(), F->getAccessUnsafe());
Julie Hockette975a472018-03-22 23:34:46 +0000218 }
219}
220
221static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
222 for (const EnumConstantDecl *E : D->enumerators())
223 I.Members.emplace_back(E->getNameAsString());
224}
225
226static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
227 for (const ParmVarDecl *P : D->parameters()) {
Julie Hockette975a472018-03-22 23:34:46 +0000228 if (const auto *T = getDeclForType(P->getOriginalType())) {
Julie Hockettb59cd772018-05-04 17:02:13 +0000229 if (const auto *N = dyn_cast<EnumDecl>(T)) {
230 I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
231 InfoType::IT_enum, P->getNameAsString());
232 continue;
233 } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
234 I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
235 InfoType::IT_record, P->getNameAsString());
236 continue;
237 }
Julie Hockette975a472018-03-22 23:34:46 +0000238 }
Julie Hockettb59cd772018-05-04 17:02:13 +0000239 I.Params.emplace_back(P->getOriginalType().getAsString(),
240 P->getNameAsString());
Julie Hockette975a472018-03-22 23:34:46 +0000241 }
242}
243
244static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
Julie Hockett73a4d542018-10-03 18:25:27 +0000245 // Don't parse bases if this isn't a definition.
246 if (!D->isThisDeclarationADefinition())
247 return;
Julie Hockette975a472018-03-22 23:34:46 +0000248 for (const CXXBaseSpecifier &B : D->bases()) {
249 if (B.isVirtual())
250 continue;
Julie Hockettb1f01e22019-06-24 19:31:02 +0000251 if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
252 const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
253 I.Parents.emplace_back(getUSRForDecl(D), B.getType().getAsString(),
254 InfoType::IT_record);
255 } else if (const RecordDecl *P = getDeclForType(B.getType()))
Julie Hockettb59cd772018-05-04 17:02:13 +0000256 I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
257 InfoType::IT_record);
Julie Hockette975a472018-03-22 23:34:46 +0000258 else
259 I.Parents.emplace_back(B.getType().getAsString());
260 }
261 for (const CXXBaseSpecifier &B : D->vbases()) {
262 if (const auto *P = getDeclForType(B.getType()))
Julie Hockettb59cd772018-05-04 17:02:13 +0000263 I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
264 InfoType::IT_record);
Julie Hockette975a472018-03-22 23:34:46 +0000265 else
266 I.VirtualParents.emplace_back(B.getType().getAsString());
267 }
268}
269
270template <typename T>
271static void
272populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
Julie Hockettd900ef02019-06-28 19:07:56 +0000273 const T *D, bool &IsAnonymousNamespace) {
Julie Hockette975a472018-03-22 23:34:46 +0000274 const auto *DC = dyn_cast<DeclContext>(D);
275 while ((DC = DC->getParent())) {
Julie Hockettd900ef02019-06-28 19:07:56 +0000276 if (const auto *N = dyn_cast<NamespaceDecl>(DC)) {
277 std::string Namespace;
278 if (N->isAnonymousNamespace()) {
279 Namespace = "@nonymous_namespace";
280 IsAnonymousNamespace = true;
281 } else
282 Namespace = N->getNameAsString();
283 Namespaces.emplace_back(getUSRForDecl(N), Namespace,
Julie Hockettb59cd772018-05-04 17:02:13 +0000284 InfoType::IT_namespace);
Julie Hockettd900ef02019-06-28 19:07:56 +0000285 } else if (const auto *N = dyn_cast<RecordDecl>(DC))
Julie Hockettb59cd772018-05-04 17:02:13 +0000286 Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
287 InfoType::IT_record);
Julie Hockette975a472018-03-22 23:34:46 +0000288 else if (const auto *N = dyn_cast<FunctionDecl>(DC))
Julie Hockettb59cd772018-05-04 17:02:13 +0000289 Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
290 InfoType::IT_function);
Julie Hockette975a472018-03-22 23:34:46 +0000291 else if (const auto *N = dyn_cast<EnumDecl>(DC))
Julie Hockettb59cd772018-05-04 17:02:13 +0000292 Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
293 InfoType::IT_enum);
Julie Hockette975a472018-03-22 23:34:46 +0000294 }
295}
296
297template <typename T>
Julie Hockettd900ef02019-06-28 19:07:56 +0000298static void populateInfo(Info &I, const T *D, const FullComment *C,
299 bool &IsInAnonymousNamespace) {
Julie Hockette975a472018-03-22 23:34:46 +0000300 I.USR = getUSRForDecl(D);
301 I.Name = D->getNameAsString();
Julie Hockettd900ef02019-06-28 19:07:56 +0000302 populateParentNamespaces(I.Namespace, D, IsInAnonymousNamespace);
Julie Hockette975a472018-03-22 23:34:46 +0000303 if (C) {
304 I.Description.emplace_back();
305 parseFullComment(C, I.Description.back());
306 }
307}
308
309template <typename T>
310static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
Julie Hockettd900ef02019-06-28 19:07:56 +0000311 int LineNumber, StringRef Filename,
312 bool &IsInAnonymousNamespace) {
313 populateInfo(I, D, C, IsInAnonymousNamespace);
Julie Hockette975a472018-03-22 23:34:46 +0000314 if (D->isThisDeclarationADefinition())
315 I.DefLoc.emplace(LineNumber, Filename);
316 else
317 I.Loc.emplace_back(LineNumber, Filename);
318}
319
320static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
321 const FullComment *FC, int LineNumber,
Julie Hockettd900ef02019-06-28 19:07:56 +0000322 StringRef Filename,
323 bool &IsInAnonymousNamespace) {
324 populateSymbolInfo(I, D, FC, LineNumber, Filename, IsInAnonymousNamespace);
Julie Hockette975a472018-03-22 23:34:46 +0000325 if (const auto *T = getDeclForType(D->getReturnType())) {
Julie Hockette975a472018-03-22 23:34:46 +0000326 if (dyn_cast<EnumDecl>(T))
Julie Hockettb59cd772018-05-04 17:02:13 +0000327 I.ReturnType =
328 TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_enum);
Julie Hockette975a472018-03-22 23:34:46 +0000329 else if (dyn_cast<RecordDecl>(T))
Julie Hockettb59cd772018-05-04 17:02:13 +0000330 I.ReturnType =
331 TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_record);
Julie Hockette975a472018-03-22 23:34:46 +0000332 } else {
Julie Hockettb59cd772018-05-04 17:02:13 +0000333 I.ReturnType = TypeInfo(D->getReturnType().getAsString());
Julie Hockette975a472018-03-22 23:34:46 +0000334 }
335 parseParameters(I, D);
336}
337
Julie Hockett8899c292018-08-02 20:10:17 +0000338std::unique_ptr<Info> emitInfo(const NamespaceDecl *D, const FullComment *FC,
339 int LineNumber, llvm::StringRef File,
340 bool PublicOnly) {
Julie Hockettd900ef02019-06-28 19:07:56 +0000341 auto I = llvm::make_unique<NamespaceInfo>();
342 bool IsInAnonymousNamespace = false;
343 populateInfo(*I, D, FC, IsInAnonymousNamespace);
344 if (PublicOnly && ((IsInAnonymousNamespace || D->isAnonymousNamespace()) ||
Julie Hocketteb50a2e2018-07-20 18:49:55 +0000345 !isPublic(D->getAccess(), D->getLinkageInternal())))
Julie Hockett8899c292018-08-02 20:10:17 +0000346 return nullptr;
Julie Hockettd900ef02019-06-28 19:07:56 +0000347 I->Name = D->isAnonymousNamespace()
348 ? llvm::SmallString<16>("@nonymous_namespace")
349 : I->Name;
Julie Hockett87072162018-08-03 00:40:11 +0000350 return std::unique_ptr<Info>{std::move(I)};
Julie Hockette975a472018-03-22 23:34:46 +0000351}
352
Julie Hockett8899c292018-08-02 20:10:17 +0000353std::unique_ptr<Info> emitInfo(const RecordDecl *D, const FullComment *FC,
354 int LineNumber, llvm::StringRef File,
355 bool PublicOnly) {
Julie Hockett8899c292018-08-02 20:10:17 +0000356 auto I = llvm::make_unique<RecordInfo>();
Julie Hockettd900ef02019-06-28 19:07:56 +0000357 bool IsInAnonymousNamespace = false;
358 populateSymbolInfo(*I, D, FC, LineNumber, File, IsInAnonymousNamespace);
359 if (PublicOnly && ((IsInAnonymousNamespace ||
360 !isPublic(D->getAccess(), D->getLinkageInternal()))))
361 return nullptr;
362
Julie Hockett8899c292018-08-02 20:10:17 +0000363 I->TagType = D->getTagKind();
364 parseFields(*I, D, PublicOnly);
Julie Hockettb1f01e22019-06-24 19:31:02 +0000365 if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
366 if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl()) {
367 I->Name = TD->getNameAsString();
368 I->IsTypeDef = true;
369 }
Julie Hockett8899c292018-08-02 20:10:17 +0000370 parseBases(*I, C);
Julie Hockettb1f01e22019-06-24 19:31:02 +0000371 }
Julie Hockett87072162018-08-03 00:40:11 +0000372 return std::unique_ptr<Info>{std::move(I)};
Julie Hockette975a472018-03-22 23:34:46 +0000373}
374
Julie Hockett8899c292018-08-02 20:10:17 +0000375std::unique_ptr<Info> emitInfo(const FunctionDecl *D, const FullComment *FC,
376 int LineNumber, llvm::StringRef File,
377 bool PublicOnly) {
Julie Hockett8899c292018-08-02 20:10:17 +0000378 FunctionInfo Func;
Julie Hockettd900ef02019-06-28 19:07:56 +0000379 bool IsInAnonymousNamespace = false;
380 populateFunctionInfo(Func, D, FC, LineNumber, File, IsInAnonymousNamespace);
381 if (PublicOnly && ((IsInAnonymousNamespace ||
382 !isPublic(D->getAccess(), D->getLinkageInternal()))))
383 return nullptr;
384
Julie Hockett8899c292018-08-02 20:10:17 +0000385 Func.Access = clang::AccessSpecifier::AS_none;
386
387 // Wrap in enclosing scope
388 auto I = llvm::make_unique<NamespaceInfo>();
389 if (!Func.Namespace.empty())
390 I->USR = Func.Namespace[0].USR;
391 else
392 I->USR = SymbolID();
Julie Hockettb8ff56c2018-08-24 16:43:46 +0000393 I->ChildFunctions.emplace_back(std::move(Func));
Julie Hockett87072162018-08-03 00:40:11 +0000394 return std::unique_ptr<Info>{std::move(I)};
Julie Hockette975a472018-03-22 23:34:46 +0000395}
396
Julie Hockett8899c292018-08-02 20:10:17 +0000397std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC,
398 int LineNumber, llvm::StringRef File,
399 bool PublicOnly) {
Julie Hockett8899c292018-08-02 20:10:17 +0000400 FunctionInfo Func;
Julie Hockettd900ef02019-06-28 19:07:56 +0000401 bool IsInAnonymousNamespace = false;
402 populateFunctionInfo(Func, D, FC, LineNumber, File, IsInAnonymousNamespace);
403 if (PublicOnly && ((IsInAnonymousNamespace ||
404 !isPublic(D->getAccess(), D->getLinkageInternal()))))
405 return nullptr;
406
Julie Hockett8899c292018-08-02 20:10:17 +0000407 Func.IsMethod = true;
408
Julie Hockettb1f01e22019-06-24 19:31:02 +0000409 const NamedDecl *Parent = nullptr;
410 if (const auto *SD =
411 dyn_cast<ClassTemplateSpecializationDecl>(D->getParent()))
412 Parent = SD->getSpecializedTemplate();
413 else
414 Parent = D->getParent();
415
416 SymbolID ParentUSR = getUSRForDecl(Parent);
417 Func.Parent =
418 Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record};
Julie Hockett8899c292018-08-02 20:10:17 +0000419 Func.Access = D->getAccess();
420
421 // Wrap in enclosing scope
422 auto I = llvm::make_unique<RecordInfo>();
423 I->USR = ParentUSR;
Julie Hockettb8ff56c2018-08-24 16:43:46 +0000424 I->ChildFunctions.emplace_back(std::move(Func));
Julie Hockett87072162018-08-03 00:40:11 +0000425 return std::unique_ptr<Info>{std::move(I)};
Julie Hockette975a472018-03-22 23:34:46 +0000426}
427
Julie Hockett8899c292018-08-02 20:10:17 +0000428std::unique_ptr<Info> emitInfo(const EnumDecl *D, const FullComment *FC,
429 int LineNumber, llvm::StringRef File,
430 bool PublicOnly) {
Julie Hockett8899c292018-08-02 20:10:17 +0000431 EnumInfo Enum;
Julie Hockettd900ef02019-06-28 19:07:56 +0000432 bool IsInAnonymousNamespace = false;
433 populateSymbolInfo(Enum, D, FC, LineNumber, File, IsInAnonymousNamespace);
434 if (PublicOnly && ((IsInAnonymousNamespace ||
435 !isPublic(D->getAccess(), D->getLinkageInternal()))))
436 return nullptr;
437
Julie Hockett8899c292018-08-02 20:10:17 +0000438 Enum.Scoped = D->isScoped();
439 parseEnumerators(Enum, D);
440
441 // Wrap in enclosing scope
442 if (!Enum.Namespace.empty()) {
443 switch (Enum.Namespace[0].RefType) {
444 case InfoType::IT_namespace: {
Julie Hockett87072162018-08-03 00:40:11 +0000445 auto I = llvm::make_unique<NamespaceInfo>();
Julie Hockett8899c292018-08-02 20:10:17 +0000446 I->USR = Enum.Namespace[0].USR;
Julie Hockettb8ff56c2018-08-24 16:43:46 +0000447 I->ChildEnums.emplace_back(std::move(Enum));
Julie Hockett87072162018-08-03 00:40:11 +0000448 return std::unique_ptr<Info>{std::move(I)};
Julie Hockett8899c292018-08-02 20:10:17 +0000449 }
450 case InfoType::IT_record: {
Julie Hockett87072162018-08-03 00:40:11 +0000451 auto I = llvm::make_unique<RecordInfo>();
Julie Hockett8899c292018-08-02 20:10:17 +0000452 I->USR = Enum.Namespace[0].USR;
Julie Hockettb8ff56c2018-08-24 16:43:46 +0000453 I->ChildEnums.emplace_back(std::move(Enum));
Julie Hockett87072162018-08-03 00:40:11 +0000454 return std::unique_ptr<Info>{std::move(I)};
Julie Hockett8899c292018-08-02 20:10:17 +0000455 }
456 default:
457 break;
458 }
459 }
460
461 // Put in global namespace
462 auto I = llvm::make_unique<NamespaceInfo>();
463 I->USR = SymbolID();
Julie Hockettb8ff56c2018-08-24 16:43:46 +0000464 I->ChildEnums.emplace_back(std::move(Enum));
Julie Hockett87072162018-08-03 00:40:11 +0000465 return std::unique_ptr<Info>{std::move(I)};
Julie Hockette975a472018-03-22 23:34:46 +0000466}
467
468} // namespace serialize
469} // namespace doc
470} // namespace clang