• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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