1 //===--- Comment.cpp - Comment AST node implementation --------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/Comment.h"
12 #include "clang/AST/Decl.h"
13 #include "clang/AST/DeclObjC.h"
14 #include "clang/AST/DeclTemplate.h"
15 #include "llvm/Support/ErrorHandling.h"
16 #include "llvm/Support/raw_ostream.h"
17
18 namespace clang {
19 namespace comments {
20
getCommentKindName() const21 const char *Comment::getCommentKindName() const {
22 switch (getCommentKind()) {
23 case NoCommentKind: return "NoCommentKind";
24 #define ABSTRACT_COMMENT(COMMENT)
25 #define COMMENT(CLASS, PARENT) \
26 case CLASS##Kind: \
27 return #CLASS;
28 #include "clang/AST/CommentNodes.inc"
29 #undef COMMENT
30 #undef ABSTRACT_COMMENT
31 }
32 llvm_unreachable("Unknown comment kind!");
33 }
34
dump() const35 void Comment::dump() const {
36 // It is important that Comment::dump() is defined in a different TU than
37 // Comment::dump(raw_ostream, SourceManager). If both functions were defined
38 // in CommentDumper.cpp, that object file would be removed by linker because
39 // none of its functions are referenced by other object files, despite the
40 // LLVM_ATTRIBUTE_USED.
41 dump(llvm::errs(), NULL, NULL);
42 }
43
dump(const ASTContext & Context) const44 void Comment::dump(const ASTContext &Context) const {
45 dump(llvm::errs(), &Context.getCommentCommandTraits(),
46 &Context.getSourceManager());
47 }
48
49 namespace {
50 struct good {};
51 struct bad {};
52
53 template <typename T>
implements_child_begin_end(Comment::child_iterator (T::*)()const)54 good implements_child_begin_end(Comment::child_iterator (T::*)() const) {
55 return good();
56 }
57
implements_child_begin_end(Comment::child_iterator (Comment::*)()const)58 static inline bad implements_child_begin_end(
59 Comment::child_iterator (Comment::*)() const) {
60 return bad();
61 }
62
63 #define ASSERT_IMPLEMENTS_child_begin(function) \
64 (void) sizeof(good(implements_child_begin_end(function)))
65
CheckCommentASTNodes()66 static inline void CheckCommentASTNodes() {
67 #define ABSTRACT_COMMENT(COMMENT)
68 #define COMMENT(CLASS, PARENT) \
69 ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \
70 ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end);
71 #include "clang/AST/CommentNodes.inc"
72 #undef COMMENT
73 #undef ABSTRACT_COMMENT
74 }
75
76 #undef ASSERT_IMPLEMENTS_child_begin
77
78 } // end unnamed namespace
79
child_begin() const80 Comment::child_iterator Comment::child_begin() const {
81 switch (getCommentKind()) {
82 case NoCommentKind: llvm_unreachable("comment without a kind");
83 #define ABSTRACT_COMMENT(COMMENT)
84 #define COMMENT(CLASS, PARENT) \
85 case CLASS##Kind: \
86 return static_cast<const CLASS *>(this)->child_begin();
87 #include "clang/AST/CommentNodes.inc"
88 #undef COMMENT
89 #undef ABSTRACT_COMMENT
90 }
91 llvm_unreachable("Unknown comment kind!");
92 }
93
child_end() const94 Comment::child_iterator Comment::child_end() const {
95 switch (getCommentKind()) {
96 case NoCommentKind: llvm_unreachable("comment without a kind");
97 #define ABSTRACT_COMMENT(COMMENT)
98 #define COMMENT(CLASS, PARENT) \
99 case CLASS##Kind: \
100 return static_cast<const CLASS *>(this)->child_end();
101 #include "clang/AST/CommentNodes.inc"
102 #undef COMMENT
103 #undef ABSTRACT_COMMENT
104 }
105 llvm_unreachable("Unknown comment kind!");
106 }
107
isWhitespaceNoCache() const108 bool TextComment::isWhitespaceNoCache() const {
109 for (StringRef::const_iterator I = Text.begin(), E = Text.end();
110 I != E; ++I) {
111 const char C = *I;
112 if (C != ' ' && C != '\n' && C != '\r' &&
113 C != '\t' && C != '\f' && C != '\v')
114 return false;
115 }
116 return true;
117 }
118
isWhitespaceNoCache() const119 bool ParagraphComment::isWhitespaceNoCache() const {
120 for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) {
121 if (const TextComment *TC = dyn_cast<TextComment>(*I)) {
122 if (!TC->isWhitespace())
123 return false;
124 } else
125 return false;
126 }
127 return true;
128 }
129
getDirectionAsString(PassDirection D)130 const char *ParamCommandComment::getDirectionAsString(PassDirection D) {
131 switch (D) {
132 case ParamCommandComment::In:
133 return "[in]";
134 case ParamCommandComment::Out:
135 return "[out]";
136 case ParamCommandComment::InOut:
137 return "[in,out]";
138 }
139 llvm_unreachable("unknown PassDirection");
140 }
141
fill()142 void DeclInfo::fill() {
143 assert(!IsFilled);
144
145 // Set defaults.
146 Kind = OtherKind;
147 TemplateKind = NotTemplate;
148 IsObjCMethod = false;
149 IsInstanceMethod = false;
150 IsClassMethod = false;
151 ParamVars = ArrayRef<const ParmVarDecl *>();
152 TemplateParameters = NULL;
153
154 if (!ThisDecl) {
155 // If there is no declaration, the defaults is our only guess.
156 IsFilled = true;
157 return;
158 }
159
160 Decl::Kind K = ThisDecl->getKind();
161 switch (K) {
162 default:
163 // Defaults are should be good for declarations we don't handle explicitly.
164 break;
165 case Decl::Function:
166 case Decl::CXXMethod:
167 case Decl::CXXConstructor:
168 case Decl::CXXDestructor:
169 case Decl::CXXConversion: {
170 const FunctionDecl *FD = cast<FunctionDecl>(ThisDecl);
171 Kind = FunctionKind;
172 ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
173 FD->getNumParams());
174 ResultType = FD->getResultType();
175 unsigned NumLists = FD->getNumTemplateParameterLists();
176 if (NumLists != 0) {
177 TemplateKind = TemplateSpecialization;
178 TemplateParameters =
179 FD->getTemplateParameterList(NumLists - 1);
180 }
181
182 if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
183 K == Decl::CXXDestructor || K == Decl::CXXConversion) {
184 const CXXMethodDecl *MD = cast<CXXMethodDecl>(ThisDecl);
185 IsInstanceMethod = MD->isInstance();
186 IsClassMethod = !IsInstanceMethod;
187 }
188 break;
189 }
190 case Decl::ObjCMethod: {
191 const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(ThisDecl);
192 Kind = FunctionKind;
193 ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
194 MD->param_size());
195 ResultType = MD->getResultType();
196 IsObjCMethod = true;
197 IsInstanceMethod = MD->isInstanceMethod();
198 IsClassMethod = !IsInstanceMethod;
199 break;
200 }
201 case Decl::FunctionTemplate: {
202 const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(ThisDecl);
203 Kind = FunctionKind;
204 TemplateKind = Template;
205 const FunctionDecl *FD = FTD->getTemplatedDecl();
206 ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
207 FD->getNumParams());
208 ResultType = FD->getResultType();
209 TemplateParameters = FTD->getTemplateParameters();
210 break;
211 }
212 case Decl::ClassTemplate: {
213 const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(ThisDecl);
214 Kind = ClassKind;
215 TemplateKind = Template;
216 TemplateParameters = CTD->getTemplateParameters();
217 break;
218 }
219 case Decl::ClassTemplatePartialSpecialization: {
220 const ClassTemplatePartialSpecializationDecl *CTPSD =
221 cast<ClassTemplatePartialSpecializationDecl>(ThisDecl);
222 Kind = ClassKind;
223 TemplateKind = TemplatePartialSpecialization;
224 TemplateParameters = CTPSD->getTemplateParameters();
225 break;
226 }
227 case Decl::ClassTemplateSpecialization:
228 Kind = ClassKind;
229 TemplateKind = TemplateSpecialization;
230 break;
231 case Decl::Record:
232 case Decl::CXXRecord:
233 Kind = ClassKind;
234 break;
235 case Decl::Var:
236 case Decl::Field:
237 case Decl::EnumConstant:
238 case Decl::ObjCIvar:
239 case Decl::ObjCAtDefsField:
240 Kind = VariableKind;
241 break;
242 case Decl::Namespace:
243 Kind = NamespaceKind;
244 break;
245 case Decl::Typedef: {
246 Kind = TypedefKind;
247 // If this is a typedef to something we consider a function, extract
248 // arguments and return type.
249 const TypedefDecl *TD = cast<TypedefDecl>(ThisDecl);
250 const TypeSourceInfo *TSI = TD->getTypeSourceInfo();
251 if (!TSI)
252 break;
253 TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
254 while (true) {
255 TL = TL.IgnoreParens();
256 // Look through typedefs.
257 if (TypedefTypeLoc *TypedefTL = dyn_cast<TypedefTypeLoc>(&TL)) {
258 TSI = TypedefTL->getTypedefNameDecl()->getTypeSourceInfo();
259 if (TSI)
260 break;
261 TL = TSI->getTypeLoc().getUnqualifiedLoc();
262 continue;
263 }
264 // Look through qualified types.
265 if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
266 TL = QualifiedTL->getUnqualifiedLoc();
267 continue;
268 }
269 // Look through pointer types.
270 if (PointerTypeLoc *PointerTL = dyn_cast<PointerTypeLoc>(&TL)) {
271 TL = PointerTL->getPointeeLoc().getUnqualifiedLoc();
272 continue;
273 }
274 if (BlockPointerTypeLoc *BlockPointerTL =
275 dyn_cast<BlockPointerTypeLoc>(&TL)) {
276 TL = BlockPointerTL->getPointeeLoc().getUnqualifiedLoc();
277 continue;
278 }
279 if (MemberPointerTypeLoc *MemberPointerTL =
280 dyn_cast<MemberPointerTypeLoc>(&TL)) {
281 TL = MemberPointerTL->getPointeeLoc().getUnqualifiedLoc();
282 continue;
283 }
284 // Is this a typedef for a function type?
285 if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
286 Kind = FunctionKind;
287 ArrayRef<ParmVarDecl *> Params = FTL->getParams();
288 ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
289 Params.size());
290 ResultType = FTL->getResultLoc().getType();
291 break;
292 }
293 break;
294 }
295 break;
296 }
297 case Decl::TypeAlias:
298 Kind = TypedefKind;
299 break;
300 case Decl::TypeAliasTemplate: {
301 const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(ThisDecl);
302 Kind = TypedefKind;
303 TemplateKind = Template;
304 TemplateParameters = TAT->getTemplateParameters();
305 break;
306 }
307 case Decl::Enum:
308 Kind = EnumKind;
309 break;
310 }
311
312 IsFilled = true;
313 }
314
315 } // end namespace comments
316 } // end namespace clang
317
318