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/Comment.h"
11 #include "clang/AST/Decl.h"
12 #include "clang/AST/DeclObjC.h"
13 #include "clang/AST/DeclTemplate.h"
14 #include "llvm/Support/ErrorHandling.h"
15 #include "llvm/Support/raw_ostream.h"
16 
17 namespace clang {
18 namespace comments {
19 
20 const char *Comment::getCommentKindName() const {
21   switch (getCommentKind()) {
22   case NoCommentKind: return "NoCommentKind";
23 #define ABSTRACT_COMMENT(COMMENT)
24 #define COMMENT(CLASS, PARENT) \
25   case CLASS##Kind: \
26     return #CLASS;
27 #include "clang/AST/CommentNodes.inc"
28 #undef COMMENT
29 #undef ABSTRACT_COMMENT
30   }
31   llvm_unreachable("Unknown comment kind!");
32 }
33 
34 void Comment::dump() const {
35   // It is important that Comment::dump() is defined in a different TU than
36   // Comment::dump(raw_ostream, SourceManager).  If both functions were defined
37   // in CommentDumper.cpp, that object file would be removed by linker because
38   // none of its functions are referenced by other object files, despite the
39   // LLVM_ATTRIBUTE_USED.
40   dump(llvm::errs(), NULL);
41 }
42 
43 void Comment::dump(SourceManager &SM) const {
44   dump(llvm::errs(), &SM);
45 }
46 
47 namespace {
48 struct good {};
49 struct bad {};
50 
51 template <typename T>
52 good implements_child_begin_end(Comment::child_iterator (T::*)() const) {
53   return good();
54 }
55 
56 static inline bad implements_child_begin_end(
57                       Comment::child_iterator (Comment::*)() const) {
58   return bad();
59 }
60 
61 #define ASSERT_IMPLEMENTS_child_begin(function) \
62   (void) sizeof(good(implements_child_begin_end(function)))
63 
64 static inline void CheckCommentASTNodes() {
65 #define ABSTRACT_COMMENT(COMMENT)
66 #define COMMENT(CLASS, PARENT) \
67   ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \
68   ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end);
69 #include "clang/AST/CommentNodes.inc"
70 #undef COMMENT
71 #undef ABSTRACT_COMMENT
72 }
73 
74 #undef ASSERT_IMPLEMENTS_child_begin
75 
76 } // end unnamed namespace
77 
78 Comment::child_iterator Comment::child_begin() const {
79   switch (getCommentKind()) {
80   case NoCommentKind: llvm_unreachable("comment without a kind");
81 #define ABSTRACT_COMMENT(COMMENT)
82 #define COMMENT(CLASS, PARENT) \
83   case CLASS##Kind: \
84     return static_cast<const CLASS *>(this)->child_begin();
85 #include "clang/AST/CommentNodes.inc"
86 #undef COMMENT
87 #undef ABSTRACT_COMMENT
88   }
89   llvm_unreachable("Unknown comment kind!");
90 }
91 
92 Comment::child_iterator Comment::child_end() const {
93   switch (getCommentKind()) {
94   case NoCommentKind: llvm_unreachable("comment without a kind");
95 #define ABSTRACT_COMMENT(COMMENT)
96 #define COMMENT(CLASS, PARENT) \
97   case CLASS##Kind: \
98     return static_cast<const CLASS *>(this)->child_end();
99 #include "clang/AST/CommentNodes.inc"
100 #undef COMMENT
101 #undef ABSTRACT_COMMENT
102   }
103   llvm_unreachable("Unknown comment kind!");
104 }
105 
106 bool TextComment::isWhitespaceNoCache() const {
107   for (StringRef::const_iterator I = Text.begin(), E = Text.end();
108        I != E; ++I) {
109     const char C = *I;
110     if (C != ' ' && C != '\n' && C != '\r' &&
111         C != '\t' && C != '\f' && C != '\v')
112       return false;
113   }
114   return true;
115 }
116 
117 bool ParagraphComment::isWhitespaceNoCache() const {
118   for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) {
119     if (const TextComment *TC = dyn_cast<TextComment>(*I)) {
120       if (!TC->isWhitespace())
121         return false;
122     } else
123       return false;
124   }
125   return true;
126 }
127 
128 const char *ParamCommandComment::getDirectionAsString(PassDirection D) {
129   switch (D) {
130   case ParamCommandComment::In:
131     return "[in]";
132   case ParamCommandComment::Out:
133     return "[out]";
134   case ParamCommandComment::InOut:
135     return "[in,out]";
136   }
137   llvm_unreachable("unknown PassDirection");
138 }
139 
140 void DeclInfo::fill() {
141   assert(!IsFilled);
142 
143   // Set defaults.
144   Kind = OtherKind;
145   IsTemplateDecl = false;
146   IsTemplateSpecialization = false;
147   IsTemplatePartialSpecialization = false;
148   IsInstanceMethod = false;
149   IsClassMethod = false;
150   ParamVars = ArrayRef<const ParmVarDecl *>();
151   TemplateParameters = NULL;
152 
153   if (!ThisDecl) {
154     // If there is no declaration, the defaults is our only guess.
155     IsFilled = true;
156     return;
157   }
158 
159   Decl::Kind K = ThisDecl->getKind();
160   switch (K) {
161   default:
162     // Defaults are should be good for declarations we don't handle explicitly.
163     break;
164   case Decl::Function:
165   case Decl::CXXMethod:
166   case Decl::CXXConstructor:
167   case Decl::CXXDestructor:
168   case Decl::CXXConversion: {
169     const FunctionDecl *FD = cast<FunctionDecl>(ThisDecl);
170     Kind = FunctionKind;
171     ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
172                                               FD->getNumParams());
173     ResultType = FD->getResultType();
174     unsigned NumLists = FD->getNumTemplateParameterLists();
175     if (NumLists != 0) {
176       IsTemplateDecl = true;
177       IsTemplateSpecialization = true;
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     IsInstanceMethod = MD->isInstanceMethod();
197     IsClassMethod = !IsInstanceMethod;
198     break;
199   }
200   case Decl::FunctionTemplate: {
201     const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(ThisDecl);
202     Kind = FunctionKind;
203     IsTemplateDecl = true;
204     const FunctionDecl *FD = FTD->getTemplatedDecl();
205     ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
206                                               FD->getNumParams());
207     ResultType = FD->getResultType();
208     TemplateParameters = FTD->getTemplateParameters();
209     break;
210   }
211   case Decl::ClassTemplate: {
212     const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(ThisDecl);
213     Kind = ClassKind;
214     IsTemplateDecl = true;
215     TemplateParameters = CTD->getTemplateParameters();
216     break;
217   }
218   case Decl::ClassTemplatePartialSpecialization: {
219     const ClassTemplatePartialSpecializationDecl *CTPSD =
220         cast<ClassTemplatePartialSpecializationDecl>(ThisDecl);
221     Kind = ClassKind;
222     IsTemplateDecl = true;
223     IsTemplatePartialSpecialization = true;
224     TemplateParameters = CTPSD->getTemplateParameters();
225     break;
226   }
227   case Decl::ClassTemplateSpecialization:
228     Kind = ClassKind;
229     IsTemplateDecl = true;
230     IsTemplateSpecialization = true;
231     break;
232   case Decl::Record:
233   case Decl::CXXRecord:
234     Kind = ClassKind;
235     break;
236   case Decl::Var:
237   case Decl::Field:
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   case Decl::TypeAlias:
247     Kind = TypedefKind;
248     break;
249   case Decl::TypeAliasTemplate: {
250     const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(ThisDecl);
251     Kind = TypedefKind;
252     IsTemplateDecl = true;
253     TemplateParameters = TAT->getTemplateParameters();
254     break;
255   }
256   }
257 
258   IsFilled = true;
259 }
260 
261 } // end namespace comments
262 } // end namespace clang
263 
264