8
8
9
9
#include " Serialize.h"
10
10
#include " BitcodeWriter.h"
11
+ #include " clang/AST/Attr.h"
11
12
#include " clang/AST/Comment.h"
12
13
#include " clang/Index/USRGeneration.h"
13
14
#include " clang/Lex/Lexer.h"
14
- #include " llvm/ADT/Hashing.h"
15
15
#include " llvm/ADT/StringExtras.h"
16
16
#include " llvm/Support/SHA1.h"
17
17
@@ -35,6 +35,180 @@ static void populateMemberTypeInfo(RecordInfo &I, AccessSpecifier &Access,
35
35
const DeclaratorDecl *D,
36
36
bool IsStatic = false );
37
37
38
+ static 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
+ const NamedDecl *Param = TemplateParams->getParam (i);
47
+ if (const auto *TTP = llvm::dyn_cast<TemplateTypeParmDecl>(Param)) {
48
+ if (TTP->wasDeclaredWithTypename ())
49
+ Stream << " typename" ;
50
+ else
51
+ Stream << " class" ;
52
+ if (TTP->isParameterPack ())
53
+ Stream << " ..." ;
54
+ Stream << " " << TTP->getNameAsString ();
55
+ } else if (const auto *NTTP =
56
+ llvm::dyn_cast<NonTypeTemplateParmDecl>(Param)) {
57
+ NTTP->getType ().print (Stream, NTTP->getASTContext ().getPrintingPolicy ());
58
+ if (NTTP->isParameterPack ())
59
+ Stream << " ..." ;
60
+ Stream << " " << NTTP->getNameAsString ();
61
+ } else if (const auto *TTPD =
62
+ llvm::dyn_cast<TemplateTemplateParmDecl>(Param)) {
63
+ Stream << " template <" ;
64
+ getTemplateParameters (TTPD->getTemplateParameters (), Stream);
65
+ Stream << " > class " << TTPD->getNameAsString ();
66
+ }
67
+ }
68
+
69
+ Stream << " > " ;
70
+ }
71
+
72
+ // Extract the full function prototype from a FunctionDecl including
73
+ // Full Decl
74
+ static llvm::SmallString<256 >
75
+ getFunctionPrototype (const FunctionDecl *FuncDecl) {
76
+ llvm::SmallString<256 > Result;
77
+ llvm::raw_svector_ostream Stream (Result);
78
+ const ASTContext &Ctx = FuncDecl->getASTContext ();
79
+ const auto *Method = llvm::dyn_cast<CXXMethodDecl>(FuncDecl);
80
+ // If it's a templated function, handle the template parameters
81
+ if (const auto *TmplDecl = FuncDecl->getDescribedTemplate ())
82
+ getTemplateParameters (TmplDecl->getTemplateParameters (), Stream);
83
+
84
+ // If it's a virtual method
85
+ if (Method && Method->isVirtual ())
86
+ Stream << " virtual " ;
87
+
88
+ // Print return type
89
+ FuncDecl->getReturnType ().print (Stream, Ctx.getPrintingPolicy ());
90
+
91
+ // Print function name
92
+ Stream << " " << FuncDecl->getNameAsString () << " (" ;
93
+
94
+ // Print parameter list with types, names, and default values
95
+ for (unsigned I = 0 ; I < FuncDecl->getNumParams (); ++I) {
96
+ if (I > 0 )
97
+ Stream << " , " ;
98
+ const ParmVarDecl *ParamDecl = FuncDecl->getParamDecl (I);
99
+ QualType ParamType = ParamDecl->getType ();
100
+ ParamType.print (Stream, Ctx.getPrintingPolicy ());
101
+
102
+ // Print parameter name if it has one
103
+ if (!ParamDecl->getName ().empty ())
104
+ Stream << " " << ParamDecl->getNameAsString ();
105
+
106
+ // Print default argument if it exists
107
+ if (ParamDecl->hasDefaultArg ()) {
108
+ const Expr *DefaultArg = ParamDecl->getDefaultArg ();
109
+ if (DefaultArg) {
110
+ Stream << " = " ;
111
+ DefaultArg->printPretty (Stream, nullptr , Ctx.getPrintingPolicy ());
112
+ }
113
+ }
114
+ }
115
+
116
+ // If it is a variadic function, add '...'
117
+ if (FuncDecl->isVariadic ()) {
118
+ if (FuncDecl->getNumParams () > 0 )
119
+ Stream << " , " ;
120
+ Stream << " ..." ;
121
+ }
122
+
123
+ Stream << " )" ;
124
+
125
+ // If it's a const method, add 'const' qualifier
126
+ if (Method) {
127
+ if (Method->size_overridden_methods ())
128
+ Stream << " override" ;
129
+ if (Method->hasAttr <clang::FinalAttr>())
130
+ Stream << " final" ;
131
+ if (Method->isConst ())
132
+ Stream << " const" ;
133
+ if (Method->isPureVirtual ())
134
+ Stream << " = 0" ;
135
+ }
136
+ return Result; // Convert SmallString to std::string for return
137
+ }
138
+
139
+ static llvm::SmallString<16 > getTypeDefDecl (const TypedefDecl *TypeDef) {
140
+ llvm::SmallString<16 > Result;
141
+ llvm::raw_svector_ostream Stream (Result);
142
+ const ASTContext &Ctx = TypeDef->getASTContext ();
143
+ Stream << " typedef " ;
144
+ QualType Q = TypeDef->getUnderlyingType ();
145
+ Q.print (Stream, Ctx.getPrintingPolicy ());
146
+ Stream << " " << TypeDef->getNameAsString ();
147
+ return Result;
148
+ }
149
+
150
+ static llvm::SmallString<16 > getTypeAlias (const TypeAliasDecl *Alias) {
151
+ llvm::SmallString<16 > Result;
152
+ llvm::raw_svector_ostream Stream (Result);
153
+ const ASTContext &Ctx = Alias->getASTContext ();
154
+ if (const auto *TmplDecl = Alias->getDescribedTemplate ())
155
+ getTemplateParameters (TmplDecl->getTemplateParameters (), Stream);
156
+ Stream << " using " << Alias->getNameAsString () << " = " ;
157
+ QualType Q = Alias->getUnderlyingType ();
158
+ Q.print (Stream, Ctx.getPrintingPolicy ());
159
+
160
+ return Result;
161
+ }
162
+
163
+ // extract full syntax for record declaration
164
+ static llvm::SmallString<16 > getRecordPrototype (const CXXRecordDecl *CXXRD) {
165
+ llvm::SmallString<16 > Result;
166
+ LangOptions LangOpts;
167
+ PrintingPolicy Policy (LangOpts);
168
+ Policy.SuppressTagKeyword = false ;
169
+ Policy.FullyQualifiedName = true ;
170
+ Policy.IncludeNewlines = false ;
171
+ llvm::raw_svector_ostream OS (Result);
172
+ if (const auto *TD = CXXRD->getDescribedClassTemplate ()) {
173
+ OS << " template <" ;
174
+ bool FirstParam = true ;
175
+ for (const auto *Param : *TD->getTemplateParameters ()) {
176
+ if (!FirstParam)
177
+ OS << " , " ;
178
+ Param->print (OS, Policy);
179
+ FirstParam = false ;
180
+ }
181
+ OS << " >\n " ;
182
+ }
183
+
184
+ if (CXXRD->isStruct ())
185
+ OS << " struct " ;
186
+ else if (CXXRD->isClass ())
187
+ OS << " class " ;
188
+ else if (CXXRD->isUnion ())
189
+ OS << " union " ;
190
+
191
+ OS << CXXRD->getNameAsString ();
192
+
193
+ // We need to make sure we have a good enough declaration to check. In the
194
+ // case where the class is a forward declaration, we'll fail assertions in
195
+ // DeclCXX.
196
+ if (CXXRD->isCompleteDefinition () && CXXRD->getNumBases () > 0 ) {
197
+ OS << " : " ;
198
+ bool FirstBase = true ;
199
+ for (const auto &Base : CXXRD->bases ()) {
200
+ if (!FirstBase)
201
+ OS << " , " ;
202
+ if (Base.isVirtual ())
203
+ OS << " virtual " ;
204
+ OS << getAccessSpelling (Base.getAccessSpecifier ()) << " " ;
205
+ OS << Base.getType ().getAsString (Policy);
206
+ FirstBase = false ;
207
+ }
208
+ }
209
+ return Result;
210
+ }
211
+
38
212
// A function to extract the appropriate relative path for a given info's
39
213
// documentation. The path returned is a composite of the parent namespaces.
40
214
//
@@ -408,7 +582,6 @@ static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
408
582
ASTContext &Context = E->getASTContext ();
409
583
if (RawComment *Comment =
410
584
E->getASTContext ().getRawCommentForDeclNoCache (E)) {
411
- CommentInfo CInfo;
412
585
Comment->setAttached ();
413
586
if (comments::FullComment *Fc = Comment->parse (Context, nullptr , E)) {
414
587
EnumValueInfo &Member = I.Members .back ();
@@ -434,6 +607,7 @@ static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
434
607
// Don't parse bases if this isn't a definition.
435
608
if (!D->isThisDeclarationADefinition ())
436
609
return ;
610
+
437
611
for (const CXXBaseSpecifier &B : D->bases ()) {
438
612
if (B.isVirtual ())
439
613
continue ;
@@ -549,6 +723,7 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
549
723
populateSymbolInfo (I, D, FC, Loc, IsInAnonymousNamespace);
550
724
auto &LO = D->getLangOpts ();
551
725
I.ReturnType = getTypeInfoForType (D->getReturnType (), LO);
726
+ I.Prototype = getFunctionPrototype (D);
552
727
parseParameters (I, D);
553
728
554
729
populateTemplateParameters (I.Template , D);
@@ -680,15 +855,19 @@ emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc,
680
855
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
681
856
emitInfo (const RecordDecl *D, const FullComment *FC, Location Loc,
682
857
bool PublicOnly) {
858
+
683
859
auto RI = std::make_unique<RecordInfo>();
684
860
bool IsInAnonymousNamespace = false ;
861
+
685
862
populateSymbolInfo (*RI, D, FC, Loc, IsInAnonymousNamespace);
686
863
if (!shouldSerializeInfo (PublicOnly, IsInAnonymousNamespace, D))
687
864
return {};
688
865
689
866
RI->TagType = D->getTagKind ();
690
867
parseFields (*RI, D, PublicOnly);
868
+
691
869
if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
870
+ RI->FullName = getRecordPrototype (C);
692
871
if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl ()) {
693
872
RI->Name = TD->getNameAsString ();
694
873
RI->IsTypeDef = true ;
@@ -710,11 +889,11 @@ emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
710
889
711
890
// What this is a specialization of.
712
891
auto SpecOf = CTSD->getSpecializedTemplateOrPartial ();
713
- if (auto *CTD = dyn_cast<ClassTemplateDecl *>(SpecOf))
714
- Specialization.SpecializationOf = getUSRForDecl (CTD );
715
- else if (auto *CTPSD =
892
+ if (auto *SpecTD = dyn_cast<ClassTemplateDecl *>(SpecOf))
893
+ Specialization.SpecializationOf = getUSRForDecl (SpecTD );
894
+ else if (auto *SpecTD =
716
895
dyn_cast<ClassTemplatePartialSpecializationDecl *>(SpecOf))
717
- Specialization.SpecializationOf = getUSRForDecl (CTPSD );
896
+ Specialization.SpecializationOf = getUSRForDecl (SpecTD );
718
897
719
898
// Parameters to the specialization. For partial specializations, get the
720
899
// parameters "as written" from the ClassTemplatePartialSpecializationDecl
@@ -786,25 +965,42 @@ emitInfo(const CXXMethodDecl *D, const FullComment *FC, Location Loc,
786
965
return {nullptr , makeAndInsertIntoParent<FunctionInfo &&>(std::move (Func))};
787
966
}
788
967
968
+ static void extractCommentFromDecl (const Decl *D, TypedefInfo &Info) {
969
+ assert (D && " Invalid Decl when extracting comment" );
970
+ ASTContext &Context = D->getASTContext ();
971
+ RawComment *Comment = Context.getRawCommentForDeclNoCache (D);
972
+ if (!Comment)
973
+ return ;
974
+
975
+ Comment->setAttached ();
976
+ if (comments::FullComment *Fc = Comment->parse (Context, nullptr , D)) {
977
+ Info.Description .emplace_back ();
978
+ parseFullComment (Fc, Info.Description .back ());
979
+ }
980
+ }
981
+
789
982
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
790
983
emitInfo (const TypedefDecl *D, const FullComment *FC, Location Loc,
791
984
bool PublicOnly) {
792
985
TypedefInfo Info;
793
986
bool IsInAnonymousNamespace = false ;
794
987
populateInfo (Info, D, FC, IsInAnonymousNamespace);
988
+
795
989
if (!shouldSerializeInfo (PublicOnly, IsInAnonymousNamespace, D))
796
990
return {};
797
991
798
992
Info.DefLoc = Loc;
799
993
auto &LO = D->getLangOpts ();
800
994
Info.Underlying = getTypeInfoForType (D->getUnderlyingType (), LO);
995
+
801
996
if (Info.Underlying .Type .Name .empty ()) {
802
997
// Typedef for an unnamed type. This is like "typedef struct { } Foo;"
803
998
// The record serializer explicitly checks for this syntax and constructs
804
999
// a record with that name, so we don't want to emit a duplicate here.
805
1000
return {};
806
1001
}
807
1002
Info.IsUsing = false ;
1003
+ extractCommentFromDecl (D, Info);
808
1004
809
1005
// Info is wrapped in its parent scope so is returned in the second position.
810
1006
return {nullptr , makeAndInsertIntoParent<TypedefInfo &&>(std::move (Info))};
@@ -816,17 +1012,19 @@ std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
816
1012
emitInfo (const TypeAliasDecl *D, const FullComment *FC, Location Loc,
817
1013
bool PublicOnly) {
818
1014
TypedefInfo Info;
819
-
820
1015
bool IsInAnonymousNamespace = false ;
821
1016
populateInfo (Info, D, FC, IsInAnonymousNamespace);
822
1017
if (!shouldSerializeInfo (PublicOnly, IsInAnonymousNamespace, D))
823
1018
return {};
824
1019
825
1020
Info.DefLoc = Loc;
826
- auto &LO = D->getLangOpts ();
1021
+ const LangOptions &LO = D->getLangOpts ();
827
1022
Info.Underlying = getTypeInfoForType (D->getUnderlyingType (), LO);
1023
+ Info.TypeDeclaration = getTypeAlias (D);
828
1024
Info.IsUsing = true ;
829
1025
1026
+ extractCommentFromDecl (D, Info);
1027
+
830
1028
// Info is wrapped in its parent scope so is returned in the second position.
831
1029
return {nullptr , makeAndInsertIntoParent<TypedefInfo &&>(std::move (Info))};
832
1030
}
0 commit comments