Home | History | Annotate | Download | only in AST
      1 //===--- Comment.h - Comment AST nodes --------------------------*- C++ -*-===//
      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 //  This file defines comment AST nodes.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_CLANG_AST_COMMENT_H
     15 #define LLVM_CLANG_AST_COMMENT_H
     16 
     17 #include "clang/Basic/SourceLocation.h"
     18 #include "clang/AST/Type.h"
     19 #include "clang/AST/CommentCommandTraits.h"
     20 #include "llvm/ADT/ArrayRef.h"
     21 #include "llvm/ADT/StringRef.h"
     22 
     23 namespace clang {
     24 class Decl;
     25 class ParmVarDecl;
     26 class TemplateParameterList;
     27 
     28 namespace comments {
     29 
     30 /// Any part of the comment.
     31 /// Abstract class.
     32 class Comment {
     33 protected:
     34   /// Preferred location to show caret.
     35   SourceLocation Loc;
     36 
     37   /// Source range of this AST node.
     38   SourceRange Range;
     39 
     40   class CommentBitfields {
     41     friend class Comment;
     42 
     43     /// Type of this AST node.
     44     unsigned Kind : 8;
     45   };
     46   enum { NumCommentBits = 8 };
     47 
     48   class InlineContentCommentBitfields {
     49     friend class InlineContentComment;
     50 
     51     unsigned : NumCommentBits;
     52 
     53     /// True if there is a newline after this inline content node.
     54     /// (There is no separate AST node for a newline.)
     55     unsigned HasTrailingNewline : 1;
     56   };
     57   enum { NumInlineContentCommentBits = NumCommentBits + 1 };
     58 
     59   class TextCommentBitfields {
     60     friend class TextComment;
     61 
     62     unsigned : NumInlineContentCommentBits;
     63 
     64     /// True if \c IsWhitespace field contains a valid value.
     65     mutable unsigned IsWhitespaceValid : 1;
     66 
     67     /// True if this comment AST node contains only whitespace.
     68     mutable unsigned IsWhitespace : 1;
     69   };
     70   enum { NumTextCommentBits = NumInlineContentCommentBits + 2 };
     71 
     72   class InlineCommandCommentBitfields {
     73     friend class InlineCommandComment;
     74 
     75     unsigned : NumInlineContentCommentBits;
     76 
     77     unsigned RenderKind : 2;
     78     unsigned CommandID : 8;
     79   };
     80   enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 10 };
     81 
     82   class HTMLStartTagCommentBitfields {
     83     friend class HTMLStartTagComment;
     84 
     85     unsigned : NumInlineContentCommentBits;
     86 
     87     /// True if this tag is self-closing (e. g., <br />).  This is based on tag
     88     /// spelling in comment (plain <br> would not set this flag).
     89     unsigned IsSelfClosing : 1;
     90   };
     91   enum { NumHTMLStartTagCommentBits = NumInlineContentCommentBits + 1 };
     92 
     93   class ParagraphCommentBitfields {
     94     friend class ParagraphComment;
     95 
     96     unsigned : NumCommentBits;
     97 
     98     /// True if \c IsWhitespace field contains a valid value.
     99     mutable unsigned IsWhitespaceValid : 1;
    100 
    101     /// True if this comment AST node contains only whitespace.
    102     mutable unsigned IsWhitespace : 1;
    103   };
    104   enum { NumParagraphCommentBits = NumCommentBits + 2 };
    105 
    106   class BlockCommandCommentBitfields {
    107     friend class BlockCommandComment;
    108 
    109     unsigned : NumCommentBits;
    110 
    111     unsigned CommandID : 8;
    112   };
    113   enum { NumBlockCommandCommentBits = NumCommentBits + 8 };
    114 
    115   class ParamCommandCommentBitfields {
    116     friend class ParamCommandComment;
    117 
    118     unsigned : NumBlockCommandCommentBits;
    119 
    120     /// Parameter passing direction, see ParamCommandComment::PassDirection.
    121     unsigned Direction : 2;
    122 
    123     /// True if direction was specified explicitly in the comment.
    124     unsigned IsDirectionExplicit : 1;
    125   };
    126   enum { NumParamCommandCommentBits = NumBlockCommandCommentBits + 3 };
    127 
    128   union {
    129     CommentBitfields CommentBits;
    130     InlineContentCommentBitfields InlineContentCommentBits;
    131     TextCommentBitfields TextCommentBits;
    132     InlineCommandCommentBitfields InlineCommandCommentBits;
    133     HTMLStartTagCommentBitfields HTMLStartTagCommentBits;
    134     ParagraphCommentBitfields ParagraphCommentBits;
    135     BlockCommandCommentBitfields BlockCommandCommentBits;
    136     ParamCommandCommentBitfields ParamCommandCommentBits;
    137   };
    138 
    139   void setSourceRange(SourceRange SR) {
    140     Range = SR;
    141   }
    142 
    143   void setLocation(SourceLocation L) {
    144     Loc = L;
    145   }
    146 
    147 public:
    148   enum CommentKind {
    149     NoCommentKind = 0,
    150 #define COMMENT(CLASS, PARENT) CLASS##Kind,
    151 #define COMMENT_RANGE(BASE, FIRST, LAST) \
    152     First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind,
    153 #define LAST_COMMENT_RANGE(BASE, FIRST, LAST) \
    154     First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind
    155 #define ABSTRACT_COMMENT(COMMENT)
    156 #include "clang/AST/CommentNodes.inc"
    157   };
    158 
    159   Comment(CommentKind K,
    160           SourceLocation LocBegin,
    161           SourceLocation LocEnd) :
    162       Loc(LocBegin), Range(SourceRange(LocBegin, LocEnd)) {
    163     CommentBits.Kind = K;
    164   }
    165 
    166   CommentKind getCommentKind() const {
    167     return static_cast<CommentKind>(CommentBits.Kind);
    168   }
    169 
    170   const char *getCommentKindName() const;
    171 
    172   LLVM_ATTRIBUTE_USED void dump() const;
    173   LLVM_ATTRIBUTE_USED void dump(const ASTContext &Context) const;
    174   void dump(llvm::raw_ostream &OS, const CommandTraits *Traits,
    175             const SourceManager *SM) const;
    176 
    177   static bool classof(const Comment *) { return true; }
    178 
    179   SourceRange getSourceRange() const LLVM_READONLY { return Range; }
    180 
    181   SourceLocation getLocStart() const LLVM_READONLY {
    182     return Range.getBegin();
    183   }
    184 
    185   SourceLocation getLocEnd() const LLVM_READONLY {
    186     return Range.getEnd();
    187   }
    188 
    189   SourceLocation getLocation() const LLVM_READONLY { return Loc; }
    190 
    191   typedef Comment * const *child_iterator;
    192 
    193   child_iterator child_begin() const;
    194   child_iterator child_end() const;
    195 
    196   // TODO: const child iterator
    197 
    198   unsigned child_count() const {
    199     return child_end() - child_begin();
    200   }
    201 };
    202 
    203 /// Inline content (contained within a block).
    204 /// Abstract class.
    205 class InlineContentComment : public Comment {
    206 protected:
    207   InlineContentComment(CommentKind K,
    208                        SourceLocation LocBegin,
    209                        SourceLocation LocEnd) :
    210       Comment(K, LocBegin, LocEnd) {
    211     InlineContentCommentBits.HasTrailingNewline = 0;
    212   }
    213 
    214 public:
    215   static bool classof(const Comment *C) {
    216     return C->getCommentKind() >= FirstInlineContentCommentConstant &&
    217            C->getCommentKind() <= LastInlineContentCommentConstant;
    218   }
    219 
    220   static bool classof(const InlineContentComment *) { return true; }
    221 
    222   void addTrailingNewline() {
    223     InlineContentCommentBits.HasTrailingNewline = 1;
    224   }
    225 
    226   bool hasTrailingNewline() const {
    227     return InlineContentCommentBits.HasTrailingNewline;
    228   }
    229 };
    230 
    231 /// Plain text.
    232 class TextComment : public InlineContentComment {
    233   StringRef Text;
    234 
    235 public:
    236   TextComment(SourceLocation LocBegin,
    237               SourceLocation LocEnd,
    238               StringRef Text) :
    239       InlineContentComment(TextCommentKind, LocBegin, LocEnd),
    240       Text(Text) {
    241     TextCommentBits.IsWhitespaceValid = false;
    242   }
    243 
    244   static bool classof(const Comment *C) {
    245     return C->getCommentKind() == TextCommentKind;
    246   }
    247 
    248   static bool classof(const TextComment *) { return true; }
    249 
    250   child_iterator child_begin() const { return NULL; }
    251 
    252   child_iterator child_end() const { return NULL; }
    253 
    254   StringRef getText() const LLVM_READONLY { return Text; }
    255 
    256   bool isWhitespace() const {
    257     if (TextCommentBits.IsWhitespaceValid)
    258       return TextCommentBits.IsWhitespace;
    259 
    260     TextCommentBits.IsWhitespace = isWhitespaceNoCache();
    261     TextCommentBits.IsWhitespaceValid = true;
    262     return TextCommentBits.IsWhitespace;
    263   }
    264 
    265 private:
    266   bool isWhitespaceNoCache() const;
    267 };
    268 
    269 /// A command with word-like arguments that is considered inline content.
    270 class InlineCommandComment : public InlineContentComment {
    271 public:
    272   struct Argument {
    273     SourceRange Range;
    274     StringRef Text;
    275 
    276     Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { }
    277   };
    278 
    279   /// The most appropriate rendering mode for this command, chosen on command
    280   /// semantics in Doxygen.
    281   enum RenderKind {
    282     RenderNormal,
    283     RenderBold,
    284     RenderMonospaced,
    285     RenderEmphasized
    286   };
    287 
    288 protected:
    289   /// Command arguments.
    290   llvm::ArrayRef<Argument> Args;
    291 
    292 public:
    293   InlineCommandComment(SourceLocation LocBegin,
    294                        SourceLocation LocEnd,
    295                        unsigned CommandID,
    296                        RenderKind RK,
    297                        llvm::ArrayRef<Argument> Args) :
    298       InlineContentComment(InlineCommandCommentKind, LocBegin, LocEnd),
    299       Args(Args) {
    300     InlineCommandCommentBits.RenderKind = RK;
    301     InlineCommandCommentBits.CommandID = CommandID;
    302   }
    303 
    304   static bool classof(const Comment *C) {
    305     return C->getCommentKind() == InlineCommandCommentKind;
    306   }
    307 
    308   static bool classof(const InlineCommandComment *) { return true; }
    309 
    310   child_iterator child_begin() const { return NULL; }
    311 
    312   child_iterator child_end() const { return NULL; }
    313 
    314   unsigned getCommandID() const {
    315     return InlineCommandCommentBits.CommandID;
    316   }
    317 
    318   StringRef getCommandName(const CommandTraits &Traits) const {
    319     return Traits.getCommandInfo(getCommandID())->Name;
    320   }
    321 
    322   SourceRange getCommandNameRange() const {
    323     return SourceRange(getLocStart().getLocWithOffset(-1),
    324                        getLocEnd());
    325   }
    326 
    327   RenderKind getRenderKind() const {
    328     return static_cast<RenderKind>(InlineCommandCommentBits.RenderKind);
    329   }
    330 
    331   unsigned getNumArgs() const {
    332     return Args.size();
    333   }
    334 
    335   StringRef getArgText(unsigned Idx) const {
    336     return Args[Idx].Text;
    337   }
    338 
    339   SourceRange getArgRange(unsigned Idx) const {
    340     return Args[Idx].Range;
    341   }
    342 };
    343 
    344 /// Abstract class for opening and closing HTML tags.  HTML tags are always
    345 /// treated as inline content (regardless HTML semantics); opening and closing
    346 /// tags are not matched.
    347 class HTMLTagComment : public InlineContentComment {
    348 protected:
    349   StringRef TagName;
    350   SourceRange TagNameRange;
    351 
    352   HTMLTagComment(CommentKind K,
    353                  SourceLocation LocBegin,
    354                  SourceLocation LocEnd,
    355                  StringRef TagName,
    356                  SourceLocation TagNameBegin,
    357                  SourceLocation TagNameEnd) :
    358       InlineContentComment(K, LocBegin, LocEnd),
    359       TagName(TagName),
    360       TagNameRange(TagNameBegin, TagNameEnd) {
    361     setLocation(TagNameBegin);
    362   }
    363 
    364 public:
    365   static bool classof(const Comment *C) {
    366     return C->getCommentKind() >= FirstHTMLTagCommentConstant &&
    367            C->getCommentKind() <= LastHTMLTagCommentConstant;
    368   }
    369 
    370   static bool classof(const HTMLTagComment *) { return true; }
    371 
    372   StringRef getTagName() const LLVM_READONLY { return TagName; }
    373 
    374   SourceRange getTagNameSourceRange() const LLVM_READONLY {
    375     SourceLocation L = getLocation();
    376     return SourceRange(L.getLocWithOffset(1),
    377                        L.getLocWithOffset(1 + TagName.size()));
    378   }
    379 };
    380 
    381 /// An opening HTML tag with attributes.
    382 class HTMLStartTagComment : public HTMLTagComment {
    383 public:
    384   class Attribute {
    385   public:
    386     SourceLocation NameLocBegin;
    387     StringRef Name;
    388 
    389     SourceLocation EqualsLoc;
    390 
    391     SourceRange ValueRange;
    392     StringRef Value;
    393 
    394     Attribute() { }
    395 
    396     Attribute(SourceLocation NameLocBegin, StringRef Name) :
    397         NameLocBegin(NameLocBegin), Name(Name),
    398         EqualsLoc(SourceLocation()),
    399         ValueRange(SourceRange()), Value(StringRef())
    400     { }
    401 
    402     Attribute(SourceLocation NameLocBegin, StringRef Name,
    403               SourceLocation EqualsLoc,
    404               SourceRange ValueRange, StringRef Value) :
    405         NameLocBegin(NameLocBegin), Name(Name),
    406         EqualsLoc(EqualsLoc),
    407         ValueRange(ValueRange), Value(Value)
    408     { }
    409 
    410     SourceLocation getNameLocEnd() const {
    411       return NameLocBegin.getLocWithOffset(Name.size());
    412     }
    413 
    414     SourceRange getNameRange() const {
    415       return SourceRange(NameLocBegin, getNameLocEnd());
    416     }
    417   };
    418 
    419 private:
    420   ArrayRef<Attribute> Attributes;
    421 
    422 public:
    423   HTMLStartTagComment(SourceLocation LocBegin,
    424                       StringRef TagName) :
    425       HTMLTagComment(HTMLStartTagCommentKind,
    426                      LocBegin, LocBegin.getLocWithOffset(1 + TagName.size()),
    427                      TagName,
    428                      LocBegin.getLocWithOffset(1),
    429                      LocBegin.getLocWithOffset(1 + TagName.size())) {
    430     HTMLStartTagCommentBits.IsSelfClosing = false;
    431   }
    432 
    433   static bool classof(const Comment *C) {
    434     return C->getCommentKind() == HTMLStartTagCommentKind;
    435   }
    436 
    437   static bool classof(const HTMLStartTagComment *) { return true; }
    438 
    439   child_iterator child_begin() const { return NULL; }
    440 
    441   child_iterator child_end() const { return NULL; }
    442 
    443   unsigned getNumAttrs() const {
    444     return Attributes.size();
    445   }
    446 
    447   const Attribute &getAttr(unsigned Idx) const {
    448     return Attributes[Idx];
    449   }
    450 
    451   void setAttrs(ArrayRef<Attribute> Attrs) {
    452     Attributes = Attrs;
    453     if (!Attrs.empty()) {
    454       const Attribute &Attr = Attrs.back();
    455       SourceLocation L = Attr.ValueRange.getEnd();
    456       if (L.isValid())
    457         Range.setEnd(L);
    458       else {
    459         Range.setEnd(Attr.getNameLocEnd());
    460       }
    461     }
    462   }
    463 
    464   void setGreaterLoc(SourceLocation GreaterLoc) {
    465     Range.setEnd(GreaterLoc);
    466   }
    467 
    468   bool isSelfClosing() const {
    469     return HTMLStartTagCommentBits.IsSelfClosing;
    470   }
    471 
    472   void setSelfClosing() {
    473     HTMLStartTagCommentBits.IsSelfClosing = true;
    474   }
    475 };
    476 
    477 /// A closing HTML tag.
    478 class HTMLEndTagComment : public HTMLTagComment {
    479 public:
    480   HTMLEndTagComment(SourceLocation LocBegin,
    481                     SourceLocation LocEnd,
    482                     StringRef TagName) :
    483       HTMLTagComment(HTMLEndTagCommentKind,
    484                      LocBegin, LocEnd,
    485                      TagName,
    486                      LocBegin.getLocWithOffset(2),
    487                      LocBegin.getLocWithOffset(2 + TagName.size()))
    488   { }
    489 
    490   static bool classof(const Comment *C) {
    491     return C->getCommentKind() == HTMLEndTagCommentKind;
    492   }
    493 
    494   static bool classof(const HTMLEndTagComment *) { return true; }
    495 
    496   child_iterator child_begin() const { return NULL; }
    497 
    498   child_iterator child_end() const { return NULL; }
    499 };
    500 
    501 /// Block content (contains inline content).
    502 /// Abstract class.
    503 class BlockContentComment : public Comment {
    504 protected:
    505   BlockContentComment(CommentKind K,
    506                       SourceLocation LocBegin,
    507                       SourceLocation LocEnd) :
    508       Comment(K, LocBegin, LocEnd)
    509   { }
    510 
    511 public:
    512   static bool classof(const Comment *C) {
    513     return C->getCommentKind() >= FirstBlockContentCommentConstant &&
    514            C->getCommentKind() <= LastBlockContentCommentConstant;
    515   }
    516 
    517   static bool classof(const BlockContentComment *) { return true; }
    518 };
    519 
    520 /// A single paragraph that contains inline content.
    521 class ParagraphComment : public BlockContentComment {
    522   llvm::ArrayRef<InlineContentComment *> Content;
    523 
    524 public:
    525   ParagraphComment(llvm::ArrayRef<InlineContentComment *> Content) :
    526       BlockContentComment(ParagraphCommentKind,
    527                           SourceLocation(),
    528                           SourceLocation()),
    529       Content(Content) {
    530     if (Content.empty()) {
    531       ParagraphCommentBits.IsWhitespace = true;
    532       ParagraphCommentBits.IsWhitespaceValid = true;
    533       return;
    534     }
    535 
    536     ParagraphCommentBits.IsWhitespaceValid = false;
    537 
    538     setSourceRange(SourceRange(Content.front()->getLocStart(),
    539                                Content.back()->getLocEnd()));
    540     setLocation(Content.front()->getLocStart());
    541   }
    542 
    543   static bool classof(const Comment *C) {
    544     return C->getCommentKind() == ParagraphCommentKind;
    545   }
    546 
    547   static bool classof(const ParagraphComment *) { return true; }
    548 
    549   child_iterator child_begin() const {
    550     return reinterpret_cast<child_iterator>(Content.begin());
    551   }
    552 
    553   child_iterator child_end() const {
    554     return reinterpret_cast<child_iterator>(Content.end());
    555   }
    556 
    557   bool isWhitespace() const {
    558     if (ParagraphCommentBits.IsWhitespaceValid)
    559       return ParagraphCommentBits.IsWhitespace;
    560 
    561     ParagraphCommentBits.IsWhitespace = isWhitespaceNoCache();
    562     ParagraphCommentBits.IsWhitespaceValid = true;
    563     return ParagraphCommentBits.IsWhitespace;
    564   }
    565 
    566 private:
    567   bool isWhitespaceNoCache() const;
    568 };
    569 
    570 /// A command that has zero or more word-like arguments (number of word-like
    571 /// arguments depends on command name) and a paragraph as an argument
    572 /// (e. g., \\brief).
    573 class BlockCommandComment : public BlockContentComment {
    574 public:
    575   struct Argument {
    576     SourceRange Range;
    577     StringRef Text;
    578 
    579     Argument() { }
    580     Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { }
    581   };
    582 
    583 protected:
    584   /// Word-like arguments.
    585   llvm::ArrayRef<Argument> Args;
    586 
    587   /// Paragraph argument.
    588   ParagraphComment *Paragraph;
    589 
    590   BlockCommandComment(CommentKind K,
    591                       SourceLocation LocBegin,
    592                       SourceLocation LocEnd,
    593                       unsigned CommandID) :
    594       BlockContentComment(K, LocBegin, LocEnd),
    595       Paragraph(NULL) {
    596     setLocation(getCommandNameBeginLoc());
    597     BlockCommandCommentBits.CommandID = CommandID;
    598   }
    599 
    600 public:
    601   BlockCommandComment(SourceLocation LocBegin,
    602                       SourceLocation LocEnd,
    603                       unsigned CommandID) :
    604       BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd),
    605       Paragraph(NULL) {
    606     setLocation(getCommandNameBeginLoc());
    607     BlockCommandCommentBits.CommandID = CommandID;
    608   }
    609 
    610   static bool classof(const Comment *C) {
    611     return C->getCommentKind() >= FirstBlockCommandCommentConstant &&
    612            C->getCommentKind() <= LastBlockCommandCommentConstant;
    613   }
    614 
    615   static bool classof(const BlockCommandComment *) { return true; }
    616 
    617   child_iterator child_begin() const {
    618     return reinterpret_cast<child_iterator>(&Paragraph);
    619   }
    620 
    621   child_iterator child_end() const {
    622     return reinterpret_cast<child_iterator>(&Paragraph + 1);
    623   }
    624 
    625   unsigned getCommandID() const {
    626     return BlockCommandCommentBits.CommandID;
    627   }
    628 
    629   StringRef getCommandName(const CommandTraits &Traits) const {
    630     return Traits.getCommandInfo(getCommandID())->Name;
    631   }
    632 
    633   SourceLocation getCommandNameBeginLoc() const {
    634     return getLocStart().getLocWithOffset(1);
    635   }
    636 
    637   SourceRange getCommandNameRange(const CommandTraits &Traits) const {
    638     StringRef Name = getCommandName(Traits);
    639     return SourceRange(getCommandNameBeginLoc(),
    640                        getLocStart().getLocWithOffset(1 + Name.size()));
    641   }
    642 
    643   unsigned getNumArgs() const {
    644     return Args.size();
    645   }
    646 
    647   StringRef getArgText(unsigned Idx) const {
    648     return Args[Idx].Text;
    649   }
    650 
    651   SourceRange getArgRange(unsigned Idx) const {
    652     return Args[Idx].Range;
    653   }
    654 
    655   void setArgs(llvm::ArrayRef<Argument> A) {
    656     Args = A;
    657     if (Args.size() > 0) {
    658       SourceLocation NewLocEnd = Args.back().Range.getEnd();
    659       if (NewLocEnd.isValid())
    660         setSourceRange(SourceRange(getLocStart(), NewLocEnd));
    661     }
    662   }
    663 
    664   ParagraphComment *getParagraph() const LLVM_READONLY {
    665     return Paragraph;
    666   }
    667 
    668   bool hasNonWhitespaceParagraph() const {
    669     return Paragraph && !Paragraph->isWhitespace();
    670   }
    671 
    672   void setParagraph(ParagraphComment *PC) {
    673     Paragraph = PC;
    674     SourceLocation NewLocEnd = PC->getLocEnd();
    675     if (NewLocEnd.isValid())
    676       setSourceRange(SourceRange(getLocStart(), NewLocEnd));
    677   }
    678 };
    679 
    680 /// Doxygen \\param command.
    681 class ParamCommandComment : public BlockCommandComment {
    682 private:
    683   /// Parameter index in the function declaration.
    684   unsigned ParamIndex;
    685 
    686 public:
    687   enum { InvalidParamIndex = ~0U };
    688 
    689   ParamCommandComment(SourceLocation LocBegin,
    690                       SourceLocation LocEnd,
    691                       unsigned CommandID) :
    692       BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd,
    693                           CommandID),
    694       ParamIndex(InvalidParamIndex) {
    695     ParamCommandCommentBits.Direction = In;
    696     ParamCommandCommentBits.IsDirectionExplicit = false;
    697   }
    698 
    699   static bool classof(const Comment *C) {
    700     return C->getCommentKind() == ParamCommandCommentKind;
    701   }
    702 
    703   static bool classof(const ParamCommandComment *) { return true; }
    704 
    705   enum PassDirection {
    706     In,
    707     Out,
    708     InOut
    709   };
    710 
    711   static const char *getDirectionAsString(PassDirection D);
    712 
    713   PassDirection getDirection() const LLVM_READONLY {
    714     return static_cast<PassDirection>(ParamCommandCommentBits.Direction);
    715   }
    716 
    717   bool isDirectionExplicit() const LLVM_READONLY {
    718     return ParamCommandCommentBits.IsDirectionExplicit;
    719   }
    720 
    721   void setDirection(PassDirection Direction, bool Explicit) {
    722     ParamCommandCommentBits.Direction = Direction;
    723     ParamCommandCommentBits.IsDirectionExplicit = Explicit;
    724   }
    725 
    726   bool hasParamName() const {
    727     return getNumArgs() > 0;
    728   }
    729 
    730   StringRef getParamName() const {
    731     return Args[0].Text;
    732   }
    733 
    734   SourceRange getParamNameRange() const {
    735     return Args[0].Range;
    736   }
    737 
    738   bool isParamIndexValid() const LLVM_READONLY {
    739     return ParamIndex != InvalidParamIndex;
    740   }
    741 
    742   unsigned getParamIndex() const LLVM_READONLY {
    743     assert(isParamIndexValid());
    744     return ParamIndex;
    745   }
    746 
    747   void setParamIndex(unsigned Index) {
    748     ParamIndex = Index;
    749     assert(isParamIndexValid());
    750   }
    751 };
    752 
    753 /// Doxygen \\tparam command, describes a template parameter.
    754 class TParamCommandComment : public BlockCommandComment {
    755 private:
    756   /// If this template parameter name was resolved (found in template parameter
    757   /// list), then this stores a list of position indexes in all template
    758   /// parameter lists.
    759   ///
    760   /// For example:
    761   /// \verbatim
    762   ///     template<typename C, template<typename T> class TT>
    763   ///     void test(TT<int> aaa);
    764   /// \endverbatim
    765   /// For C:  Position = { 0 }
    766   /// For TT: Position = { 1 }
    767   /// For T:  Position = { 1, 0 }
    768   llvm::ArrayRef<unsigned> Position;
    769 
    770 public:
    771   TParamCommandComment(SourceLocation LocBegin,
    772                        SourceLocation LocEnd,
    773                        unsigned CommandID) :
    774       BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID)
    775   { }
    776 
    777   static bool classof(const Comment *C) {
    778     return C->getCommentKind() == TParamCommandCommentKind;
    779   }
    780 
    781   static bool classof(const TParamCommandComment *) { return true; }
    782 
    783   bool hasParamName() const {
    784     return getNumArgs() > 0;
    785   }
    786 
    787   StringRef getParamName() const {
    788     return Args[0].Text;
    789   }
    790 
    791   SourceRange getParamNameRange() const {
    792     return Args[0].Range;
    793   }
    794 
    795   bool isPositionValid() const LLVM_READONLY {
    796     return !Position.empty();
    797   }
    798 
    799   unsigned getDepth() const {
    800     assert(isPositionValid());
    801     return Position.size();
    802   }
    803 
    804   unsigned getIndex(unsigned Depth) const {
    805     assert(isPositionValid());
    806     return Position[Depth];
    807   }
    808 
    809   void setPosition(ArrayRef<unsigned> NewPosition) {
    810     Position = NewPosition;
    811     assert(isPositionValid());
    812   }
    813 };
    814 
    815 /// A line of text contained in a verbatim block.
    816 class VerbatimBlockLineComment : public Comment {
    817   StringRef Text;
    818 
    819 public:
    820   VerbatimBlockLineComment(SourceLocation LocBegin,
    821                            StringRef Text) :
    822       Comment(VerbatimBlockLineCommentKind,
    823               LocBegin,
    824               LocBegin.getLocWithOffset(Text.size())),
    825       Text(Text)
    826   { }
    827 
    828   static bool classof(const Comment *C) {
    829     return C->getCommentKind() == VerbatimBlockLineCommentKind;
    830   }
    831 
    832   static bool classof(const VerbatimBlockLineComment *) { return true; }
    833 
    834   child_iterator child_begin() const { return NULL; }
    835 
    836   child_iterator child_end() const { return NULL; }
    837 
    838   StringRef getText() const LLVM_READONLY {
    839     return Text;
    840   }
    841 };
    842 
    843 /// A verbatim block command (e. g., preformatted code).  Verbatim block has an
    844 /// opening and a closing command and contains multiple lines of text
    845 /// (VerbatimBlockLineComment nodes).
    846 class VerbatimBlockComment : public BlockCommandComment {
    847 protected:
    848   StringRef CloseName;
    849   SourceLocation CloseNameLocBegin;
    850   llvm::ArrayRef<VerbatimBlockLineComment *> Lines;
    851 
    852 public:
    853   VerbatimBlockComment(SourceLocation LocBegin,
    854                        SourceLocation LocEnd,
    855                        unsigned CommandID) :
    856       BlockCommandComment(VerbatimBlockCommentKind,
    857                           LocBegin, LocEnd, CommandID)
    858   { }
    859 
    860   static bool classof(const Comment *C) {
    861     return C->getCommentKind() == VerbatimBlockCommentKind;
    862   }
    863 
    864   static bool classof(const VerbatimBlockComment *) { return true; }
    865 
    866   child_iterator child_begin() const {
    867     return reinterpret_cast<child_iterator>(Lines.begin());
    868   }
    869 
    870   child_iterator child_end() const {
    871     return reinterpret_cast<child_iterator>(Lines.end());
    872   }
    873 
    874   void setCloseName(StringRef Name, SourceLocation LocBegin) {
    875     CloseName = Name;
    876     CloseNameLocBegin = LocBegin;
    877   }
    878 
    879   void setLines(llvm::ArrayRef<VerbatimBlockLineComment *> L) {
    880     Lines = L;
    881   }
    882 
    883   StringRef getCloseName() const {
    884     return CloseName;
    885   }
    886 
    887   unsigned getNumLines() const {
    888     return Lines.size();
    889   }
    890 
    891   StringRef getText(unsigned LineIdx) const {
    892     return Lines[LineIdx]->getText();
    893   }
    894 };
    895 
    896 /// A verbatim line command.  Verbatim line has an opening command, a single
    897 /// line of text (up to the newline after the opening command) and has no
    898 /// closing command.
    899 class VerbatimLineComment : public BlockCommandComment {
    900 protected:
    901   StringRef Text;
    902   SourceLocation TextBegin;
    903 
    904 public:
    905   VerbatimLineComment(SourceLocation LocBegin,
    906                       SourceLocation LocEnd,
    907                       unsigned CommandID,
    908                       SourceLocation TextBegin,
    909                       StringRef Text) :
    910       BlockCommandComment(VerbatimLineCommentKind,
    911                           LocBegin, LocEnd,
    912                           CommandID),
    913       Text(Text),
    914       TextBegin(TextBegin)
    915   { }
    916 
    917   static bool classof(const Comment *C) {
    918     return C->getCommentKind() == VerbatimLineCommentKind;
    919   }
    920 
    921   static bool classof(const VerbatimLineComment *) { return true; }
    922 
    923   child_iterator child_begin() const { return NULL; }
    924 
    925   child_iterator child_end() const { return NULL; }
    926 
    927   StringRef getText() const {
    928     return Text;
    929   }
    930 
    931   SourceRange getTextRange() const {
    932     return SourceRange(TextBegin, getLocEnd());
    933   }
    934 };
    935 
    936 /// Information about the declaration, useful to clients of FullComment.
    937 struct DeclInfo {
    938   /// Declaration the comment is attached to.  Should not be NULL.
    939   const Decl *ThisDecl;
    940 
    941   /// Parameters that can be referenced by \\param if \c ThisDecl is something
    942   /// that we consider a "function".
    943   ArrayRef<const ParmVarDecl *> ParamVars;
    944 
    945   /// Function result type if \c ThisDecl is something that we consider
    946   /// a "function".
    947   QualType ResultType;
    948 
    949   /// Template parameters that can be referenced by \\tparam if \c ThisDecl is
    950   /// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is
    951   /// true).
    952   const TemplateParameterList *TemplateParameters;
    953 
    954   /// A simplified description of \c ThisDecl kind that should be good enough
    955   /// for documentation rendering purposes.
    956   enum DeclKind {
    957     /// Everything else not explicitly mentioned below.
    958     OtherKind,
    959 
    960     /// Something that we consider a "function":
    961     /// \li function,
    962     /// \li function template,
    963     /// \li function template specialization,
    964     /// \li member function,
    965     /// \li member function template,
    966     /// \li member function template specialization,
    967     /// \li ObjC method,
    968     /// \li a typedef for a function pointer, member function pointer,
    969     ///     ObjC block.
    970     FunctionKind,
    971 
    972     /// Something that we consider a "class":
    973     /// \li class/struct,
    974     /// \li class template,
    975     /// \li class template (partial) specialization.
    976     ClassKind,
    977 
    978     /// Something that we consider a "variable":
    979     /// \li namespace scope variables;
    980     /// \li static and non-static class data members;
    981     /// \li enumerators.
    982     VariableKind,
    983 
    984     /// A C++ namespace.
    985     NamespaceKind,
    986 
    987     /// A C++ typedef-name (a 'typedef' decl specifier or alias-declaration),
    988     /// see \c TypedefNameDecl.
    989     TypedefKind,
    990 
    991     /// An enumeration or scoped enumeration.
    992     EnumKind
    993   };
    994 
    995   /// What kind of template specialization \c ThisDecl is.
    996   enum TemplateDeclKind {
    997     NotTemplate,
    998     Template,
    999     TemplateSpecialization,
   1000     TemplatePartialSpecialization
   1001   };
   1002 
   1003   /// If false, only \c ThisDecl is valid.
   1004   unsigned IsFilled : 1;
   1005 
   1006   /// Simplified kind of \c ThisDecl, see\c DeclKind enum.
   1007   unsigned Kind : 3;
   1008 
   1009   /// Is \c ThisDecl a template declaration.
   1010   unsigned TemplateKind : 2;
   1011 
   1012   /// Is \c ThisDecl an ObjCMethodDecl.
   1013   unsigned IsObjCMethod : 1;
   1014 
   1015   /// Is \c ThisDecl a non-static member function of C++ class or
   1016   /// instance method of ObjC class.
   1017   /// Can be true only if \c IsFunctionDecl is true.
   1018   unsigned IsInstanceMethod : 1;
   1019 
   1020   /// Is \c ThisDecl a static member function of C++ class or
   1021   /// class method of ObjC class.
   1022   /// Can be true only if \c IsFunctionDecl is true.
   1023   unsigned IsClassMethod : 1;
   1024 
   1025   void fill();
   1026 
   1027   DeclKind getKind() const LLVM_READONLY {
   1028     return static_cast<DeclKind>(Kind);
   1029   }
   1030 
   1031   TemplateDeclKind getTemplateKind() const LLVM_READONLY {
   1032     return static_cast<TemplateDeclKind>(TemplateKind);
   1033   }
   1034 };
   1035 
   1036 /// A full comment attached to a declaration, contains block content.
   1037 class FullComment : public Comment {
   1038   llvm::ArrayRef<BlockContentComment *> Blocks;
   1039 
   1040   DeclInfo *ThisDeclInfo;
   1041 
   1042 public:
   1043   FullComment(llvm::ArrayRef<BlockContentComment *> Blocks, DeclInfo *D) :
   1044       Comment(FullCommentKind, SourceLocation(), SourceLocation()),
   1045       Blocks(Blocks), ThisDeclInfo(D) {
   1046     if (Blocks.empty())
   1047       return;
   1048 
   1049     setSourceRange(SourceRange(Blocks.front()->getLocStart(),
   1050                                Blocks.back()->getLocEnd()));
   1051     setLocation(Blocks.front()->getLocStart());
   1052   }
   1053 
   1054   static bool classof(const Comment *C) {
   1055     return C->getCommentKind() == FullCommentKind;
   1056   }
   1057 
   1058   static bool classof(const FullComment *) { return true; }
   1059 
   1060   child_iterator child_begin() const {
   1061     return reinterpret_cast<child_iterator>(Blocks.begin());
   1062   }
   1063 
   1064   child_iterator child_end() const {
   1065     return reinterpret_cast<child_iterator>(Blocks.end());
   1066   }
   1067 
   1068   const Decl *getDecl() const LLVM_READONLY {
   1069     return ThisDeclInfo->ThisDecl;
   1070   }
   1071 
   1072   const DeclInfo *getDeclInfo() const LLVM_READONLY {
   1073     if (!ThisDeclInfo->IsFilled)
   1074       ThisDeclInfo->fill();
   1075     return ThisDeclInfo;
   1076   }
   1077 };
   1078 
   1079 } // end namespace comments
   1080 } // end namespace clang
   1081 
   1082 #endif
   1083 
   1084