Comment.cpp revision c5b0054693b3b3cafe6a13549358c22e07fcd4ff
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
18namespace clang {
19namespace comments {
20
21const 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
35namespace {
36struct good {};
37struct bad {};
38
39template <typename T>
40good implements_child_begin_end(Comment::child_iterator (T::*)() const) {
41  return good();
42}
43
44static 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
52static 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
66Comment::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
80Comment::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
94bool 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
105bool 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
116const 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
128void 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 = None;
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
294StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
295  assert(isParamIndexValid());
296  if (isVarArgParam())
297    return "...";
298  return FC->getThisDeclInfo()->ParamVars[getParamIndex()]->getName();
299}
300
301StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
302  assert(isPositionValid());
303  const TemplateParameterList *TPL = FC->getThisDeclInfo()->TemplateParameters;
304  for (unsigned i = 0, e = getDepth(); i != e; ++i) {
305    if (i == e-1)
306      return TPL->getParam(getIndex(i))->getName();
307    const NamedDecl *Param = TPL->getParam(getIndex(i));
308    if (const TemplateTemplateParmDecl *TTP =
309          dyn_cast<TemplateTemplateParmDecl>(Param))
310      TPL = TTP->getTemplateParameters();
311  }
312  return "";
313}
314
315} // end namespace comments
316} // end namespace clang
317
318