]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/lib/AST/Comment.cpp
MFC r244628:
[FreeBSD/stable/9.git] / contrib / llvm / tools / clang / lib / AST / Comment.cpp
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 (!CommentDecl) {
155     // If there is no declaration, the defaults is our only guess.
156     IsFilled = true;
157     return;
158   }
159   CurrentDecl = CommentDecl;
160   
161   Decl::Kind K = CommentDecl->getKind();
162   switch (K) {
163   default:
164     // Defaults are should be good for declarations we don't handle explicitly.
165     break;
166   case Decl::Function:
167   case Decl::CXXMethod:
168   case Decl::CXXConstructor:
169   case Decl::CXXDestructor:
170   case Decl::CXXConversion: {
171     const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl);
172     Kind = FunctionKind;
173     ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
174                                               FD->getNumParams());
175     ResultType = FD->getResultType();
176     unsigned NumLists = FD->getNumTemplateParameterLists();
177     if (NumLists != 0) {
178       TemplateKind = TemplateSpecialization;
179       TemplateParameters =
180           FD->getTemplateParameterList(NumLists - 1);
181     }
182
183     if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
184         K == Decl::CXXDestructor || K == Decl::CXXConversion) {
185       const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl);
186       IsInstanceMethod = MD->isInstance();
187       IsClassMethod = !IsInstanceMethod;
188     }
189     break;
190   }
191   case Decl::ObjCMethod: {
192     const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl);
193     Kind = FunctionKind;
194     ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
195                                               MD->param_size());
196     ResultType = MD->getResultType();
197     IsObjCMethod = true;
198     IsInstanceMethod = MD->isInstanceMethod();
199     IsClassMethod = !IsInstanceMethod;
200     break;
201   }
202   case Decl::FunctionTemplate: {
203     const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl);
204     Kind = FunctionKind;
205     TemplateKind = Template;
206     const FunctionDecl *FD = FTD->getTemplatedDecl();
207     ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
208                                               FD->getNumParams());
209     ResultType = FD->getResultType();
210     TemplateParameters = FTD->getTemplateParameters();
211     break;
212   }
213   case Decl::ClassTemplate: {
214     const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl);
215     Kind = ClassKind;
216     TemplateKind = Template;
217     TemplateParameters = CTD->getTemplateParameters();
218     break;
219   }
220   case Decl::ClassTemplatePartialSpecialization: {
221     const ClassTemplatePartialSpecializationDecl *CTPSD =
222         cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);
223     Kind = ClassKind;
224     TemplateKind = TemplatePartialSpecialization;
225     TemplateParameters = CTPSD->getTemplateParameters();
226     break;
227   }
228   case Decl::ClassTemplateSpecialization:
229     Kind = ClassKind;
230     TemplateKind = TemplateSpecialization;
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::EnumConstant:
239   case Decl::ObjCIvar:
240   case Decl::ObjCAtDefsField:
241     Kind = VariableKind;
242     break;
243   case Decl::Namespace:
244     Kind = NamespaceKind;
245     break;
246   case Decl::Typedef: {
247     Kind = TypedefKind;
248     // If this is a typedef to something we consider a function, extract
249     // arguments and return type.
250     const TypedefDecl *TD = cast<TypedefDecl>(CommentDecl);
251     const TypeSourceInfo *TSI = TD->getTypeSourceInfo();
252     if (!TSI)
253       break;
254     TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
255     while (true) {
256       TL = TL.IgnoreParens();
257       // Look through qualified types.
258       if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
259         TL = QualifiedTL->getUnqualifiedLoc();
260         continue;
261       }
262       // Look through pointer types.
263       if (PointerTypeLoc *PointerTL = dyn_cast<PointerTypeLoc>(&TL)) {
264         TL = PointerTL->getPointeeLoc().getUnqualifiedLoc();
265         continue;
266       }
267       if (BlockPointerTypeLoc *BlockPointerTL =
268               dyn_cast<BlockPointerTypeLoc>(&TL)) {
269         TL = BlockPointerTL->getPointeeLoc().getUnqualifiedLoc();
270         continue;
271       }
272       if (MemberPointerTypeLoc *MemberPointerTL =
273               dyn_cast<MemberPointerTypeLoc>(&TL)) {
274         TL = MemberPointerTL->getPointeeLoc().getUnqualifiedLoc();
275         continue;
276       }
277       // Is this a typedef for a function type?
278       if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
279         Kind = FunctionKind;
280         ArrayRef<ParmVarDecl *> Params = FTL->getParams();
281         ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
282                                                   Params.size());
283         ResultType = FTL->getResultLoc().getType();
284         break;
285       }
286       break;
287     }
288     break;
289   }
290   case Decl::TypeAlias:
291     Kind = TypedefKind;
292     break;
293   case Decl::TypeAliasTemplate: {
294     const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl);
295     Kind = TypedefKind;
296     TemplateKind = Template;
297     TemplateParameters = TAT->getTemplateParameters();
298     break;
299   }
300   case Decl::Enum:
301     Kind = EnumKind;
302     break;
303   }
304
305   IsFilled = true;
306 }
307
308 StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
309   assert(isParamIndexValid());
310   return FC->getThisDeclInfo()->ParamVars[getParamIndex()]->getName();
311 }
312
313 StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
314   assert(isPositionValid());
315   const TemplateParameterList *TPL = FC->getThisDeclInfo()->TemplateParameters;
316   for (unsigned i = 0, e = getDepth(); i != e; ++i) {
317     if (i == e-1)
318       return TPL->getParam(getIndex(i))->getName();
319     const NamedDecl *Param = TPL->getParam(getIndex(i));
320     if (const TemplateTemplateParmDecl *TTP =
321           dyn_cast<TemplateTemplateParmDecl>(Param))
322       TPL = TTP->getTemplateParameters();
323   }
324   return "";
325 }
326
327 } // end namespace comments
328 } // end namespace clang
329