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,188 @@ static void populateMemberTypeInfo(RecordInfo &I, AccessSpecifier &Access,
35
35
const DeclaratorDecl *D,
36
36
bool IsStatic = false );
37
37
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
+
38
220
// A function to extract the appropriate relative path for a given info's
39
221
// documentation. The path returned is a composite of the parent namespaces.
40
222
//
@@ -408,7 +590,6 @@ static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
408
590
ASTContext &Context = E->getASTContext ();
409
591
if (RawComment *Comment =
410
592
E->getASTContext ().getRawCommentForDeclNoCache (E)) {
411
- CommentInfo CInfo;
412
593
Comment->setAttached ();
413
594
if (comments::FullComment *Fc = Comment->parse (Context, nullptr , E)) {
414
595
EnumValueInfo &Member = I.Members .back ();
@@ -434,6 +615,7 @@ static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
434
615
// Don't parse bases if this isn't a definition.
435
616
if (!D->isThisDeclarationADefinition ())
436
617
return ;
618
+
437
619
for (const CXXBaseSpecifier &B : D->bases ()) {
438
620
if (B.isVirtual ())
439
621
continue ;
@@ -549,6 +731,7 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
549
731
populateSymbolInfo (I, D, FC, Loc, IsInAnonymousNamespace);
550
732
auto &LO = D->getLangOpts ();
551
733
I.ReturnType = getTypeInfoForType (D->getReturnType (), LO);
734
+ I.ProtoType = getFunctionPrototype (D);
552
735
parseParameters (I, D);
553
736
554
737
populateTemplateParameters (I.Template , D);
@@ -680,15 +863,19 @@ emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc,
680
863
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
681
864
emitInfo (const RecordDecl *D, const FullComment *FC, Location Loc,
682
865
bool PublicOnly) {
866
+
683
867
auto RI = std::make_unique<RecordInfo>();
684
868
bool IsInAnonymousNamespace = false ;
869
+
685
870
populateSymbolInfo (*RI, D, FC, Loc, IsInAnonymousNamespace);
686
871
if (!shouldSerializeInfo (PublicOnly, IsInAnonymousNamespace, D))
687
872
return {};
688
873
689
874
RI->TagType = D->getTagKind ();
690
875
parseFields (*RI, D, PublicOnly);
876
+
691
877
if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
878
+ RI->FullName = getRecordPrototype (C);
692
879
if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl ()) {
693
880
RI->Name = TD->getNameAsString ();
694
881
RI->IsTypeDef = true ;
@@ -710,11 +897,12 @@ emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
710
897
711
898
// What this is a specialization of.
712
899
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
+ }
718
906
719
907
// Parameters to the specialization. For partial specializations, get the
720
908
// parameters "as written" from the ClassTemplatePartialSpecializationDecl
@@ -786,25 +974,42 @@ emitInfo(const CXXMethodDecl *D, const FullComment *FC, Location Loc,
786
974
return {nullptr , makeAndInsertIntoParent<FunctionInfo &&>(std::move (Func))};
787
975
}
788
976
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
+
789
991
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
790
992
emitInfo (const TypedefDecl *D, const FullComment *FC, Location Loc,
791
993
bool PublicOnly) {
792
994
TypedefInfo Info;
793
995
bool IsInAnonymousNamespace = false ;
794
996
populateInfo (Info, D, FC, IsInAnonymousNamespace);
997
+
795
998
if (!shouldSerializeInfo (PublicOnly, IsInAnonymousNamespace, D))
796
999
return {};
797
1000
798
1001
Info.DefLoc = Loc;
799
1002
auto &LO = D->getLangOpts ();
800
1003
Info.Underlying = getTypeInfoForType (D->getUnderlyingType (), LO);
1004
+
801
1005
if (Info.Underlying .Type .Name .empty ()) {
802
1006
// Typedef for an unnamed type. This is like "typedef struct { } Foo;"
803
1007
// The record serializer explicitly checks for this syntax and constructs
804
1008
// a record with that name, so we don't want to emit a duplicate here.
805
1009
return {};
806
1010
}
807
1011
Info.IsUsing = false ;
1012
+ extractCommentFromDecl (D, Info);
808
1013
809
1014
// Info is wrapped in its parent scope so is returned in the second position.
810
1015
return {nullptr , makeAndInsertIntoParent<TypedefInfo &&>(std::move (Info))};
@@ -816,17 +1021,19 @@ std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
816
1021
emitInfo (const TypeAliasDecl *D, const FullComment *FC, Location Loc,
817
1022
bool PublicOnly) {
818
1023
TypedefInfo Info;
819
-
820
1024
bool IsInAnonymousNamespace = false ;
821
1025
populateInfo (Info, D, FC, IsInAnonymousNamespace);
822
1026
if (!shouldSerializeInfo (PublicOnly, IsInAnonymousNamespace, D))
823
1027
return {};
824
1028
825
1029
Info.DefLoc = Loc;
826
- auto &LO = D->getLangOpts ();
1030
+ const LangOptions &LO = D->getLangOpts ();
827
1031
Info.Underlying = getTypeInfoForType (D->getUnderlyingType (), LO);
1032
+ Info.TypeDeclaration = getTypeAlias (D);
828
1033
Info.IsUsing = true ;
829
1034
1035
+ extractCommentFromDecl (D, Info);
1036
+
830
1037
// Info is wrapped in its parent scope so is returned in the second position.
831
1038
return {nullptr , makeAndInsertIntoParent<TypedefInfo &&>(std::move (Info))};
832
1039
}
0 commit comments