clang-tools 23.0.0git
Serialize.cpp
Go to the documentation of this file.
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
12#include "clang/AST/Attr.h"
13#include "clang/AST/Comment.h"
14#include "clang/AST/CommentVisitor.h"
15#include "clang/AST/DeclFriend.h"
16#include "clang/AST/ExprConcepts.h"
17#include "clang/AST/Mangle.h"
18#include "clang/Lex/Lexer.h"
19#include "clang/UnifiedSymbolResolution/USRGeneration.h"
20#include "llvm/ADT/StringExtras.h"
21#include "llvm/Support/SHA1.h"
22
23using clang::comments::FullComment;
24
25namespace clang {
26namespace doc {
27namespace serialize {
28
29namespace {
30static StringRef exprToString(const clang::Expr *E) {
31 clang::LangOptions Opts;
32 clang::PrintingPolicy Policy(Opts);
33 SmallString<16> Result;
34 llvm::raw_svector_ostream OS(Result);
35 E->printPretty(OS, nullptr, Policy);
36 return internString(Result);
37}
38} // namespace
39
40SymbolID hashUSR(llvm::StringRef USR) {
41 return llvm::SHA1::hash(arrayRefFromStringRef(USR));
42}
43
44void Serializer::getTemplateParameters(
45 const TemplateParameterList *TemplateParams, llvm::raw_ostream &Stream) {
46 Stream << "template <";
47
48 for (unsigned i = 0; i < TemplateParams->size(); ++i) {
49 if (i > 0)
50 Stream << ", ";
51
52 const NamedDecl *Param = TemplateParams->getParam(i);
53 if (const auto *TTP = llvm::dyn_cast<TemplateTypeParmDecl>(Param)) {
54 if (TTP->wasDeclaredWithTypename())
55 Stream << "typename";
56 else
57 Stream << "class";
58 if (TTP->isParameterPack())
59 Stream << "...";
60 Stream << " " << TTP->getNameAsString();
61
62 // We need to also handle type constraints for code like:
63 // template <class T = void>
64 // class C {};
65 if (TTP->hasTypeConstraint()) {
66 Stream << " = ";
67 TTP->getTypeConstraint()->print(
68 Stream, TTP->getASTContext().getPrintingPolicy());
69 }
70 } else if (const auto *NTTP =
71 llvm::dyn_cast<NonTypeTemplateParmDecl>(Param)) {
72 NTTP->getType().print(Stream, NTTP->getASTContext().getPrintingPolicy());
73 if (NTTP->isParameterPack())
74 Stream << "...";
75 Stream << " " << NTTP->getNameAsString();
76 } else if (const auto *TTPD =
77 llvm::dyn_cast<TemplateTemplateParmDecl>(Param)) {
78 Stream << "template <";
79 getTemplateParameters(TTPD->getTemplateParameters(), Stream);
80 Stream << "> class " << TTPD->getNameAsString();
81 }
82 }
83
84 Stream << "> ";
85}
86
87// Extract the full function prototype from a FunctionDecl including
88// Full Decl
89StringRef Serializer::getFunctionPrototype(const FunctionDecl *FuncDecl) {
90 llvm::SmallString<256> Result;
91 llvm::raw_svector_ostream Stream(Result);
92 const ASTContext &Ctx = FuncDecl->getASTContext();
93 const auto *Method = llvm::dyn_cast<CXXMethodDecl>(FuncDecl);
94 // If it's a templated function, handle the template parameters
95 if (const auto *TmplDecl = FuncDecl->getDescribedTemplate())
96 getTemplateParameters(TmplDecl->getTemplateParameters(), Stream);
97
98 // If it's a virtual method
99 if (Method && Method->isVirtual())
100 Stream << "virtual ";
101
102 // Print return type
103 FuncDecl->getReturnType().print(Stream, Ctx.getPrintingPolicy());
104
105 // Print function name
106 Stream << " " << FuncDecl->getNameAsString() << "(";
107
108 // Print parameter list with types, names, and default values
109 for (unsigned I = 0; I < FuncDecl->getNumParams(); ++I) {
110 if (I > 0)
111 Stream << ", ";
112 const ParmVarDecl *ParamDecl = FuncDecl->getParamDecl(I);
113 QualType ParamType = ParamDecl->getType();
114 ParamType.print(Stream, Ctx.getPrintingPolicy());
115
116 // Print parameter name if it has one
117 if (!ParamDecl->getName().empty())
118 Stream << " " << ParamDecl->getNameAsString();
119
120 // Print default argument if it exists
121 if (ParamDecl->hasDefaultArg() &&
122 !ParamDecl->hasUninstantiatedDefaultArg()) {
123 if (const Expr *DefaultArg = ParamDecl->getDefaultArg()) {
124 Stream << " = ";
125 DefaultArg->printPretty(Stream, nullptr, Ctx.getPrintingPolicy());
126 }
127 }
128 }
129
130 // If it is a variadic function, add '...'
131 if (FuncDecl->isVariadic()) {
132 if (FuncDecl->getNumParams() > 0)
133 Stream << ", ";
134 Stream << "...";
135 }
136
137 Stream << ")";
138
139 // If it's a const method, add 'const' qualifier
140 if (Method) {
141 if (Method->isDeleted())
142 Stream << " = delete";
143 if (Method->size_overridden_methods())
144 Stream << " override";
145 if (Method->hasAttr<clang::FinalAttr>())
146 Stream << " final";
147 if (Method->isConst())
148 Stream << " const";
149 if (Method->isPureVirtual())
150 Stream << " = 0";
151 }
152
153 if (auto ExceptionSpecType = FuncDecl->getExceptionSpecType())
154 Stream << " " << ExceptionSpecType;
155
156 return internString(Result);
157}
158
159StringRef Serializer::getTypeAlias(const TypeAliasDecl *Alias) {
160 llvm::SmallString<16> Result;
161 llvm::raw_svector_ostream Stream(Result);
162 const ASTContext &Ctx = Alias->getASTContext();
163 if (const auto *TmplDecl = Alias->getDescribedTemplate())
164 getTemplateParameters(TmplDecl->getTemplateParameters(), Stream);
165 Stream << "using " << Alias->getNameAsString() << " = ";
166 QualType Q = Alias->getUnderlyingType();
167 Q.print(Stream, Ctx.getPrintingPolicy());
168
169 return internString(Result);
170}
171
172// A function to extract the appropriate relative path for a given info's
173// documentation. The path returned is a composite of the parent namespaces.
174//
175// Example: Given the below, the directory path for class C info will be
176// <root>/A/B
177//
178// namespace A {
179// namespace B {
180//
181// class C {};
182//
183// }
184// }
185StringRef
186Serializer::getInfoRelativePath(llvm::ArrayRef<doc::Reference> Namespaces) {
187 llvm::SmallString<128> Path;
188 for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
189 llvm::sys::path::append(Path, R->Name);
190 return internString(Path);
191}
192
193StringRef Serializer::getInfoRelativePath(const Decl *D) {
194 llvm::SmallVector<Reference, 4> Namespaces;
195 // The third arg in populateParentNamespaces is a boolean passed by reference,
196 // its value is not relevant in here so it's not used anywhere besides the
197 // function call
198 bool B = true;
199 populateParentNamespaces(Namespaces, D, B);
200 return getInfoRelativePath(Namespaces);
201}
202
204 : public ConstCommentVisitor<ClangDocCommentVisitor> {
205public:
206 ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {}
207
208 void parseComment(const comments::Comment *C);
209
210 void visitTextComment(const TextComment *C);
211 void visitInlineCommandComment(const InlineCommandComment *C);
212 void visitHTMLStartTagComment(const HTMLStartTagComment *C);
213 void visitHTMLEndTagComment(const HTMLEndTagComment *C);
214 void visitBlockCommandComment(const BlockCommandComment *C);
215 void visitParamCommandComment(const ParamCommandComment *C);
216 void visitTParamCommandComment(const TParamCommandComment *C);
217 void visitVerbatimBlockComment(const VerbatimBlockComment *C);
218 void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
219 void visitVerbatimLineComment(const VerbatimLineComment *C);
220
221private:
222 StringRef getCommandName(unsigned CommandID) const;
223 bool isWhitespaceOnly(StringRef S) const;
224
225 CommentInfo &CurrentCI;
226};
227
228void ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
229 CurrentCI.Kind = stringToCommentKind(C->getCommentKindName());
231
232 unsigned NumChildren = C->child_count();
233 if (NumChildren > 0) {
234 CommentInfo *ChildrenArray =
235 TransientArena.Allocate<CommentInfo>(NumChildren);
236 unsigned Idx = 0;
237 for (comments::Comment *Child :
238 llvm::make_range(C->child_begin(), C->child_end())) {
239 new (&ChildrenArray[Idx]) CommentInfo();
240 ClangDocCommentVisitor Visitor(ChildrenArray[Idx]);
241 Visitor.parseComment(Child);
242 Idx++;
243 }
244 assert(Idx == NumChildren &&
245 "Mismatch between child_count and actual children");
246 CurrentCI.Children =
247 llvm::ArrayRef<CommentInfo>(ChildrenArray, NumChildren);
248 }
249}
250
252 if (!isWhitespaceOnly(C->getText()))
253 CurrentCI.Text = C->getText().trim();
254}
255
257 const InlineCommandComment *C) {
258 CurrentCI.Name = internString(getCommandName(C->getCommandID()));
259 llvm::SmallVector<StringRef> Args;
260 for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
261 Args.push_back(internString(C->getArgText(I).trim()));
262 if (!Args.empty()) {
263 CurrentCI.Args = allocateArray(Args, TransientArena);
264 }
265}
266
268 const HTMLStartTagComment *C) {
269 CurrentCI.Name = internString(C->getTagName());
270 CurrentCI.SelfClosing = C->isSelfClosing();
271 llvm::SmallVector<StringRef> AttrKeys;
272 llvm::SmallVector<StringRef> AttrValues;
273 for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) {
274 const HTMLStartTagComment::Attribute &Attr = C->getAttr(I);
275 AttrKeys.push_back(internString(Attr.Name));
276 AttrValues.push_back(internString(Attr.Value));
277 }
278 if (!AttrKeys.empty()) {
279 CurrentCI.AttrKeys = allocateArray(AttrKeys, TransientArena);
280 }
281 if (!AttrValues.empty()) {
282 CurrentCI.AttrValues = allocateArray(AttrValues, TransientArena);
283 }
284}
285
287 const HTMLEndTagComment *C) {
288 CurrentCI.Name = internString(C->getTagName());
289 CurrentCI.SelfClosing = true;
290}
291
293 const BlockCommandComment *C) {
294 CurrentCI.Name = internString(getCommandName(C->getCommandID()));
295 llvm::SmallVector<StringRef> Args;
296 for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
297 Args.push_back(internString(C->getArgText(I).trim()));
298 if (!Args.empty()) {
299 CurrentCI.Args = allocateArray(Args, TransientArena);
300 }
301}
302
304 const ParamCommandComment *C) {
305 CurrentCI.Direction = internString(
306 ParamCommandComment::getDirectionAsString(C->getDirection()));
307 CurrentCI.Explicit = C->isDirectionExplicit();
308 if (C->hasParamName())
309 CurrentCI.ParamName = internString(C->getParamNameAsWritten());
310}
311
313 const TParamCommandComment *C) {
314 if (C->hasParamName())
315 CurrentCI.ParamName = internString(C->getParamNameAsWritten());
316}
317
319 const VerbatimBlockComment *C) {
320 CurrentCI.Name = internString(getCommandName(C->getCommandID()));
321 CurrentCI.CloseName = internString(C->getCloseName());
322}
323
325 const VerbatimBlockLineComment *C) {
326 if (!isWhitespaceOnly(C->getText()))
327 CurrentCI.Text = internString(C->getText());
328}
329
331 const VerbatimLineComment *C) {
332 if (!isWhitespaceOnly(C->getText()))
333 CurrentCI.Text = internString(C->getText());
334}
335
336bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const {
337 return llvm::all_of(S, isspace);
338}
339
340StringRef ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
341 const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
342 if (Info)
343 return internString(Info->Name);
344 // TODO: Add parsing for \file command.
345 return "<not a builtin command>";
346}
347
348// Serializing functions.
349
350StringRef Serializer::getSourceCode(const Decl *D, const SourceRange &R) {
351 return internString(Lexer::getSourceText(
352 CharSourceRange::getTokenRange(R), D->getASTContext().getSourceManager(),
353 D->getASTContext().getLangOpts()));
354}
355
356template <typename T>
357static std::string serialize(T &I, DiagnosticsEngine &Diags) {
358 SmallString<2048> Buffer;
359 llvm::BitstreamWriter Stream(Buffer);
360 ClangDocBitcodeWriter Writer(Stream, Diags);
361 Writer.emitBlock(I);
362 return Buffer.str().str();
363}
364
365std::string serialize(OwnedPtr<Info> &I, DiagnosticsEngine &Diags) {
366 switch (I->IT) {
368 return serialize(*static_cast<NamespaceInfo *>(getPtr(I)), Diags);
370 return serialize(*static_cast<RecordInfo *>(getPtr(I)), Diags);
372 return serialize(*static_cast<EnumInfo *>(getPtr(I)), Diags);
374 return serialize(*static_cast<FunctionInfo *>(getPtr(I)), Diags);
376 return serialize(*static_cast<ConceptInfo *>(getPtr(I)), Diags);
378 return serialize(*static_cast<VarInfo *>(getPtr(I)), Diags);
382 return "";
383 }
384 llvm_unreachable("unhandled enumerator");
385}
386
387void Serializer::parseFullComment(const FullComment *C, CommentInfo &CI) {
388 ClangDocCommentVisitor Visitor(CI);
389 Visitor.parseComment(C);
390}
391
392SymbolID Serializer::getUSRForDecl(const Decl *D) {
393 llvm::SmallString<128> USR;
394 if (index::generateUSRForDecl(D, USR))
395 return SymbolID();
396 return hashUSR(USR);
397}
398
399TagDecl *Serializer::getTagDeclForType(const QualType &T) {
400 if (const TagDecl *D = T->getAsTagDecl())
401 return D->getDefinition();
402 return nullptr;
403}
404
405RecordDecl *Serializer::getRecordDeclForType(const QualType &T) {
406 if (const RecordDecl *D = T->getAsRecordDecl())
407 return D->getDefinition();
408 return nullptr;
409}
410
411TypeInfo Serializer::getTypeInfoForType(const QualType &T,
412 const PrintingPolicy &Policy) {
413 const TagDecl *TD = getTagDeclForType(T);
414 if (!TD) {
415 TypeInfo TI = TypeInfo(Reference(SymbolID(), T.getAsString(Policy)));
416 TI.IsBuiltIn = T->isBuiltinType();
417 TI.IsTemplate = T->isTemplateTypeParmType();
418 return TI;
419 }
420 InfoType IT;
421 if (isa<EnumDecl>(TD)) {
423 } else if (isa<RecordDecl>(TD)) {
425 } else {
427 }
428 Reference R = Reference(getUSRForDecl(TD), TD->getNameAsString(), IT,
429 T.getAsString(Policy), getInfoRelativePath(TD));
430 TypeInfo TI = TypeInfo(R);
431 TI.IsBuiltIn = T->isBuiltinType();
432 TI.IsTemplate = T->isTemplateTypeParmType();
433 return TI;
434}
435
436bool Serializer::isPublic(const clang::AccessSpecifier AS,
437 const clang::Linkage Link) {
438 if (AS == clang::AccessSpecifier::AS_private)
439 return false;
440 if ((Link == clang::Linkage::Module) || (Link == clang::Linkage::External))
441 return true;
442 return false; // otherwise, linkage is some form of internal linkage
443}
444
445bool Serializer::shouldSerializeInfo(bool PublicOnly,
446 bool IsInAnonymousNamespace,
447 const NamedDecl *D) {
448 bool IsAnonymousNamespace = false;
449 if (const auto *N = dyn_cast<NamespaceDecl>(D))
450 IsAnonymousNamespace = N->isAnonymousNamespace();
451 return !PublicOnly ||
452 (!IsInAnonymousNamespace && !IsAnonymousNamespace &&
453 isPublic(D->getAccessUnsafe(), D->getLinkageInternal()));
454}
455
456// The InsertChild functions insert the given info into the given scope using
457// the method appropriate for that type. Some types are moved into the
458// appropriate vector, while other types have Reference objects generated to
459// refer to them.
460//
461// See MakeAndInsertIntoParent().
462void Serializer::InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) {
463 Scope.Namespaces.push_back(*allocateListNodeTransient<Reference>(
464 Info.USR, Info.Name, InfoType::IT_namespace, Info.Name,
465 getInfoRelativePath(Info.Namespace)));
466}
467
468void Serializer::InsertChild(ScopeChildren &Scope, const RecordInfo &Info) {
469 Scope.Records.push_back(*allocateListNodeTransient<Reference>(
470 Info.USR, Info.Name, InfoType::IT_record, Info.Name,
471 getInfoRelativePath(Info.Namespace), Info.MangledName));
472}
473
474void Serializer::InsertChild(ScopeChildren &Scope, EnumInfo &Info) {
475 Scope.Enums.push_back(*allocateListNodeTransient<EnumInfo>(&Info));
476}
477
478void Serializer::InsertChild(ScopeChildren &Scope, FunctionInfo &Info) {
479 Scope.Functions.push_back(*allocateListNodeTransient<FunctionInfo>(&Info));
480}
481
482void Serializer::InsertChild(ScopeChildren &Scope, TypedefInfo &Info) {
483 Scope.Typedefs.push_back(*allocateListNodeTransient<TypedefInfo>(&Info));
484}
485
486void Serializer::InsertChild(ScopeChildren &Scope, ConceptInfo &Info) {
487 Scope.Concepts.push_back(*allocateListNodeTransient<ConceptInfo>(&Info));
488}
489
490void Serializer::InsertChild(ScopeChildren &Scope, VarInfo &Info) {
491 Scope.Variables.push_back(*allocateListNodeTransient<VarInfo>(&Info));
492}
493
494// Creates a parent of the correct type for the given child and inserts it into
495// that parent.
496//
497// This is complicated by the fact that namespaces and records are inserted by
498// reference (constructing a "Reference" object with that namespace/record's
499// info), while everything else is inserted by moving it directly into the child
500// vectors.
501//
502// For namespaces and records, explicitly specify a const& template parameter
503// when invoking this function:
504// MakeAndInsertIntoParent<const Record&>(...);
505// Otherwise, specify an rvalue reference <EnumInfo&&> and move into the
506// parameter. Since each variant is used once, it's not worth having a more
507// elaborate system to automatically deduce this information.
508template <typename ChildType>
509OwnedPtr<Info> Serializer::makeAndInsertIntoParent(ChildType &Child) {
510 if (Child.Namespace.empty()) {
511 // Insert into unnamed parent namespace.
512 auto ParentNS = allocatePtr<NamespaceInfo>();
513 InsertChild(ParentNS->Children, Child);
514 return ParentNS;
515 }
516
517 switch (Child.Namespace[0].RefType) {
519 auto ParentNS = allocatePtr<NamespaceInfo>();
520 ParentNS->USR = Child.Namespace[0].USR;
521 InsertChild(ParentNS->Children, Child);
522 return ParentNS;
523 }
524 case InfoType::IT_record: {
525 auto ParentRec = allocatePtr<RecordInfo>();
526 ParentRec->USR = Child.Namespace[0].USR;
527 InsertChild(ParentRec->Children, Child);
528 return ParentRec;
529 }
537 break;
538 }
539 llvm_unreachable("Invalid reference type for parent namespace");
540}
541
542// There are two uses for this function.
543// 1) Getting the resulting mode of inheritance of a record.
544// Example: class A {}; class B : private A {}; class C : public B {};
545// It's explicit that C is publicly inherited from C and B is privately
546// inherited from A. It's not explicit but C is also privately inherited from
547// A. This is the AS that this function calculates. FirstAS is the
548// inheritance mode of `class C : B` and SecondAS is the inheritance mode of
549// `class B : A`.
550// 2) Getting the inheritance mode of an inherited attribute / method.
551// Example : class A { public: int M; }; class B : private A {};
552// Class B is inherited from class A, which has a public attribute. This
553// attribute is now part of the derived class B but it's not public. This
554// will be private because the inheritance is private. This is the AS that
555// this function calculates. FirstAS is the inheritance mode and SecondAS is
556// the AS of the attribute / method.
557AccessSpecifier Serializer::getFinalAccessSpecifier(AccessSpecifier FirstAS,
558 AccessSpecifier SecondAS) {
559 if (FirstAS == AccessSpecifier::AS_none ||
560 SecondAS == AccessSpecifier::AS_none)
561 return AccessSpecifier::AS_none;
562 if (FirstAS == AccessSpecifier::AS_private ||
563 SecondAS == AccessSpecifier::AS_private)
564 return AccessSpecifier::AS_private;
565 if (FirstAS == AccessSpecifier::AS_protected ||
566 SecondAS == AccessSpecifier::AS_protected)
567 return AccessSpecifier::AS_protected;
568 return AccessSpecifier::AS_public;
569}
570
571// The Access parameter is only provided when parsing the field of an inherited
572// record, the access specification of the field depends on the inheritance mode
573void Serializer::parseFields(RecordInfo &I, const RecordDecl *D,
574 bool PublicOnly, AccessSpecifier Access) {
575 SmallVector<MemberTypeInfo, 4> Members;
576 for (const FieldDecl *F : D->fields()) {
577 if (!shouldSerializeInfo(PublicOnly, /*IsInAnonymousNamespace=*/false, F))
578 continue;
579 populateMemberTypeInfo(Members, Access, F);
580 }
581 const auto *CxxRD = dyn_cast<CXXRecordDecl>(D);
582 if (!CxxRD) {
583 if (!Members.empty())
584 I.Members = allocateArray<MemberTypeInfo>(Members, TransientArena);
585 return;
586 }
587 for (Decl *CxxDecl : CxxRD->decls()) {
588 auto *VD = dyn_cast<VarDecl>(CxxDecl);
589 if (!VD ||
590 !shouldSerializeInfo(PublicOnly, /*IsInAnonymousNamespace=*/false, VD))
591 continue;
592
593 if (VD->isStaticDataMember())
594 populateMemberTypeInfo(Members, Access, VD, /*IsStatic=*/true);
595 }
596 if (!Members.empty())
597 I.Members = allocateArray<MemberTypeInfo>(Members, TransientArena);
598}
599
600void Serializer::parseEnumerators(EnumInfo &I, const EnumDecl *D) {
601 llvm::SmallVector<EnumValueInfo, 4> LocalMembers;
602 for (const EnumConstantDecl *E : D->enumerators()) {
603 std::string ValueExpr;
604 if (const Expr *InitExpr = E->getInitExpr())
605 ValueExpr = getSourceCode(D, InitExpr->getSourceRange());
606 SmallString<16> ValueStr;
607 E->getInitVal().toString(ValueStr);
608 EnumValueInfo &Member = LocalMembers.emplace_back(
609 E->getNameAsString(), ValueStr.str(), ValueExpr);
610 ASTContext &Context = E->getASTContext();
611 if (RawComment *Comment =
612 E->getASTContext().getRawCommentForDeclNoCache(E)) {
613 Comment->setAttached();
614 if (comments::FullComment *Fc = Comment->parse(Context, nullptr, E)) {
616 Member.Description.push_back(*NewCI);
617 parseFullComment(Fc, *NewCI->Ptr);
618 }
619 }
620 }
621 if (!LocalMembers.empty())
622 I.Members = allocateArray<EnumValueInfo>(LocalMembers, TransientArena);
623}
624
625void Serializer::parseParameters(FunctionInfo &I, const FunctionDecl *D) {
626 llvm::SmallVector<FieldTypeInfo, 4> LocalParams;
627 auto &LO = D->getLangOpts();
628 for (const ParmVarDecl *P : D->parameters()) {
629 FieldTypeInfo &FieldInfo = LocalParams.emplace_back(
630 getTypeInfoForType(P->getOriginalType(), LO), P->getNameAsString());
631 if (std::optional<StringRef> DefaultValue =
632 getSourceCode(D, P->getDefaultArgRange()))
633 FieldInfo.DefaultValue = *DefaultValue;
634 }
635 if (!LocalParams.empty())
636 I.Params = allocateArray<FieldTypeInfo>(LocalParams, TransientArena);
637}
638
639// TODO: Remove the serialization of Parents and VirtualParents, this
640// information is also extracted in the other definition of parseBases.
641void Serializer::parseBases(RecordInfo &I, const CXXRecordDecl *D) {
642 // Don't parse bases if this isn't a definition.
643 if (!D->isThisDeclarationADefinition())
644 return;
645
646 llvm::SmallVector<Reference, 4> LocalParents;
647 for (const CXXBaseSpecifier &B : D->bases()) {
648 if (B.isVirtual())
649 continue;
650 if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
651 const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
652 LocalParents.emplace_back(getUSRForDecl(D), B.getType().getAsString(),
653 InfoType::IT_record, B.getType().getAsString());
654 } else if (const RecordDecl *P = getRecordDeclForType(B.getType()))
655 LocalParents.emplace_back(
656 getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record,
657 P->getQualifiedNameAsString(), internString(getInfoRelativePath(P)));
658 else
659 LocalParents.emplace_back(SymbolID(), B.getType().getAsString());
660 }
661 if (!LocalParents.empty())
662 I.Parents = allocateArray<Reference>(LocalParents, TransientArena);
663
664 llvm::SmallVector<Reference, 4> LocalVirtualParents;
665 for (const CXXBaseSpecifier &B : D->vbases()) {
666 if (const RecordDecl *P = getRecordDeclForType(B.getType()))
667 LocalVirtualParents.emplace_back(
668 getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record,
669 P->getQualifiedNameAsString(), internString(getInfoRelativePath(P)));
670 else
671 LocalVirtualParents.emplace_back(SymbolID(), B.getType().getAsString());
672 }
673 if (!LocalVirtualParents.empty())
674 I.VirtualParents =
675 allocateArray<Reference>(LocalVirtualParents, TransientArena);
676}
677
678template <typename T>
679void Serializer::populateParentNamespaces(
680 llvm::SmallVector<Reference, 4> &Namespaces, const T *D,
681 bool &IsInAnonymousNamespace) {
682 const DeclContext *DC = D->getDeclContext();
683 do {
684 if (const auto *N = dyn_cast<NamespaceDecl>(DC)) {
685 std::string Namespace;
686 if (N->isAnonymousNamespace()) {
687 Namespace = "@nonymous_namespace";
688 IsInAnonymousNamespace = true;
689 } else
690 Namespace = N->getNameAsString();
691 Namespaces.emplace_back(getUSRForDecl(N), Namespace,
693 N->getQualifiedNameAsString());
694 } else if (const auto *N = dyn_cast<RecordDecl>(DC))
695 Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
697 N->getQualifiedNameAsString());
698 else if (const auto *N = dyn_cast<FunctionDecl>(DC))
699 Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
701 N->getQualifiedNameAsString());
702 else if (const auto *N = dyn_cast<EnumDecl>(DC))
703 Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
704 InfoType::IT_enum, N->getQualifiedNameAsString());
705 } while ((DC = DC->getParent()));
706 // The global namespace should be added to the list of namespaces if the decl
707 // corresponds to a Record and if it doesn't have any namespace (because this
708 // means it's in the global namespace). Also if its outermost namespace is a
709 // record because that record matches the previous condition mentioned.
710 if ((Namespaces.empty() && isa<RecordDecl>(D)) ||
711 (!Namespaces.empty() && Namespaces.back().RefType == InfoType::IT_record))
712 Namespaces.emplace_back(SymbolID(), "GlobalNamespace",
714}
715
716void Serializer::populateTemplateParameters(
717 std::optional<TemplateInfo> &TemplateInfo, const clang::Decl *D) {
718 if (const TemplateParameterList *ParamList =
719 D->getDescribedTemplateParams()) {
720 if (!TemplateInfo) {
721 TemplateInfo.emplace();
722 }
723 llvm::SmallVector<TemplateParamInfo, 4> LocalParams;
724 for (const NamedDecl *ND : *ParamList) {
725 LocalParams.emplace_back(getSourceCode(ND, ND->getSourceRange()));
726 }
727 if (!LocalParams.empty())
728 TemplateInfo->Params =
730 }
731}
732
733TemplateParamInfo
734Serializer::convertTemplateArgToInfo(const clang::Decl *D,
735 const TemplateArgument &Arg) {
736 // The TemplateArgument's pretty printing handles all the normal cases
737 // well enough for our requirements.
738 std::string Str;
739 llvm::raw_string_ostream Stream(Str);
740 Arg.print(PrintingPolicy(D->getLangOpts()), Stream, false);
741 return TemplateParamInfo(Str);
742}
743
744// Check if the DeclKind is one for which we support contextual relationships.
745// There might be other ContextDecls, like blocks, that we currently don't
746// handle at all.
747bool Serializer::isSupportedContext(Decl::Kind DeclKind) {
748 switch (DeclKind) {
749 case Decl::Kind::Record:
750 case Decl::Kind::CXXRecord:
751 case Decl::Kind::ClassTemplateSpecialization:
752 case Decl::Kind::ClassTemplatePartialSpecialization:
753 case Decl::Kind::Namespace:
754 return true;
755 default:
756 return false;
757 }
758}
759
760void Serializer::findParent(Info &I, const Decl *D) {
761 assert(D && "Invalid Decl");
762
763 // Only walk up contexts if D is a record or namespace.
764 if (!isSupportedContext(D->getKind()))
765 return;
766
767 const DeclContext *ParentCtx = dyn_cast<DeclContext>(D)->getLexicalParent();
768 while (ParentCtx) {
769 if (isSupportedContext(ParentCtx->getDeclKind())) {
770 // Break when we reach the first record or namespace.
771 I.ParentUSR = getUSRForDecl(dyn_cast<Decl>(ParentCtx));
772 break;
773 }
774 ParentCtx = ParentCtx->getParent();
775 }
776}
777
778template <typename T>
779void Serializer::populateInfo(Info &I, const T *D, const FullComment *C,
780 bool &IsInAnonymousNamespace) {
781 I.USR = getUSRForDecl(D);
782 findParent(I, D);
783
784 if (auto ConversionDecl = dyn_cast_or_null<CXXConversionDecl>(D);
785 ConversionDecl && ConversionDecl->getConversionType()
786 .getTypePtr()
787 ->isTemplateTypeParmType())
788 I.Name = internString("operator " +
789 ConversionDecl->getConversionType().getAsString());
790 else
791 I.Name = internString(D->getNameAsString());
792 llvm::SmallVector<Reference, 4> LocalNamespaces;
793 populateParentNamespaces(LocalNamespaces, D, IsInAnonymousNamespace);
794 if (!LocalNamespaces.empty())
795 I.Namespace = allocateArray<Reference>(LocalNamespaces, TransientArena);
796 if (C) {
797
799 I.Description.push_back(*NewCI);
800 parseFullComment(C, *NewCI->Ptr);
801 }
802}
803
804template <typename T>
805void Serializer::populateSymbolInfo(SymbolInfo &I, const T *D,
806 const FullComment *C, Location Loc,
807 bool &IsInAnonymousNamespace) {
808 populateInfo(I, D, C, IsInAnonymousNamespace);
809 if (D->isThisDeclarationADefinition())
810 I.DefLoc = Loc;
811 else {
812 I.Loc.push_back(*allocateListNodeTransient<Location>(Loc));
813 }
814
815 auto *Mangler = ItaniumMangleContext::create(
816 D->getASTContext(), D->getASTContext().getDiagnostics());
817 std::string MangledName;
818 llvm::raw_string_ostream MangledStream(MangledName);
819 if (auto *CXXD = dyn_cast<CXXRecordDecl>(D))
820 Mangler->mangleCXXVTable(CXXD, MangledStream);
821 else
822 MangledStream << D->getNameAsString();
823 // A 250 length limit was chosen since 255 is a common limit across
824 // different filesystems, with a 5 character buffer for file extensions.
825 if (MangledName.size() > 250) {
826 auto SymbolID = llvm::toStringRef(llvm::toHex(I.USR)).str();
827 I.MangledName =
828 internString(MangledName.substr(0, 250 - SymbolID.size()) + SymbolID);
829 } else
830 I.MangledName = internString(MangledName);
831 delete Mangler;
832}
833
834void Serializer::handleCompoundConstraints(
835 const Expr *Constraint,
836 llvm::SmallVectorImpl<ConstraintInfo> &ConstraintInfos) {
837 if (Constraint->getStmtClass() == Stmt::ParenExprClass) {
838 handleCompoundConstraints(dyn_cast<ParenExpr>(Constraint)->getSubExpr(),
839 ConstraintInfos);
840 } else if (Constraint->getStmtClass() == Stmt::BinaryOperatorClass) {
841 auto *BinaryOpExpr = dyn_cast<BinaryOperator>(Constraint);
842 handleCompoundConstraints(BinaryOpExpr->getLHS(), ConstraintInfos);
843 handleCompoundConstraints(BinaryOpExpr->getRHS(), ConstraintInfos);
844 } else if (Constraint->getStmtClass() ==
845 Stmt::ConceptSpecializationExprClass) {
846 auto *Concept = dyn_cast<ConceptSpecializationExpr>(Constraint);
847 ConstraintInfo CI(getUSRForDecl(Concept->getNamedConcept()),
848 Concept->getNamedConcept()->getNameAsString());
849 CI.ConstraintExpr = internString(exprToString(Concept));
850 ConstraintInfos.push_back(CI);
851 }
852}
853
854void Serializer::populateConstraints(TemplateInfo &I, const TemplateDecl *D) {
855 if (!D || !D->hasAssociatedConstraints())
856 return;
857
858 SmallVector<AssociatedConstraint> AssociatedConstraints;
859 D->getAssociatedConstraints(AssociatedConstraints);
860 SmallVector<ConstraintInfo, 4> LocalConstraints;
861 for (const auto &Constraint : AssociatedConstraints) {
862 if (!Constraint)
863 continue;
864
865 // TODO: Investigate if atomic constraints need to be handled specifically.
866 if (const auto *ConstraintExpr =
867 dyn_cast_or_null<ConceptSpecializationExpr>(
868 Constraint.ConstraintExpr)) {
869 ConstraintInfo CI(getUSRForDecl(ConstraintExpr->getNamedConcept()),
870 ConstraintExpr->getNamedConcept()->getNameAsString());
871 CI.ConstraintExpr = internString(exprToString(ConstraintExpr));
872 LocalConstraints.push_back(std::move(CI));
873 } else {
874 handleCompoundConstraints(Constraint.ConstraintExpr, LocalConstraints);
875 }
876 }
877 if (!LocalConstraints.empty())
878 I.Constraints =
880}
881
882void Serializer::populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
883 const FullComment *FC, Location Loc,
884 bool &IsInAnonymousNamespace) {
885 populateSymbolInfo(I, D, FC, Loc, IsInAnonymousNamespace);
886 auto &LO = D->getLangOpts();
887 I.ReturnType = getTypeInfoForType(D->getReturnType(), LO);
888 I.Prototype = getFunctionPrototype(D);
889 parseParameters(I, D);
890 I.IsStatic = D->isStatic();
891
892 populateTemplateParameters(I.Template, D);
893 if (I.Template)
894 populateConstraints(I.Template.value(), D->getDescribedFunctionTemplate());
895
896 // Handle function template specializations.
897 if (const FunctionTemplateSpecializationInfo *FTSI =
898 D->getTemplateSpecializationInfo()) {
899 if (!I.Template)
900 I.Template.emplace();
901 I.Template->Specialization.emplace();
902 auto &Specialization = *I.Template->Specialization;
903
904 Specialization.SpecializationOf = getUSRForDecl(FTSI->getTemplate());
905
906 // Template parameters to the specialization.
907 if (FTSI->TemplateArguments) {
908 SmallVector<TemplateParamInfo, 4> LocalParams;
909 for (const TemplateArgument &Arg : FTSI->TemplateArguments->asArray()) {
910 LocalParams.push_back(convertTemplateArgToInfo(D, Arg));
911 }
912 if (!LocalParams.empty())
913 Specialization.Params =
915 }
916 }
917}
918
919// TODO: Rename this, since this doesn't populate anything besides comments and
920// isn't exclusive to members
921template <typename T>
922void Serializer::populateMemberTypeInfo(T &I, const Decl *D) {
923 assert(D && "Expect non-null FieldDecl in populateMemberTypeInfo");
924
925 ASTContext &Context = D->getASTContext();
926 // TODO investigate whether we can use ASTContext::getCommentForDecl instead
927 // of this logic. See also similar code in Mapper.cpp.
928 RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
929 if (!Comment)
930 return;
931
932 Comment->setAttached();
933 if (comments::FullComment *Fc = Comment->parse(Context, nullptr, D)) {
935 I.Description.push_back(*NewCI);
936 parseFullComment(Fc, *NewCI->Ptr);
937 }
938}
939
940void Serializer::populateMemberTypeInfo(
941 SmallVectorImpl<MemberTypeInfo> &Members, AccessSpecifier &Access,
942 const DeclaratorDecl *D, bool IsStatic) {
943 // Use getAccessUnsafe so that we just get the default AS_none if it's not
944 // valid, as opposed to an assert.
945 MemberTypeInfo &NewMember = Members.emplace_back(
946 getTypeInfoForType(D->getTypeSourceInfo()->getType(), D->getLangOpts()),
947 D->getNameAsString(),
948 getFinalAccessSpecifier(Access, D->getAccessUnsafe()), IsStatic);
949 populateMemberTypeInfo(NewMember, D);
950}
951
952void Serializer::parseBases(llvm::SmallVectorImpl<BaseRecordInfo> &Bases,
953 const CXXRecordDecl *D, bool IsFileInRootDir,
954 bool PublicOnly, bool IsParent,
955 AccessSpecifier ParentAccess) {
956 // Don't parse bases if this isn't a definition.
957 if (!D->isThisDeclarationADefinition())
958 return;
959 for (const CXXBaseSpecifier &B : D->bases()) {
960 if (const auto *Base = B.getType()->getAsCXXRecordDecl()) {
961 if (Base->isCompleteDefinition()) {
962 // Initialized without USR and name, this will be set in the following
963 // if-else stmt.
964 BaseRecordInfo BI(
965 {}, "", internString(getInfoRelativePath(Base)), B.isVirtual(),
966 getFinalAccessSpecifier(ParentAccess, B.getAccessSpecifier()),
967 IsParent);
968 if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
969 const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
970 BI.USR = getUSRForDecl(D);
971 BI.Name = internString(B.getType().getAsString());
972 } else {
973 BI.USR = getUSRForDecl(Base);
974 BI.Name = internString(Base->getNameAsString());
975 }
976 parseFields(BI, Base, PublicOnly, BI.Access);
977 for (const auto &Decl : Base->decls())
978 if (const auto *MD = dyn_cast<CXXMethodDecl>(Decl)) {
979 // Don't serialize private methods
980 if (MD->getAccessUnsafe() == AccessSpecifier::AS_private ||
981 !MD->isUserProvided())
982 continue;
983 FunctionInfo FI;
984 FI.IsMethod = true;
985 FI.IsStatic = MD->isStatic();
986 // The seventh arg in populateFunctionInfo is a boolean passed by
987 // reference, its value is not relevant in here so it's not used
988 // anywhere besides the function call.
989 bool IsInAnonymousNamespace;
990 populateFunctionInfo(FI, MD, /*FullComment=*/{}, /*Location=*/{},
991 IsInAnonymousNamespace);
992 FI.Access =
993 getFinalAccessSpecifier(BI.Access, MD->getAccessUnsafe());
994 FunctionInfo *FIPtr = allocatePtr<FunctionInfo>(std::move(FI));
995 BI.Children.Functions.push_back(
996 *allocatePtr<InfoNode<FunctionInfo>>(FIPtr));
997 }
998 Bases.emplace_back(std::move(BI));
999 // Call this function recursively to get the inherited classes of
1000 // this base; these new bases will also get stored in the original
1001 // RecordInfo: I.
1002 parseBases(Bases, Base, IsFileInRootDir, PublicOnly, false,
1003 Bases.back().Access);
1004 }
1005 }
1006 }
1007}
1008
1009std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
1010Serializer::emitInfo(const NamespaceDecl *D, const FullComment *FC,
1011 Location Loc, bool PublicOnly) {
1012 auto NSI = allocatePtr<NamespaceInfo>();
1013 bool IsInAnonymousNamespace = false;
1014 populateInfo(*NSI, D, FC, IsInAnonymousNamespace);
1015 if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
1016 return {};
1017
1018 NSI->Name = D->isAnonymousNamespace() ? "@nonymous_namespace" : NSI->Name;
1019 NSI->Path = getInfoRelativePath(NSI->Namespace);
1020 if (NSI->Namespace.empty() && NSI->USR == SymbolID())
1021 return {OwnedPtr<Info>{std::move(NSI)}, nullptr};
1022
1023 // Namespaces are inserted into the parent by reference, so we need to return
1024 // both the parent and the record itself.
1025 return {std::move(NSI), makeAndInsertIntoParent<const NamespaceInfo &>(*NSI)};
1026}
1027
1028void Serializer::parseFriends(RecordInfo &RI, const CXXRecordDecl *D) {
1029 if (!D->hasDefinition() || !D->hasFriends())
1030 return;
1031
1032 llvm::SmallVector<FriendInfo, 4> LocalFriends;
1033
1034 for (const FriendDecl *FD : D->friends()) {
1035 if (FD->isUnsupportedFriend())
1036 continue;
1037
1038 FriendInfo F(InfoType::IT_friend, getUSRForDecl(FD));
1039 const auto *ActualDecl = FD->getFriendDecl();
1040 if (!ActualDecl) {
1041 const auto *FriendTypeInfo = FD->getFriendType();
1042 if (!FriendTypeInfo)
1043 continue;
1044 ActualDecl = FriendTypeInfo->getType()->getAsCXXRecordDecl();
1045
1046 if (!ActualDecl)
1047 continue;
1048 F.IsClass = true;
1049 }
1050
1051 if (const auto *ActualTD = dyn_cast_or_null<TemplateDecl>(ActualDecl)) {
1052 if (isa<RecordDecl>(ActualTD->getTemplatedDecl()))
1053 F.IsClass = true;
1054 F.Template.emplace();
1055 llvm::SmallVector<TemplateParamInfo, 4> LocalParams;
1056 for (const auto *Param : ActualTD->getTemplateParameters()->asArray())
1057 LocalParams.emplace_back(getSourceCode(Param, Param->getSourceRange()));
1058 if (!LocalParams.empty())
1059 F.Template->Params =
1061 ActualDecl = ActualTD->getTemplatedDecl();
1062 }
1063
1064 if (auto *FuncDecl = dyn_cast_or_null<FunctionDecl>(ActualDecl)) {
1065 FunctionInfo TempInfo;
1066 parseParameters(TempInfo, FuncDecl);
1067 F.Params = allocateArray<FieldTypeInfo>(TempInfo.Params, TransientArena);
1068 F.ReturnType = getTypeInfoForType(FuncDecl->getReturnType(),
1069 FuncDecl->getLangOpts());
1070 }
1071
1072 F.Ref =
1073 Reference(getUSRForDecl(ActualDecl), ActualDecl->getNameAsString(),
1074 InfoType::IT_default, ActualDecl->getQualifiedNameAsString(),
1075 getInfoRelativePath(ActualDecl));
1076
1077 populateMemberTypeInfo(F, ActualDecl);
1078 LocalFriends.push_back(std::move(F));
1079 }
1080 if (!LocalFriends.empty())
1082}
1083
1084std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
1085Serializer::emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
1086 bool PublicOnly) {
1087
1088 auto RI = allocatePtr<RecordInfo>();
1089 bool IsInAnonymousNamespace = false;
1090
1091 populateSymbolInfo(*RI, D, FC, Loc, IsInAnonymousNamespace);
1092 if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
1093 return {};
1094
1095 RI->TagType = D->getTagKind();
1096 parseFields(*RI, D, PublicOnly);
1097
1098 if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
1099 if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl()) {
1100 RI->Name = internString(TD->getNameAsString());
1101 RI->IsTypeDef = true;
1102 }
1103 // TODO: remove first call to parseBases, that function should be deleted
1104 parseBases(*RI, C);
1105 llvm::SmallVector<BaseRecordInfo, 4> LocalBases;
1106 parseBases(LocalBases, C, /*IsFileInRootDir=*/true, PublicOnly,
1107 /*IsParent=*/true);
1108 if (!LocalBases.empty())
1110 parseFriends(*RI, C);
1111 }
1112 RI->Path = internString(getInfoRelativePath(RI->Namespace));
1113
1114 populateTemplateParameters(RI->Template, D);
1115 if (RI->Template)
1116 populateConstraints(RI->Template.value(), D->getDescribedTemplate());
1117
1118 // Full and partial specializations.
1119 if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
1120 if (!RI->Template)
1121 RI->Template.emplace();
1122 RI->Template->Specialization.emplace();
1123 auto &Specialization = *RI->Template->Specialization;
1124
1125 // What this is a specialization of.
1126 auto SpecOf = CTSD->getSpecializedTemplateOrPartial();
1127 if (auto *SpecTD = dyn_cast<ClassTemplateDecl *>(SpecOf))
1128 Specialization.SpecializationOf = getUSRForDecl(SpecTD);
1129 else if (auto *SpecTD =
1130 dyn_cast<ClassTemplatePartialSpecializationDecl *>(SpecOf))
1131 Specialization.SpecializationOf = getUSRForDecl(SpecTD);
1132
1133 // Parameters to the specialization. For partial specializations, get the
1134 // parameters "as written" from the ClassTemplatePartialSpecializationDecl
1135 // because the non-explicit template parameters will have generated internal
1136 // placeholder names rather than the names the user typed that match the
1137 // template parameters.
1138 if (const ClassTemplatePartialSpecializationDecl *CTPSD =
1139 dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
1140 if (const ASTTemplateArgumentListInfo *AsWritten =
1141 CTPSD->getTemplateArgsAsWritten()) {
1142 llvm::SmallVector<TemplateParamInfo, 4> LocalParams;
1143 for (unsigned Idx = 0; Idx < AsWritten->getNumTemplateArgs(); Idx++) {
1144 LocalParams.emplace_back(
1145 getSourceCode(D, (*AsWritten)[Idx].getSourceRange()));
1146 }
1147 if (!LocalParams.empty())
1148 Specialization.Params =
1150 }
1151 } else {
1152 llvm::SmallVector<TemplateParamInfo, 4> LocalParams;
1153 for (const TemplateArgument &Arg : CTSD->getTemplateArgs().asArray()) {
1154 LocalParams.push_back(convertTemplateArgToInfo(D, Arg));
1155 }
1156 if (!LocalParams.empty())
1157 Specialization.Params =
1159 }
1160 }
1161
1162 // Records are inserted into the parent by reference, so we need to return
1163 // both the parent and the record itself.
1164 auto Parent = makeAndInsertIntoParent<const RecordInfo &>(*RI);
1165 return {std::move(RI), std::move(Parent)};
1166}
1167
1168std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
1169Serializer::emitInfo(const FunctionDecl *D, const FullComment *FC, Location Loc,
1170 bool PublicOnly) {
1172 bool IsInAnonymousNamespace = false;
1173 populateFunctionInfo(*Func, D, FC, Loc, IsInAnonymousNamespace);
1174 Func->Access = clang::AccessSpecifier::AS_none;
1175 if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
1176 return {};
1177
1178 // Info is wrapped in its parent scope so is returned in the second position.
1179 return {nullptr, makeAndInsertIntoParent(*Func)};
1180}
1181
1182std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
1183Serializer::emitInfo(const CXXMethodDecl *D, const FullComment *FC,
1184 Location Loc, bool PublicOnly) {
1186 bool IsInAnonymousNamespace = false;
1187 populateFunctionInfo(*Func, D, FC, Loc, IsInAnonymousNamespace);
1188 if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
1189 return {};
1190
1191 Func->IsMethod = true;
1192 Func->IsStatic = D->isStatic();
1193
1194 const NamedDecl *Parent = nullptr;
1195 if (const auto *SD =
1196 dyn_cast<ClassTemplateSpecializationDecl>(D->getParent()))
1197 Parent = SD->getSpecializedTemplate();
1198 else
1199 Parent = D->getParent();
1200
1201 SymbolID ParentUSR = getUSRForDecl(Parent);
1202 Func->Parent =
1203 Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record,
1204 Parent->getQualifiedNameAsString()};
1205 Func->Access = D->getAccess();
1206
1207 // Info is wrapped in its parent scope so is returned in the second position.
1208 return {nullptr, makeAndInsertIntoParent(*Func)};
1209}
1210
1211void Serializer::extractCommentFromDecl(const Decl *D, TypedefInfo &Info) {
1212 assert(D && "Invalid Decl when extracting comment");
1213 ASTContext &Context = D->getASTContext();
1214 RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
1215 if (!Comment)
1216 return;
1217
1218 Comment->setAttached();
1219 if (comments::FullComment *Fc = Comment->parse(Context, nullptr, D)) {
1221 Info.Description.push_back(*NewCI);
1222 parseFullComment(Fc, *NewCI->Ptr);
1223 }
1224}
1225
1226std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
1227Serializer::emitInfo(const TypedefDecl *D, const FullComment *FC, Location Loc,
1228 bool PublicOnly) {
1230 bool IsInAnonymousNamespace = false;
1231 populateInfo(*Info, D, FC, IsInAnonymousNamespace);
1232
1233 if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
1234 return {};
1235
1236 Info->DefLoc = Loc;
1237 auto &LO = D->getLangOpts();
1238 Info->Underlying = getTypeInfoForType(D->getUnderlyingType(), LO);
1239 populateTemplateParameters(Info->Template, D);
1240 if (Info->Template)
1241 populateConstraints(Info->Template.value(), D->getDescribedTemplate());
1242
1243 if (Info->Underlying.Type.Name.empty()) {
1244 // Typedef for an unnamed type. This is like "typedef struct { } Foo;"
1245 // The record serializer explicitly checks for this syntax and constructs
1246 // a record with that name, so we don't want to emit a duplicate here.
1247 return {};
1248 }
1249 Info->IsUsing = false;
1250 extractCommentFromDecl(D, *Info);
1251
1252 // Info is wrapped in its parent scope so is returned in the second position.
1253 return {nullptr, makeAndInsertIntoParent(*Info)};
1254}
1255
1256// A type alias is a C++ "using" declaration for a type. It gets mapped to a
1257// TypedefInfo with the IsUsing flag set.
1258std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
1259Serializer::emitInfo(const TypeAliasDecl *D, const FullComment *FC,
1260 Location Loc, bool PublicOnly) {
1262 bool IsInAnonymousNamespace = false;
1263 populateInfo(*Info, D, FC, IsInAnonymousNamespace);
1264 if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
1265 return {};
1266
1267 Info->DefLoc = Loc;
1268 const LangOptions &LO = D->getLangOpts();
1269 Info->Underlying = getTypeInfoForType(D->getUnderlyingType(), LO);
1270 Info->TypeDeclaration = getTypeAlias(D);
1271 Info->IsUsing = true;
1272 populateTemplateParameters(Info->Template, D);
1273 if (Info->Template)
1274 populateConstraints(Info->Template.value(), D->getDescribedAliasTemplate());
1275
1276 extractCommentFromDecl(D, *Info);
1277
1278 // Info is wrapped in its parent scope so is returned in the second position.
1279 return {nullptr, makeAndInsertIntoParent(*Info)};
1280}
1281
1282std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
1283Serializer::emitInfo(const EnumDecl *D, const FullComment *FC, Location Loc,
1284 bool PublicOnly) {
1286 bool IsInAnonymousNamespace = false;
1287 populateSymbolInfo(*Enum, D, FC, Loc, IsInAnonymousNamespace);
1288
1289 if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
1290 return {};
1291
1292 Enum->Scoped = D->isScoped();
1293 if (const TypeSourceInfo *TSI = D->getIntegerTypeSourceInfo()) {
1294 auto Name = TSI->getType().getAsString();
1295 Enum->BaseType = TypeInfo(Name, Name);
1296 }
1297 parseEnumerators(*Enum, D);
1298
1299 // Info is wrapped in its parent scope so is returned in the second position.
1300 return {nullptr, makeAndInsertIntoParent(*Enum)};
1301}
1302
1303std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
1304Serializer::emitInfo(const ConceptDecl *D, const FullComment *FC,
1305 const Location &Loc, bool PublicOnly) {
1307
1308 bool IsInAnonymousNamespace = false;
1309 populateInfo(*Concept, D, FC, IsInAnonymousNamespace);
1310 Concept->IsType = D->isTypeConcept();
1311 Concept->DefLoc = Loc;
1312 Concept->ConstraintExpression = exprToString(D->getConstraintExpr());
1313
1314 if (auto *ConceptParams = D->getTemplateParameters()) {
1315 llvm::SmallVector<TemplateParamInfo, 4> LocalParams;
1316 for (const auto *Param : ConceptParams->asArray()) {
1317 LocalParams.emplace_back(getSourceCode(Param, Param->getSourceRange()));
1318 }
1319 if (!LocalParams.empty())
1320 Concept->Template.Params =
1322 }
1323
1324 if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
1325 return {};
1326
1327 return {nullptr, makeAndInsertIntoParent(*Concept)};
1328}
1329
1330std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
1331Serializer::emitInfo(const VarDecl *D, const FullComment *FC,
1332 const Location &Loc, bool PublicOnly) {
1334 bool IsInAnonymousNamespace = false;
1335 populateSymbolInfo(*Var, D, FC, Loc, IsInAnonymousNamespace);
1336 if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
1337 return {};
1338
1339 if (D->getStorageClass() == StorageClass::SC_Static)
1340 Var->IsStatic = true;
1341 Var->Type =
1342 getTypeInfoForType(D->getType(), D->getASTContext().getPrintingPolicy());
1343
1344 if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
1345 return {};
1346
1347 return {nullptr, makeAndInsertIntoParent(*Var)};
1348}
1349
1350} // namespace serialize
1351} // namespace doc
1352} // namespace clang
static llvm::cl::opt< bool > PublicOnly("public", llvm::cl::desc("Document only public declarations."), llvm::cl::init(false), llvm::cl::cat(ClangDocCategory))
clang::find_all_symbols::SymbolInfo SymbolInfo
void emitBlock(const NamespaceInfo &I)
void visitHTMLEndTagComment(const HTMLEndTagComment *C)
void visitVerbatimLineComment(const VerbatimLineComment *C)
void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C)
void visitHTMLStartTagComment(const HTMLStartTagComment *C)
void visitTParamCommandComment(const TParamCommandComment *C)
void visitVerbatimBlockComment(const VerbatimBlockComment *C)
void visitParamCommandComment(const ParamCommandComment *C)
void visitInlineCommandComment(const InlineCommandComment *C)
void parseComment(const comments::Comment *C)
void visitTextComment(const TextComment *C)
void visitBlockCommandComment(const BlockCommandComment *C)
std::pair< OwnedPtr< Info >, OwnedPtr< Info > > emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc, bool PublicOnly)
@ Info
An information message.
Definition Protocol.h:755
std::string Path
A typedef to represent a file path.
Definition Path.h:26
@ Alias
This declaration is an alias that was referred to.
Definition FindTarget.h:112
static std::string serialize(T &I, DiagnosticsEngine &Diags)
SymbolID hashUSR(llvm::StringRef USR)
Definition Serialize.cpp:40
T * getPtr(const OwnedPtr< T > &O)
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for MD output.")
CommentKind stringToCommentKind(llvm::StringRef KindStr)
thread_local llvm::BumpPtrAllocator TransientArena
StringRef internString(const Twine &T)
llvm::ArrayRef< T > allocateArray(llvm::SmallVectorImpl< T > &V, llvm::BumpPtrAllocator &Alloc)
InfoNode< T > * allocateListNodeTransient(Args &&...args)
OwnedPtr< T > allocatePtr(Args &&...args)
std::array< uint8_t, 20 > SymbolID
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccessCheck P
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
A base struct for Infos.
DocList< CommentInfo > Description
llvm::ArrayRef< Reference > Namespace
llvm::ArrayRef< BaseRecordInfo > Bases
llvm::ArrayRef< FriendInfo > Friends
std::optional< TemplateInfo > Template
static constexpr const char FuncDecl[]