• 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 
35 namespace {
36 struct good {};
37 struct bad {};
38 
39 template <typename T>
implements_child_begin_end(Comment::child_iterator (T::*)()const)40 good implements_child_begin_end(Comment::child_iterator (T::*)() const) {
41   return good();
42 }
43 
implements_child_begin_end(Comment::child_iterator (Comment::*)()const)44 static inline bad implements_child_begin_end(
45                       Comment::child_iterator (Comment::*)() const) {
46   return bad();
47 }
48 
49 #define ASSERT_IMPLEMENTS_child_begin(function) \
50   (void) sizeof(good(implements_child_begin_end(function)))
51 
CheckCommentASTNodes()52 static inline void CheckCommentASTNodes() {
53 #define ABSTRACT_COMMENT(COMMENT)
54 #define COMMENT(CLASS, PARENT) \
55   ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \
56   ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end);
57 #include "clang/AST/CommentNodes.inc"
58 #undef COMMENT
59 #undef ABSTRACT_COMMENT
60 }
61 
62 #undef ASSERT_IMPLEMENTS_child_begin
63 
64 } // end unnamed namespace
65 
child_begin() const66 Comment::child_iterator Comment::child_begin() const {
67   switch (getCommentKind()) {
68   case NoCommentKind: llvm_unreachable("comment without a kind");
69 #define ABSTRACT_COMMENT(COMMENT)
70 #define COMMENT(CLASS, PARENT) \
71   case CLASS##Kind: \
72     return static_cast<const CLASS *>(this)->child_begin();
73 #include "clang/AST/CommentNodes.inc"
74 #undef COMMENT
75 #undef ABSTRACT_COMMENT
76   }
77   llvm_unreachable("Unknown comment kind!");
78 }
79 
child_end() const80 Comment::child_iterator Comment::child_end() 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_end();
87 #include "clang/AST/CommentNodes.inc"
88 #undef COMMENT
89 #undef ABSTRACT_COMMENT
90   }
91   llvm_unreachable("Unknown comment kind!");
92 }
93 
isWhitespaceNoCache() const94 bool TextComment::isWhitespaceNoCache() const {
95   for (StringRef::const_iterator I = Text.begin(), E = Text.end();
96        I != E; ++I) {
97     const char C = *I;
98     if (C != ' ' && C != '\n' && C != '\r' &&
99         C != '\t' && C != '\f' && C != '\v')
100       return false;
101   }
102   return true;
103 }
104 
isWhitespaceNoCache() const105 bool ParagraphComment::isWhitespaceNoCache() const {
106   for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) {
107     if (const TextComment *TC = dyn_cast<TextComment>(*I)) {
108       if (!TC->isWhitespace())
109         return false;
110     } else
111       return false;
112   }
113   return true;
114 }
115 
getDirectionAsString(PassDirection D)116 const char *ParamCommandComment::getDirectionAsString(PassDirection D) {
117   switch (D) {
118   case ParamCommandComment::In:
119     return "[in]";
120   case ParamCommandComment::Out:
121     return "[out]";
122   case ParamCommandComment::InOut:
123     return "[in,out]";
124   }
125   llvm_unreachable("unknown PassDirection");
126 }
127 
fill()128 void DeclInfo::fill() {
129   assert(!IsFilled);
130 
131   // Set defaults.
132   Kind = OtherKind;
133   TemplateKind = NotTemplate;
134   IsObjCMethod = false;
135   IsInstanceMethod = false;
136   IsClassMethod = false;
137   ParamVars = ArrayRef<const ParmVarDecl *>();
138   TemplateParameters = NULL;
139 
140   if (!CommentDecl) {
141     // If there is no declaration, the defaults is our only guess.
142     IsFilled = true;
143     return;
144   }
145   CurrentDecl = CommentDecl;
146 
147   Decl::Kind K = CommentDecl->getKind();
148   switch (K) {
149   default:
150     // Defaults are should be good for declarations we don't handle explicitly.
151     break;
152   case Decl::Function:
153   case Decl::CXXMethod:
154   case Decl::CXXConstructor:
155   case Decl::CXXDestructor:
156   case Decl::CXXConversion: {
157     const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl);
158     Kind = FunctionKind;
159     ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
160                                               FD->getNumParams());
161     ResultType = FD->getResultType();
162     unsigned NumLists = FD->getNumTemplateParameterLists();
163     if (NumLists != 0) {
164       TemplateKind = TemplateSpecialization;
165       TemplateParameters =
166           FD->getTemplateParameterList(NumLists - 1);
167     }
168 
169     if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
170         K == Decl::CXXDestructor || K == Decl::CXXConversion) {
171       const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl);
172       IsInstanceMethod = MD->isInstance();
173       IsClassMethod = !IsInstanceMethod;
174     }
175     break;
176   }
177   case Decl::ObjCMethod: {
178     const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl);
179     Kind = FunctionKind;
180     ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
181                                               MD->param_size());
182     ResultType = MD->getResultType();
183     IsObjCMethod = true;
184     IsInstanceMethod = MD->isInstanceMethod();
185     IsClassMethod = !IsInstanceMethod;
186     break;
187   }
188   case Decl::FunctionTemplate: {
189     const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl);
190     Kind = FunctionKind;
191     TemplateKind = Template;
192     const FunctionDecl *FD = FTD->getTemplatedDecl();
193     ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
194                                               FD->getNumParams());
195     ResultType = FD->getResultType();
196     TemplateParameters = FTD->getTemplateParameters();
197     break;
198   }
199   case Decl::ClassTemplate: {
200     const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl);
201     Kind = ClassKind;
202     TemplateKind = Template;
203     TemplateParameters = CTD->getTemplateParameters();
204     break;
205   }
206   case Decl::ClassTemplatePartialSpecialization: {
207     const ClassTemplatePartialSpecializationDecl *CTPSD =
208         cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);
209     Kind = ClassKind;
210     TemplateKind = TemplatePartialSpecialization;
211     TemplateParameters = CTPSD->getTemplateParameters();
212     break;
213   }
214   case Decl::ClassTemplateSpecialization:
215     Kind = ClassKind;
216     TemplateKind = TemplateSpecialization;
217     break;
218   case Decl::Record:
219   case Decl::CXXRecord:
220     Kind = ClassKind;
221     break;
222   case Decl::Var:
223   case Decl::Field:
224   case Decl::EnumConstant:
225   case Decl::ObjCIvar:
226   case Decl::ObjCAtDefsField:
227     Kind = VariableKind;
228     break;
229   case Decl::Namespace:
230     Kind = NamespaceKind;
231     break;
232   case Decl::Typedef: {
233     Kind = TypedefKind;
234     // If this is a typedef to something we consider a function, extract
235     // arguments and return type.
236     const TypedefDecl *TD = cast<TypedefDecl>(CommentDecl);
237     const TypeSourceInfo *TSI = TD->getTypeSourceInfo();
238     if (!TSI)
239       break;
240     TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
241     while (true) {
242       TL = TL.IgnoreParens();
243       // Look through qualified types.
244       if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) {
245         TL = QualifiedTL.getUnqualifiedLoc();
246         continue;
247       }
248       // Look through pointer types.
249       if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) {
250         TL = PointerTL.getPointeeLoc().getUnqualifiedLoc();
251         continue;
252       }
253       if (BlockPointerTypeLoc BlockPointerTL =
254               TL.getAs<BlockPointerTypeLoc>()) {
255         TL = BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();
256         continue;
257       }
258       if (MemberPointerTypeLoc MemberPointerTL =
259               TL.getAs<MemberPointerTypeLoc>()) {
260         TL = MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();
261         continue;
262       }
263       // Is this a typedef for a function type?
264       if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
265         Kind = FunctionKind;
266         ArrayRef<ParmVarDecl *> Params = FTL.getParams();
267         ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
268                                                   Params.size());
269         ResultType = FTL.getResultLoc().getType();
270         break;
271       }
272       break;
273     }
274     break;
275   }
276   case Decl::TypeAlias:
277     Kind = TypedefKind;
278     break;
279   case Decl::TypeAliasTemplate: {
280     const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl);
281     Kind = TypedefKind;
282     TemplateKind = Template;
283     TemplateParameters = TAT->getTemplateParameters();
284     break;
285   }
286   case Decl::Enum:
287     Kind = EnumKind;
288     break;
289   }
290 
291   IsFilled = true;
292 }
293 
getParamName(const FullComment * FC) const294 StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
295   assert(isParamIndexValid());
296   return FC->getThisDeclInfo()->ParamVars[getParamIndex()]->getName();
297 }
298 
getParamName(const FullComment * FC) const299 StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
300   assert(isPositionValid());
301   const TemplateParameterList *TPL = FC->getThisDeclInfo()->TemplateParameters;
302   for (unsigned i = 0, e = getDepth(); i != e; ++i) {
303     if (i == e-1)
304       return TPL->getParam(getIndex(i))->getName();
305     const NamedDecl *Param = TPL->getParam(getIndex(i));
306     if (const TemplateTemplateParmDecl *TTP =
307           dyn_cast<TemplateTemplateParmDecl>(Param))
308       TPL = TTP->getTemplateParameters();
309   }
310   return "";
311 }
312 
313 } // end namespace comments
314 } // end namespace clang
315 
316