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   TemplateKind = NotTemplate;
146   IsObjCMethod = false;
147   IsInstanceMethod = false;
148   IsClassMethod = false;
149   ParamVars = ArrayRef<const ParmVarDecl *>();
150   TemplateParameters = NULL;
151 
152   if (!ThisDecl) {
153     // If there is no declaration, the defaults is our only guess.
154     IsFilled = true;
155     return;
156   }
157 
158   Decl::Kind K = ThisDecl->getKind();
159   switch (K) {
160   default:
161     // Defaults are should be good for declarations we don't handle explicitly.
162     break;
163   case Decl::Function:
164   case Decl::CXXMethod:
165   case Decl::CXXConstructor:
166   case Decl::CXXDestructor:
167   case Decl::CXXConversion: {
168     const FunctionDecl *FD = cast<FunctionDecl>(ThisDecl);
169     Kind = FunctionKind;
170     ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
171                                               FD->getNumParams());
172     ResultType = FD->getResultType();
173     unsigned NumLists = FD->getNumTemplateParameterLists();
174     if (NumLists != 0) {
175       TemplateKind = TemplateSpecialization;
176       TemplateParameters =
177           FD->getTemplateParameterList(NumLists - 1);
178     }
179 
180     if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
181         K == Decl::CXXDestructor || K == Decl::CXXConversion) {
182       const CXXMethodDecl *MD = cast<CXXMethodDecl>(ThisDecl);
183       IsInstanceMethod = MD->isInstance();
184       IsClassMethod = !IsInstanceMethod;
185     }
186     break;
187   }
188   case Decl::ObjCMethod: {
189     const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(ThisDecl);
190     Kind = FunctionKind;
191     ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
192                                               MD->param_size());
193     ResultType = MD->getResultType();
194     IsObjCMethod = true;
195     IsInstanceMethod = MD->isInstanceMethod();
196     IsClassMethod = !IsInstanceMethod;
197     break;
198   }
199   case Decl::FunctionTemplate: {
200     const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(ThisDecl);
201     Kind = FunctionKind;
202     TemplateKind = Template;
203     const FunctionDecl *FD = FTD->getTemplatedDecl();
204     ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
205                                               FD->getNumParams());
206     ResultType = FD->getResultType();
207     TemplateParameters = FTD->getTemplateParameters();
208     break;
209   }
210   case Decl::ClassTemplate: {
211     const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(ThisDecl);
212     Kind = ClassKind;
213     TemplateKind = Template;
214     TemplateParameters = CTD->getTemplateParameters();
215     break;
216   }
217   case Decl::ClassTemplatePartialSpecialization: {
218     const ClassTemplatePartialSpecializationDecl *CTPSD =
219         cast<ClassTemplatePartialSpecializationDecl>(ThisDecl);
220     Kind = ClassKind;
221     TemplateKind = TemplatePartialSpecialization;
222     TemplateParameters = CTPSD->getTemplateParameters();
223     break;
224   }
225   case Decl::ClassTemplateSpecialization:
226     Kind = ClassKind;
227     TemplateKind = TemplateSpecialization;
228     break;
229   case Decl::Record:
230   case Decl::CXXRecord:
231     Kind = ClassKind;
232     break;
233   case Decl::Var:
234   case Decl::Field:
235   case Decl::EnumConstant:
236   case Decl::ObjCIvar:
237   case Decl::ObjCAtDefsField:
238     Kind = VariableKind;
239     break;
240   case Decl::Namespace:
241     Kind = NamespaceKind;
242     break;
243   case Decl::Typedef:
244   case Decl::TypeAlias:
245     Kind = TypedefKind;
246     break;
247   case Decl::TypeAliasTemplate: {
248     const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(ThisDecl);
249     Kind = TypedefKind;
250     TemplateKind = Template;
251     TemplateParameters = TAT->getTemplateParameters();
252     break;
253   }
254   case Decl::Enum:
255     Kind = EnumKind;
256     break;
257   }
258 
259   IsFilled = true;
260 }
261 
262 } // end namespace comments
263 } // end namespace clang
264 
265