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