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 
21 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 
35 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 
44 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>
54 good implements_child_begin_end(Comment::child_iterator (T::*)() const) {
55   return good();
56 }
57 
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 
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 
80 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 
94 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 
108 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 
119 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 
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 
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 qualified types.
257       if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
258         TL = QualifiedTL->getUnqualifiedLoc();
259         continue;
260       }
261       // Look through pointer types.
262       if (PointerTypeLoc *PointerTL = dyn_cast<PointerTypeLoc>(&TL)) {
263         TL = PointerTL->getPointeeLoc().getUnqualifiedLoc();
264         continue;
265       }
266       if (BlockPointerTypeLoc *BlockPointerTL =
267               dyn_cast<BlockPointerTypeLoc>(&TL)) {
268         TL = BlockPointerTL->getPointeeLoc().getUnqualifiedLoc();
269         continue;
270       }
271       if (MemberPointerTypeLoc *MemberPointerTL =
272               dyn_cast<MemberPointerTypeLoc>(&TL)) {
273         TL = MemberPointerTL->getPointeeLoc().getUnqualifiedLoc();
274         continue;
275       }
276       // Is this a typedef for a function type?
277       if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
278         Kind = FunctionKind;
279         ArrayRef<ParmVarDecl *> Params = FTL->getParams();
280         ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
281                                                   Params.size());
282         ResultType = FTL->getResultLoc().getType();
283         break;
284       }
285       break;
286     }
287     break;
288   }
289   case Decl::TypeAlias:
290     Kind = TypedefKind;
291     break;
292   case Decl::TypeAliasTemplate: {
293     const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(ThisDecl);
294     Kind = TypedefKind;
295     TemplateKind = Template;
296     TemplateParameters = TAT->getTemplateParameters();
297     break;
298   }
299   case Decl::Enum:
300     Kind = EnumKind;
301     break;
302   }
303 
304   IsFilled = true;
305 }
306 
307 } // end namespace comments
308 } // end namespace clang
309 
310