1239313Sdim//===--- Comment.cpp - Comment AST node implementation --------------------===//
2239313Sdim//
3239313Sdim//                     The LLVM Compiler Infrastructure
4239313Sdim//
5239313Sdim// This file is distributed under the University of Illinois Open Source
6239313Sdim// License. See LICENSE.TXT for details.
7239313Sdim//
8239313Sdim//===----------------------------------------------------------------------===//
9239313Sdim
10243830Sdim#include "clang/AST/ASTContext.h"
11239313Sdim#include "clang/AST/Comment.h"
12239313Sdim#include "clang/AST/Decl.h"
13239313Sdim#include "clang/AST/DeclObjC.h"
14239313Sdim#include "clang/AST/DeclTemplate.h"
15263508Sdim#include "clang/Basic/CharInfo.h"
16239313Sdim#include "llvm/Support/ErrorHandling.h"
17239313Sdim#include "llvm/Support/raw_ostream.h"
18239313Sdim
19239313Sdimnamespace clang {
20239313Sdimnamespace comments {
21239313Sdim
22239313Sdimconst char *Comment::getCommentKindName() const {
23239313Sdim  switch (getCommentKind()) {
24239313Sdim  case NoCommentKind: return "NoCommentKind";
25239313Sdim#define ABSTRACT_COMMENT(COMMENT)
26239313Sdim#define COMMENT(CLASS, PARENT) \
27239313Sdim  case CLASS##Kind: \
28239313Sdim    return #CLASS;
29239313Sdim#include "clang/AST/CommentNodes.inc"
30239313Sdim#undef COMMENT
31239313Sdim#undef ABSTRACT_COMMENT
32239313Sdim  }
33239313Sdim  llvm_unreachable("Unknown comment kind!");
34239313Sdim}
35239313Sdim
36239313Sdimnamespace {
37239313Sdimstruct good {};
38239313Sdimstruct bad {};
39239313Sdim
40239313Sdimtemplate <typename T>
41239313Sdimgood implements_child_begin_end(Comment::child_iterator (T::*)() const) {
42239313Sdim  return good();
43239313Sdim}
44239313Sdim
45263508SdimLLVM_ATTRIBUTE_UNUSED
46239313Sdimstatic inline bad implements_child_begin_end(
47239313Sdim                      Comment::child_iterator (Comment::*)() const) {
48239313Sdim  return bad();
49239313Sdim}
50239313Sdim
51239313Sdim#define ASSERT_IMPLEMENTS_child_begin(function) \
52263508Sdim  (void) good(implements_child_begin_end(function))
53239313Sdim
54263508SdimLLVM_ATTRIBUTE_UNUSED
55239313Sdimstatic inline void CheckCommentASTNodes() {
56239313Sdim#define ABSTRACT_COMMENT(COMMENT)
57239313Sdim#define COMMENT(CLASS, PARENT) \
58239313Sdim  ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \
59239313Sdim  ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end);
60239313Sdim#include "clang/AST/CommentNodes.inc"
61239313Sdim#undef COMMENT
62239313Sdim#undef ABSTRACT_COMMENT
63239313Sdim}
64239313Sdim
65239313Sdim#undef ASSERT_IMPLEMENTS_child_begin
66239313Sdim
67239313Sdim} // end unnamed namespace
68239313Sdim
69239313SdimComment::child_iterator Comment::child_begin() const {
70239313Sdim  switch (getCommentKind()) {
71239313Sdim  case NoCommentKind: llvm_unreachable("comment without a kind");
72239313Sdim#define ABSTRACT_COMMENT(COMMENT)
73239313Sdim#define COMMENT(CLASS, PARENT) \
74239313Sdim  case CLASS##Kind: \
75239313Sdim    return static_cast<const CLASS *>(this)->child_begin();
76239313Sdim#include "clang/AST/CommentNodes.inc"
77239313Sdim#undef COMMENT
78239313Sdim#undef ABSTRACT_COMMENT
79239313Sdim  }
80239313Sdim  llvm_unreachable("Unknown comment kind!");
81239313Sdim}
82239313Sdim
83239313SdimComment::child_iterator Comment::child_end() const {
84239313Sdim  switch (getCommentKind()) {
85239313Sdim  case NoCommentKind: llvm_unreachable("comment without a kind");
86239313Sdim#define ABSTRACT_COMMENT(COMMENT)
87239313Sdim#define COMMENT(CLASS, PARENT) \
88239313Sdim  case CLASS##Kind: \
89239313Sdim    return static_cast<const CLASS *>(this)->child_end();
90239313Sdim#include "clang/AST/CommentNodes.inc"
91239313Sdim#undef COMMENT
92239313Sdim#undef ABSTRACT_COMMENT
93239313Sdim  }
94239313Sdim  llvm_unreachable("Unknown comment kind!");
95239313Sdim}
96239313Sdim
97239313Sdimbool TextComment::isWhitespaceNoCache() const {
98239313Sdim  for (StringRef::const_iterator I = Text.begin(), E = Text.end();
99239313Sdim       I != E; ++I) {
100263508Sdim    if (!clang::isWhitespace(*I))
101239313Sdim      return false;
102239313Sdim  }
103239313Sdim  return true;
104239313Sdim}
105239313Sdim
106239313Sdimbool ParagraphComment::isWhitespaceNoCache() const {
107239313Sdim  for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) {
108239313Sdim    if (const TextComment *TC = dyn_cast<TextComment>(*I)) {
109239313Sdim      if (!TC->isWhitespace())
110239313Sdim        return false;
111239313Sdim    } else
112239313Sdim      return false;
113239313Sdim  }
114239313Sdim  return true;
115239313Sdim}
116239313Sdim
117239313Sdimconst char *ParamCommandComment::getDirectionAsString(PassDirection D) {
118239313Sdim  switch (D) {
119239313Sdim  case ParamCommandComment::In:
120239313Sdim    return "[in]";
121239313Sdim  case ParamCommandComment::Out:
122239313Sdim    return "[out]";
123239313Sdim  case ParamCommandComment::InOut:
124239313Sdim    return "[in,out]";
125239313Sdim  }
126239313Sdim  llvm_unreachable("unknown PassDirection");
127239313Sdim}
128239313Sdim
129239313Sdimvoid DeclInfo::fill() {
130239313Sdim  assert(!IsFilled);
131239313Sdim
132239313Sdim  // Set defaults.
133239313Sdim  Kind = OtherKind;
134239313Sdim  TemplateKind = NotTemplate;
135239313Sdim  IsObjCMethod = false;
136239313Sdim  IsInstanceMethod = false;
137239313Sdim  IsClassMethod = false;
138251662Sdim  ParamVars = None;
139239313Sdim  TemplateParameters = NULL;
140239313Sdim
141243830Sdim  if (!CommentDecl) {
142239313Sdim    // If there is no declaration, the defaults is our only guess.
143239313Sdim    IsFilled = true;
144239313Sdim    return;
145239313Sdim  }
146243830Sdim  CurrentDecl = CommentDecl;
147243830Sdim
148243830Sdim  Decl::Kind K = CommentDecl->getKind();
149239313Sdim  switch (K) {
150239313Sdim  default:
151239313Sdim    // Defaults are should be good for declarations we don't handle explicitly.
152239313Sdim    break;
153239313Sdim  case Decl::Function:
154239313Sdim  case Decl::CXXMethod:
155239313Sdim  case Decl::CXXConstructor:
156239313Sdim  case Decl::CXXDestructor:
157239313Sdim  case Decl::CXXConversion: {
158243830Sdim    const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl);
159239313Sdim    Kind = FunctionKind;
160239313Sdim    ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
161239313Sdim                                              FD->getNumParams());
162239313Sdim    ResultType = FD->getResultType();
163239313Sdim    unsigned NumLists = FD->getNumTemplateParameterLists();
164239313Sdim    if (NumLists != 0) {
165239313Sdim      TemplateKind = TemplateSpecialization;
166239313Sdim      TemplateParameters =
167239313Sdim          FD->getTemplateParameterList(NumLists - 1);
168239313Sdim    }
169239313Sdim
170239313Sdim    if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
171239313Sdim        K == Decl::CXXDestructor || K == Decl::CXXConversion) {
172243830Sdim      const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl);
173239313Sdim      IsInstanceMethod = MD->isInstance();
174239313Sdim      IsClassMethod = !IsInstanceMethod;
175239313Sdim    }
176239313Sdim    break;
177239313Sdim  }
178239313Sdim  case Decl::ObjCMethod: {
179243830Sdim    const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl);
180239313Sdim    Kind = FunctionKind;
181239313Sdim    ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
182239313Sdim                                              MD->param_size());
183239313Sdim    ResultType = MD->getResultType();
184239313Sdim    IsObjCMethod = true;
185239313Sdim    IsInstanceMethod = MD->isInstanceMethod();
186239313Sdim    IsClassMethod = !IsInstanceMethod;
187239313Sdim    break;
188239313Sdim  }
189239313Sdim  case Decl::FunctionTemplate: {
190243830Sdim    const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl);
191239313Sdim    Kind = FunctionKind;
192239313Sdim    TemplateKind = Template;
193239313Sdim    const FunctionDecl *FD = FTD->getTemplatedDecl();
194239313Sdim    ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
195239313Sdim                                              FD->getNumParams());
196239313Sdim    ResultType = FD->getResultType();
197239313Sdim    TemplateParameters = FTD->getTemplateParameters();
198239313Sdim    break;
199239313Sdim  }
200239313Sdim  case Decl::ClassTemplate: {
201243830Sdim    const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl);
202239313Sdim    Kind = ClassKind;
203239313Sdim    TemplateKind = Template;
204239313Sdim    TemplateParameters = CTD->getTemplateParameters();
205239313Sdim    break;
206239313Sdim  }
207239313Sdim  case Decl::ClassTemplatePartialSpecialization: {
208239313Sdim    const ClassTemplatePartialSpecializationDecl *CTPSD =
209243830Sdim        cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);
210239313Sdim    Kind = ClassKind;
211239313Sdim    TemplateKind = TemplatePartialSpecialization;
212239313Sdim    TemplateParameters = CTPSD->getTemplateParameters();
213239313Sdim    break;
214239313Sdim  }
215239313Sdim  case Decl::ClassTemplateSpecialization:
216239313Sdim    Kind = ClassKind;
217239313Sdim    TemplateKind = TemplateSpecialization;
218239313Sdim    break;
219239313Sdim  case Decl::Record:
220239313Sdim  case Decl::CXXRecord:
221239313Sdim    Kind = ClassKind;
222239313Sdim    break;
223239313Sdim  case Decl::Var:
224239313Sdim  case Decl::Field:
225239313Sdim  case Decl::EnumConstant:
226239313Sdim  case Decl::ObjCIvar:
227239313Sdim  case Decl::ObjCAtDefsField:
228239313Sdim    Kind = VariableKind;
229239313Sdim    break;
230239313Sdim  case Decl::Namespace:
231239313Sdim    Kind = NamespaceKind;
232239313Sdim    break;
233243830Sdim  case Decl::Typedef: {
234243830Sdim    Kind = TypedefKind;
235243830Sdim    // If this is a typedef to something we consider a function, extract
236243830Sdim    // arguments and return type.
237243830Sdim    const TypedefDecl *TD = cast<TypedefDecl>(CommentDecl);
238243830Sdim    const TypeSourceInfo *TSI = TD->getTypeSourceInfo();
239243830Sdim    if (!TSI)
240243830Sdim      break;
241243830Sdim    TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
242243830Sdim    while (true) {
243243830Sdim      TL = TL.IgnoreParens();
244243830Sdim      // Look through qualified types.
245249423Sdim      if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) {
246249423Sdim        TL = QualifiedTL.getUnqualifiedLoc();
247243830Sdim        continue;
248243830Sdim      }
249243830Sdim      // Look through pointer types.
250249423Sdim      if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) {
251249423Sdim        TL = PointerTL.getPointeeLoc().getUnqualifiedLoc();
252243830Sdim        continue;
253243830Sdim      }
254249423Sdim      if (BlockPointerTypeLoc BlockPointerTL =
255249423Sdim              TL.getAs<BlockPointerTypeLoc>()) {
256249423Sdim        TL = BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();
257243830Sdim        continue;
258243830Sdim      }
259249423Sdim      if (MemberPointerTypeLoc MemberPointerTL =
260249423Sdim              TL.getAs<MemberPointerTypeLoc>()) {
261249423Sdim        TL = MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();
262243830Sdim        continue;
263243830Sdim      }
264243830Sdim      // Is this a typedef for a function type?
265249423Sdim      if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
266243830Sdim        Kind = FunctionKind;
267249423Sdim        ArrayRef<ParmVarDecl *> Params = FTL.getParams();
268243830Sdim        ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
269243830Sdim                                                  Params.size());
270249423Sdim        ResultType = FTL.getResultLoc().getType();
271243830Sdim        break;
272243830Sdim      }
273243830Sdim      break;
274243830Sdim    }
275243830Sdim    break;
276243830Sdim  }
277239313Sdim  case Decl::TypeAlias:
278239313Sdim    Kind = TypedefKind;
279239313Sdim    break;
280239313Sdim  case Decl::TypeAliasTemplate: {
281243830Sdim    const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl);
282239313Sdim    Kind = TypedefKind;
283239313Sdim    TemplateKind = Template;
284239313Sdim    TemplateParameters = TAT->getTemplateParameters();
285239313Sdim    break;
286239313Sdim  }
287239313Sdim  case Decl::Enum:
288239313Sdim    Kind = EnumKind;
289239313Sdim    break;
290239313Sdim  }
291239313Sdim
292239313Sdim  IsFilled = true;
293239313Sdim}
294239313Sdim
295243830SdimStringRef ParamCommandComment::getParamName(const FullComment *FC) const {
296243830Sdim  assert(isParamIndexValid());
297263508Sdim  if (isVarArgParam())
298263508Sdim    return "...";
299263508Sdim  return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName();
300243830Sdim}
301243830Sdim
302243830SdimStringRef TParamCommandComment::getParamName(const FullComment *FC) const {
303243830Sdim  assert(isPositionValid());
304263508Sdim  const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;
305243830Sdim  for (unsigned i = 0, e = getDepth(); i != e; ++i) {
306243830Sdim    if (i == e-1)
307243830Sdim      return TPL->getParam(getIndex(i))->getName();
308243830Sdim    const NamedDecl *Param = TPL->getParam(getIndex(i));
309243830Sdim    if (const TemplateTemplateParmDecl *TTP =
310243830Sdim          dyn_cast<TemplateTemplateParmDecl>(Param))
311243830Sdim      TPL = TTP->getTemplateParameters();
312243830Sdim  }
313243830Sdim  return "";
314243830Sdim}
315243830Sdim
316239313Sdim} // end namespace comments
317239313Sdim} // end namespace clang
318239313Sdim
319