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