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,184 @@ 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
+
56
+ // We need to also handle type constraints for code like:
57
+ // template <class T = void>
58
+ // class C {};
59
+ if (TTP->hasTypeConstraint ()) {
60
+ Stream << " = " ;
61
+ TTP->getTypeConstraint ()->print (
62
+ Stream, TTP->getASTContext ().getPrintingPolicy ());
63
+ }
64
+ } else if (const auto *NTTP =
65
+ llvm::dyn_cast<NonTypeTemplateParmDecl>(Param)) {
66
+ NTTP->getType ().print (Stream, NTTP->getASTContext ().getPrintingPolicy ());
67
+ if (NTTP->isParameterPack ())
68
+ Stream << " ..." ;
69
+ Stream << " " << NTTP->getNameAsString ();
70
+ } else if (const auto *TTPD =
71
+ llvm::dyn_cast<TemplateTemplateParmDecl>(Param)) {
72
+ Stream << " template <" ;
73
+ getTemplateParameters (TTPD->getTemplateParameters (), Stream);
74
+ Stream << " > class " << TTPD->getNameAsString ();
75
+ }
76
+ }
77
+
78
+ Stream << " > " ;
79
+ }
80
+
81
+ // Extract the full function prototype from a FunctionDecl including
82
+ // Full Decl
83
+ static llvm::SmallString<256 >
84
+ getFunctionPrototype (const FunctionDecl *FuncDecl) {
85
+ llvm::SmallString<256 > Result;
86
+ llvm::raw_svector_ostream Stream (Result);
87
+ const ASTContext &Ctx = FuncDecl->getASTContext ();
88
+ const auto *Method = llvm::dyn_cast<CXXMethodDecl>(FuncDecl);
89
+ // If it's a templated function, handle the template parameters
90
+ if (const auto *TmplDecl = FuncDecl->getDescribedTemplate ())
91
+ getTemplateParameters (TmplDecl->getTemplateParameters (), Stream);
92
+
93
+ // If it's a virtual method
94
+ if (Method && Method->isVirtual ())
95
+ Stream << " virtual " ;
96
+
97
+ // Print return type
98
+ FuncDecl->getReturnType ().print (Stream, Ctx.getPrintingPolicy ());
99
+
100
+ // Print function name
101
+ Stream << " " << FuncDecl->getNameAsString () << " (" ;
102
+
103
+ // Print parameter list with types, names, and default values
104
+ for (unsigned I = 0 ; I < FuncDecl->getNumParams (); ++I) {
105
+ if (I > 0 )
106
+ Stream << " , " ;
107
+ const ParmVarDecl *ParamDecl = FuncDecl->getParamDecl (I);
108
+ QualType ParamType = ParamDecl->getType ();
109
+ ParamType.print (Stream, Ctx.getPrintingPolicy ());
110
+
111
+ // Print parameter name if it has one
112
+ if (!ParamDecl->getName ().empty ())
113
+ Stream << " " << ParamDecl->getNameAsString ();
114
+
115
+ // Print default argument if it exists
116
+ if (ParamDecl->hasDefaultArg ()) {
117
+ const Expr *DefaultArg = ParamDecl->getDefaultArg ();
118
+ if (DefaultArg) {
119
+ Stream << " = " ;
120
+ DefaultArg->printPretty (Stream, nullptr , Ctx.getPrintingPolicy ());
121
+ }
122
+ }
123
+ }
124
+
125
+ // If it is a variadic function, add '...'
126
+ if (FuncDecl->isVariadic ()) {
127
+ if (FuncDecl->getNumParams () > 0 )
128
+ Stream << " , " ;
129
+ Stream << " ..." ;
130
+ }
131
+
132
+ Stream << " )" ;
133
+
134
+ // If it's a const method, add 'const' qualifier
135
+ if (Method) {
136
+ if (Method->isDeleted ())
137
+ Stream << " = delete" ;
138
+ if (Method->size_overridden_methods ())
139
+ Stream << " override" ;
140
+ if (Method->hasAttr <clang::FinalAttr>())
141
+ Stream << " final" ;
142
+ if (Method->isConst ())
143
+ Stream << " const" ;
144
+ if (Method->isPureVirtual ())
145
+ Stream << " = 0" ;
146
+ }
147
+
148
+ if (auto ExceptionSpecType = FuncDecl->getExceptionSpecType ())
149
+ Stream << " " << ExceptionSpecType;
150
+
151
+ return Result; // Convert SmallString to std::string for return
152
+ }
153
+
154
+ static llvm::SmallString<16 > getTypeAlias (const TypeAliasDecl *Alias) {
155
+ llvm::SmallString<16 > Result;
156
+ llvm::raw_svector_ostream Stream (Result);
157
+ const ASTContext &Ctx = Alias->getASTContext ();
158
+ if (const auto *TmplDecl = Alias->getDescribedTemplate ())
159
+ getTemplateParameters (TmplDecl->getTemplateParameters (), Stream);
160
+ Stream << " using " << Alias->getNameAsString () << " = " ;
161
+ QualType Q = Alias->getUnderlyingType ();
162
+ Q.print (Stream, Ctx.getPrintingPolicy ());
163
+
164
+ return Result;
165
+ }
166
+
167
+ // extract full syntax for record declaration
168
+ static llvm::SmallString<16 > getRecordPrototype (const CXXRecordDecl *CXXRD) {
169
+ llvm::SmallString<16 > Result;
170
+ LangOptions LangOpts;
171
+ PrintingPolicy Policy (LangOpts);
172
+ Policy.SuppressTagKeyword = false ;
173
+ Policy.FullyQualifiedName = true ;
174
+ Policy.IncludeNewlines = false ;
175
+ llvm::raw_svector_ostream OS (Result);
176
+ if (const auto *TD = CXXRD->getDescribedClassTemplate ()) {
177
+ OS << " template <" ;
178
+ bool FirstParam = true ;
179
+ for (const auto *Param : *TD->getTemplateParameters ()) {
180
+ if (!FirstParam)
181
+ OS << " , " ;
182
+ Param->print (OS, Policy);
183
+ FirstParam = false ;
184
+ }
185
+ OS << " >\n " ;
186
+ }
187
+
188
+ if (CXXRD->isStruct ())
189
+ OS << " struct " ;
190
+ else if (CXXRD->isClass ())
191
+ OS << " class " ;
192
+ else if (CXXRD->isUnion ())
193
+ OS << " union " ;
194
+
195
+ OS << CXXRD->getNameAsString ();
196
+
197
+ // We need to make sure we have a good enough declaration to check. In the
198
+ // case where the class is a forward declaration, we'll fail assertions in
199
+ // DeclCXX.
200
+ if (CXXRD->isCompleteDefinition () && CXXRD->getNumBases () > 0 ) {
201
+ OS << " : " ;
202
+ bool FirstBase = true ;
203
+ for (const auto &Base : CXXRD->bases ()) {
204
+ if (!FirstBase)
205
+ OS << " , " ;
206
+ if (Base.isVirtual ())
207
+ OS << " virtual " ;
208
+ OS << getAccessSpelling (Base.getAccessSpecifier ()) << " " ;
209
+ OS << Base.getType ().getAsString (Policy);
210
+ FirstBase = false ;
211
+ }
212
+ }
213
+ return Result;
214
+ }
215
+
38
216
// A function to extract the appropriate relative path for a given info's
39
217
// documentation. The path returned is a composite of the parent namespaces.
40
218
//
@@ -408,7 +586,6 @@ static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
408
586
ASTContext &Context = E->getASTContext ();
409
587
if (RawComment *Comment =
410
588
E->getASTContext ().getRawCommentForDeclNoCache (E)) {
411
- CommentInfo CInfo;
412
589
Comment->setAttached ();
413
590
if (comments::FullComment *Fc = Comment->parse (Context, nullptr , E)) {
414
591
EnumValueInfo &Member = I.Members .back ();
@@ -434,6 +611,7 @@ static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
434
611
// Don't parse bases if this isn't a definition.
435
612
if (!D->isThisDeclarationADefinition ())
436
613
return ;
614
+
437
615
for (const CXXBaseSpecifier &B : D->bases ()) {
438
616
if (B.isVirtual ())
439
617
continue ;
@@ -555,6 +733,7 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
555
733
populateSymbolInfo (I, D, FC, Loc, IsInAnonymousNamespace);
556
734
auto &LO = D->getLangOpts ();
557
735
I.ReturnType = getTypeInfoForType (D->getReturnType (), LO);
736
+ I.Prototype = getFunctionPrototype (D);
558
737
parseParameters (I, D);
559
738
560
739
populateTemplateParameters (I.Template , D);
@@ -686,15 +865,19 @@ emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc,
686
865
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
687
866
emitInfo (const RecordDecl *D, const FullComment *FC, Location Loc,
688
867
bool PublicOnly) {
868
+
689
869
auto RI = std::make_unique<RecordInfo>();
690
870
bool IsInAnonymousNamespace = false ;
871
+
691
872
populateSymbolInfo (*RI, D, FC, Loc, IsInAnonymousNamespace);
692
873
if (!shouldSerializeInfo (PublicOnly, IsInAnonymousNamespace, D))
693
874
return {};
694
875
695
876
RI->TagType = D->getTagKind ();
696
877
parseFields (*RI, D, PublicOnly);
878
+
697
879
if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
880
+ RI->FullName = getRecordPrototype (C);
698
881
if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl ()) {
699
882
RI->Name = TD->getNameAsString ();
700
883
RI->IsTypeDef = true ;
@@ -716,11 +899,11 @@ emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
716
899
717
900
// What this is a specialization of.
718
901
auto SpecOf = CTSD->getSpecializedTemplateOrPartial ();
719
- if (auto *CTD = dyn_cast<ClassTemplateDecl *>(SpecOf))
720
- Specialization.SpecializationOf = getUSRForDecl (CTD );
721
- else if (auto *CTPSD =
902
+ if (auto *SpecTD = dyn_cast<ClassTemplateDecl *>(SpecOf))
903
+ Specialization.SpecializationOf = getUSRForDecl (SpecTD );
904
+ else if (auto *SpecTD =
722
905
dyn_cast<ClassTemplatePartialSpecializationDecl *>(SpecOf))
723
- Specialization.SpecializationOf = getUSRForDecl (CTPSD );
906
+ Specialization.SpecializationOf = getUSRForDecl (SpecTD );
724
907
725
908
// Parameters to the specialization. For partial specializations, get the
726
909
// parameters "as written" from the ClassTemplatePartialSpecializationDecl
@@ -792,25 +975,42 @@ emitInfo(const CXXMethodDecl *D, const FullComment *FC, Location Loc,
792
975
return {nullptr , makeAndInsertIntoParent<FunctionInfo &&>(std::move (Func))};
793
976
}
794
977
978
+ static void extractCommentFromDecl (const Decl *D, TypedefInfo &Info) {
979
+ assert (D && " Invalid Decl when extracting comment" );
980
+ ASTContext &Context = D->getASTContext ();
981
+ RawComment *Comment = Context.getRawCommentForDeclNoCache (D);
982
+ if (!Comment)
983
+ return ;
984
+
985
+ Comment->setAttached ();
986
+ if (comments::FullComment *Fc = Comment->parse (Context, nullptr , D)) {
987
+ Info.Description .emplace_back ();
988
+ parseFullComment (Fc, Info.Description .back ());
989
+ }
990
+ }
991
+
795
992
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
796
993
emitInfo (const TypedefDecl *D, const FullComment *FC, Location Loc,
797
994
bool PublicOnly) {
798
995
TypedefInfo Info;
799
996
bool IsInAnonymousNamespace = false ;
800
997
populateInfo (Info, D, FC, IsInAnonymousNamespace);
998
+
801
999
if (!shouldSerializeInfo (PublicOnly, IsInAnonymousNamespace, D))
802
1000
return {};
803
1001
804
1002
Info.DefLoc = Loc;
805
1003
auto &LO = D->getLangOpts ();
806
1004
Info.Underlying = getTypeInfoForType (D->getUnderlyingType (), LO);
1005
+
807
1006
if (Info.Underlying .Type .Name .empty ()) {
808
1007
// Typedef for an unnamed type. This is like "typedef struct { } Foo;"
809
1008
// The record serializer explicitly checks for this syntax and constructs
810
1009
// a record with that name, so we don't want to emit a duplicate here.
811
1010
return {};
812
1011
}
813
1012
Info.IsUsing = false ;
1013
+ extractCommentFromDecl (D, Info);
814
1014
815
1015
// Info is wrapped in its parent scope so is returned in the second position.
816
1016
return {nullptr , makeAndInsertIntoParent<TypedefInfo &&>(std::move (Info))};
@@ -822,17 +1022,19 @@ std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
822
1022
emitInfo (const TypeAliasDecl *D, const FullComment *FC, Location Loc,
823
1023
bool PublicOnly) {
824
1024
TypedefInfo Info;
825
-
826
1025
bool IsInAnonymousNamespace = false ;
827
1026
populateInfo (Info, D, FC, IsInAnonymousNamespace);
828
1027
if (!shouldSerializeInfo (PublicOnly, IsInAnonymousNamespace, D))
829
1028
return {};
830
1029
831
1030
Info.DefLoc = Loc;
832
- auto &LO = D->getLangOpts ();
1031
+ const LangOptions &LO = D->getLangOpts ();
833
1032
Info.Underlying = getTypeInfoForType (D->getUnderlyingType (), LO);
1033
+ Info.TypeDeclaration = getTypeAlias (D);
834
1034
Info.IsUsing = true ;
835
1035
1036
+ extractCommentFromDecl (D, Info);
1037
+
836
1038
// Info is wrapped in its parent scope so is returned in the second position.
837
1039
return {nullptr , makeAndInsertIntoParent<TypedefInfo &&>(std::move (Info))};
838
1040
}
0 commit comments