88
99#include " Serialize.h"
1010#include " BitcodeWriter.h"
11+ #include " clang/AST/Attr.h"
1112#include " clang/AST/Comment.h"
1213#include " clang/Index/USRGeneration.h"
1314#include " clang/Lex/Lexer.h"
14- #include " llvm/ADT/Hashing.h"
1515#include " llvm/ADT/StringExtras.h"
1616#include " llvm/Support/SHA1.h"
1717
@@ -35,6 +35,188 @@ static void populateMemberTypeInfo(RecordInfo &I, AccessSpecifier &Access,
3535 const DeclaratorDecl *D,
3636 bool IsStatic = false );
3737
38+ void getTemplateParameters (const TemplateParameterList *TemplateParams,
39+ llvm::raw_ostream &Stream) {
40+ Stream << " template <" ;
41+
42+ for (unsigned i = 0 ; i < TemplateParams->size (); ++i) {
43+ if (i > 0 ) {
44+ Stream << " , " ;
45+ }
46+
47+ const NamedDecl *Param = TemplateParams->getParam (i);
48+ if (const auto *TTP = llvm::dyn_cast<TemplateTypeParmDecl>(Param)) {
49+ if (TTP->wasDeclaredWithTypename ()) {
50+ Stream << " typename" ;
51+ } else {
52+ Stream << " class" ;
53+ }
54+ if (TTP->isParameterPack ()) {
55+ Stream << " ..." ;
56+ }
57+ Stream << " " << TTP->getNameAsString ();
58+ } else if (const auto *NTTP =
59+ llvm::dyn_cast<NonTypeTemplateParmDecl>(Param)) {
60+ NTTP->getType ().print (Stream, NTTP->getASTContext ().getPrintingPolicy ());
61+ if (NTTP->isParameterPack ()) {
62+ Stream << " ..." ;
63+ }
64+ Stream << " " << NTTP->getNameAsString ();
65+ } else if (const auto *TTPD =
66+ llvm::dyn_cast<TemplateTemplateParmDecl>(Param)) {
67+ Stream << " template <" ;
68+ getTemplateParameters (TTPD->getTemplateParameters (), Stream);
69+ Stream << " > class " << TTPD->getNameAsString ();
70+ }
71+ }
72+
73+ Stream << " > " ;
74+ }
75+
76+ // Extract the full function prototype from a FunctionDecl including
77+ // Full Decl
78+ llvm::SmallString<256 > getFunctionPrototype (const FunctionDecl *FuncDecl) {
79+ llvm::SmallString<256 > Result;
80+ llvm::raw_svector_ostream Stream (Result);
81+ const ASTContext &Ctx = FuncDecl->getASTContext ();
82+ const auto *Method = llvm::dyn_cast<CXXMethodDecl>(FuncDecl);
83+ // If it's a templated function, handle the template parameters
84+ if (const auto *TmplDecl = FuncDecl->getDescribedTemplate ()) {
85+ getTemplateParameters (TmplDecl->getTemplateParameters (), Stream);
86+ }
87+ // If it's a virtual method
88+ if (Method) {
89+ if (Method->isVirtual ()) {
90+ Stream << " virtual " ;
91+ }
92+ }
93+ // Print return type
94+ FuncDecl->getReturnType ().print (Stream, Ctx.getPrintingPolicy ());
95+
96+ // Print function name
97+ Stream << " " << FuncDecl->getNameAsString () << " (" ;
98+
99+ // Print parameter list with types, names, and default values
100+ for (unsigned I = 0 ; I < FuncDecl->getNumParams (); ++I) {
101+ if (I > 0 ) {
102+ Stream << " , " ;
103+ }
104+ const ParmVarDecl *ParamDecl = FuncDecl->getParamDecl (I);
105+ QualType ParamType = ParamDecl->getType ();
106+ ParamType.print (Stream, Ctx.getPrintingPolicy ());
107+
108+ // Print parameter name if it has one
109+ if (!ParamDecl->getName ().empty ()) {
110+ Stream << " " << ParamDecl->getNameAsString ();
111+ }
112+
113+ // Print default argument if it exists
114+ if (ParamDecl->hasDefaultArg ()) {
115+ const Expr *DefaultArg = ParamDecl->getDefaultArg ();
116+ if (DefaultArg) {
117+ Stream << " = " ;
118+ DefaultArg->printPretty (Stream, nullptr , Ctx.getPrintingPolicy ());
119+ }
120+ }
121+ }
122+
123+ // If it is a variadic function, add '...'
124+ if (FuncDecl->isVariadic ()) {
125+ if (FuncDecl->getNumParams () > 0 ) {
126+ Stream << " , " ;
127+ }
128+ Stream << " ..." ;
129+ }
130+
131+ Stream << " )" ;
132+
133+ // If it's a const method, add 'const' qualifier
134+ if (Method) {
135+ if (Method->size_overridden_methods ())
136+ Stream << " override" ;
137+ if (Method->hasAttr <clang::FinalAttr>())
138+ Stream << " final" ;
139+ if (Method->isConst ())
140+ Stream << " const" ;
141+ if (Method->isPureVirtual ())
142+ Stream << " = 0" ;
143+ }
144+ return Result; // Convert SmallString to std::string for return
145+ }
146+
147+ llvm::SmallString<16 > getTypeDefDecl (const TypedefDecl *TypeDef) {
148+ llvm::SmallString<16 > Result;
149+ llvm::raw_svector_ostream Stream (Result);
150+ const ASTContext &Ctx = TypeDef->getASTContext ();
151+ Stream << " typedef " ;
152+ QualType Q = TypeDef->getUnderlyingType ();
153+ Q.print (Stream, Ctx.getPrintingPolicy ());
154+ Stream << " " << TypeDef->getNameAsString ();
155+ return Result;
156+ }
157+
158+ llvm::SmallString<16 > getTypeAlias (const TypeAliasDecl *Alias) {
159+ llvm::SmallString<16 > Result;
160+ llvm::raw_svector_ostream Stream (Result);
161+ const ASTContext &Ctx = Alias->getASTContext ();
162+ if (const auto *TmplDecl = Alias->getDescribedTemplate ()) {
163+ getTemplateParameters (TmplDecl->getTemplateParameters (), Stream);
164+ }
165+ Stream << " using " << Alias->getNameAsString () << " = " ;
166+ QualType Q = Alias->getUnderlyingType ();
167+ Q.print (Stream, Ctx.getPrintingPolicy ());
168+
169+ return Result;
170+ }
171+
172+ // extract full syntax for record declaration
173+ llvm::SmallString<16 > getRecordPrototype (const CXXRecordDecl *CXXRD) {
174+ llvm::SmallString<16 > Result;
175+ LangOptions LangOpts;
176+ PrintingPolicy Policy (LangOpts);
177+ Policy.SuppressTagKeyword = false ;
178+ Policy.FullyQualifiedName = true ;
179+ Policy.IncludeNewlines = false ;
180+ llvm::raw_svector_ostream OS (Result);
181+ if (const auto *TD = CXXRD->getDescribedClassTemplate ()) {
182+ OS << " template <" ;
183+ bool FirstParam = true ;
184+ for (const auto *Param : *TD->getTemplateParameters ()) {
185+ if (!FirstParam)
186+ OS << " , " ;
187+ Param->print (OS, Policy);
188+ FirstParam = false ;
189+ }
190+ OS << " >\n " ;
191+ }
192+ if (CXXRD->isStruct ()) {
193+ OS << " struct " ;
194+ } else if (CXXRD->isClass ()) {
195+ OS << " class " ;
196+ } else if (CXXRD->isUnion ()) {
197+ OS << " union " ;
198+ }
199+ OS << CXXRD->getNameAsString ();
200+
201+ // We need to make sure we have a good enough declaration to check. In the
202+ // case where the class is a forward declaration, we'll fail assertions in
203+ // DeclCXX.
204+ if (CXXRD->isCompleteDefinition () && CXXRD->getNumBases () > 0 ) {
205+ OS << " : " ;
206+ bool FirstBase = true ;
207+ for (const auto &Base : CXXRD->bases ()) {
208+ if (!FirstBase)
209+ OS << " , " ;
210+ if (Base.isVirtual ())
211+ OS << " virtual " ;
212+ OS << getAccessSpelling (Base.getAccessSpecifier ()) << " " ;
213+ OS << Base.getType ().getAsString (Policy);
214+ FirstBase = false ;
215+ }
216+ }
217+ return Result;
218+ }
219+
38220// A function to extract the appropriate relative path for a given info's
39221// documentation. The path returned is a composite of the parent namespaces.
40222//
@@ -408,7 +590,6 @@ static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
408590 ASTContext &Context = E->getASTContext ();
409591 if (RawComment *Comment =
410592 E->getASTContext ().getRawCommentForDeclNoCache (E)) {
411- CommentInfo CInfo;
412593 Comment->setAttached ();
413594 if (comments::FullComment *Fc = Comment->parse (Context, nullptr , E)) {
414595 EnumValueInfo &Member = I.Members .back ();
@@ -434,6 +615,7 @@ static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
434615 // Don't parse bases if this isn't a definition.
435616 if (!D->isThisDeclarationADefinition ())
436617 return ;
618+
437619 for (const CXXBaseSpecifier &B : D->bases ()) {
438620 if (B.isVirtual ())
439621 continue ;
@@ -549,6 +731,7 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
549731 populateSymbolInfo (I, D, FC, Loc, IsInAnonymousNamespace);
550732 auto &LO = D->getLangOpts ();
551733 I.ReturnType = getTypeInfoForType (D->getReturnType (), LO);
734+ I.ProtoType = getFunctionPrototype (D);
552735 parseParameters (I, D);
553736
554737 populateTemplateParameters (I.Template , D);
@@ -680,15 +863,19 @@ emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc,
680863std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
681864emitInfo (const RecordDecl *D, const FullComment *FC, Location Loc,
682865 bool PublicOnly) {
866+
683867 auto RI = std::make_unique<RecordInfo>();
684868 bool IsInAnonymousNamespace = false ;
869+
685870 populateSymbolInfo (*RI, D, FC, Loc, IsInAnonymousNamespace);
686871 if (!shouldSerializeInfo (PublicOnly, IsInAnonymousNamespace, D))
687872 return {};
688873
689874 RI->TagType = D->getTagKind ();
690875 parseFields (*RI, D, PublicOnly);
876+
691877 if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
878+ RI->FullName = getRecordPrototype (C);
692879 if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl ()) {
693880 RI->Name = TD->getNameAsString ();
694881 RI->IsTypeDef = true ;
@@ -710,11 +897,12 @@ emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
710897
711898 // What this is a specialization of.
712899 auto SpecOf = CTSD->getSpecializedTemplateOrPartial ();
713- if (auto *CTD = dyn_cast<ClassTemplateDecl *>(SpecOf))
714- Specialization.SpecializationOf = getUSRForDecl (CTD);
715- else if (auto *CTPSD =
716- dyn_cast<ClassTemplatePartialSpecializationDecl *>(SpecOf))
717- Specialization.SpecializationOf = getUSRForDecl (CTPSD);
900+ if (auto *SpecPtr = dyn_cast<ClassTemplateDecl *>(SpecOf)) {
901+ Specialization.SpecializationOf = getUSRForDecl (SpecPtr);
902+ } else if (auto *SpecPtr =
903+ dyn_cast<ClassTemplatePartialSpecializationDecl *>(SpecOf)) {
904+ Specialization.SpecializationOf = getUSRForDecl (SpecPtr);
905+ }
718906
719907 // Parameters to the specialization. For partial specializations, get the
720908 // parameters "as written" from the ClassTemplatePartialSpecializationDecl
@@ -786,25 +974,42 @@ emitInfo(const CXXMethodDecl *D, const FullComment *FC, Location Loc,
786974 return {nullptr , makeAndInsertIntoParent<FunctionInfo &&>(std::move (Func))};
787975}
788976
977+ static void extractCommentFromDecl (const Decl *D, TypedefInfo &Info) {
978+ assert (D && " Invalid Decl when extracting comment" );
979+ ASTContext &Context = D->getASTContext ();
980+ RawComment *Comment = Context.getRawCommentForDeclNoCache (D);
981+ if (!Comment)
982+ return ;
983+
984+ Comment->setAttached ();
985+ if (comments::FullComment *Fc = Comment->parse (Context, nullptr , D)) {
986+ Info.Description .emplace_back ();
987+ parseFullComment (Fc, Info.Description .back ());
988+ }
989+ }
990+
789991std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
790992emitInfo (const TypedefDecl *D, const FullComment *FC, Location Loc,
791993 bool PublicOnly) {
792994 TypedefInfo Info;
793995 bool IsInAnonymousNamespace = false ;
794996 populateInfo (Info, D, FC, IsInAnonymousNamespace);
997+
795998 if (!shouldSerializeInfo (PublicOnly, IsInAnonymousNamespace, D))
796999 return {};
7971000
7981001 Info.DefLoc = Loc;
7991002 auto &LO = D->getLangOpts ();
8001003 Info.Underlying = getTypeInfoForType (D->getUnderlyingType (), LO);
1004+
8011005 if (Info.Underlying .Type .Name .empty ()) {
8021006 // Typedef for an unnamed type. This is like "typedef struct { } Foo;"
8031007 // The record serializer explicitly checks for this syntax and constructs
8041008 // a record with that name, so we don't want to emit a duplicate here.
8051009 return {};
8061010 }
8071011 Info.IsUsing = false ;
1012+ extractCommentFromDecl (D, Info);
8081013
8091014 // Info is wrapped in its parent scope so is returned in the second position.
8101015 return {nullptr , makeAndInsertIntoParent<TypedefInfo &&>(std::move (Info))};
@@ -816,17 +1021,19 @@ std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
8161021emitInfo (const TypeAliasDecl *D, const FullComment *FC, Location Loc,
8171022 bool PublicOnly) {
8181023 TypedefInfo Info;
819-
8201024 bool IsInAnonymousNamespace = false ;
8211025 populateInfo (Info, D, FC, IsInAnonymousNamespace);
8221026 if (!shouldSerializeInfo (PublicOnly, IsInAnonymousNamespace, D))
8231027 return {};
8241028
8251029 Info.DefLoc = Loc;
826- auto &LO = D->getLangOpts ();
1030+ const LangOptions &LO = D->getLangOpts ();
8271031 Info.Underlying = getTypeInfoForType (D->getUnderlyingType (), LO);
1032+ Info.TypeDeclaration = getTypeAlias (D);
8281033 Info.IsUsing = true ;
8291034
1035+ extractCommentFromDecl (D, Info);
1036+
8301037 // Info is wrapped in its parent scope so is returned in the second position.
8311038 return {nullptr , makeAndInsertIntoParent<TypedefInfo &&>(std::move (Info))};
8321039}
0 commit comments