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 { InvalidParamIndex = ~0U };
    703 
    704   ParamCommandComment(SourceLocation LocBegin,
    705                       SourceLocation LocEnd,
    706                       unsigned CommandID,
    707                       CommandMarkerKind CommandMarker) :
    708       BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd,
    709                           CommandID, CommandMarker),
    710       ParamIndex(InvalidParamIndex) {
    711     ParamCommandCommentBits.Direction = In;
    712     ParamCommandCommentBits.IsDirectionExplicit = false;
    713   }
    714 
    715   static bool classof(const Comment *C) {
    716     return C->getCommentKind() == ParamCommandCommentKind;
    717   }
    718 
    719   enum PassDirection {
    720     In,
    721     Out,
    722     InOut
    723   };
    724 
    725   static const char *getDirectionAsString(PassDirection D);
    726 
    727   PassDirection getDirection() const LLVM_READONLY {
    728     return static_cast<PassDirection>(ParamCommandCommentBits.Direction);
    729   }
    730 
    731   bool isDirectionExplicit() const LLVM_READONLY {
    732     return ParamCommandCommentBits.IsDirectionExplicit;
    733   }
    734 
    735   void setDirection(PassDirection Direction, bool Explicit) {
    736     ParamCommandCommentBits.Direction = Direction;
    737     ParamCommandCommentBits.IsDirectionExplicit = Explicit;
    738   }
    739 
    740   bool hasParamName() const {
    741     return getNumArgs() > 0;
    742   }
    743 
    744   StringRef getParamName(const FullComment *FC) const;
    745 
    746   StringRef getParamNameAsWritten() const {
    747     return Args[0].Text;
    748   }
    749 
    750   SourceRange getParamNameRange() const {
    751     return Args[0].Range;
    752   }
    753 
    754   bool isParamIndexValid() const LLVM_READONLY {
    755     return ParamIndex != InvalidParamIndex;
    756   }
    757 
    758   unsigned getParamIndex() const LLVM_READONLY {
    759     assert(isParamIndexValid());
    760     return ParamIndex;
    761   }
    762 
    763   void setParamIndex(unsigned Index) {
    764     ParamIndex = Index;
    765     assert(isParamIndexValid());
    766   }
    767 };
    768 
    769 /// Doxygen \\tparam command, describes a template parameter.
    770 class TParamCommandComment : public BlockCommandComment {
    771 private:
    772   /// If this template parameter name was resolved (found in template parameter
    773   /// list), then this stores a list of position indexes in all template
    774   /// parameter lists.
    775   ///
    776   /// For example:
    777   /// \verbatim
    778   ///     template<typename C, template<typename T> class TT>
    779   ///     void test(TT<int> aaa);
    780   /// \endverbatim
    781   /// For C:  Position = { 0 }
    782   /// For TT: Position = { 1 }
    783   /// For T:  Position = { 1, 0 }
    784   ArrayRef<unsigned> Position;
    785 
    786 public:
    787   TParamCommandComment(SourceLocation LocBegin,
    788                        SourceLocation LocEnd,
    789                        unsigned CommandID,
    790                        CommandMarkerKind CommandMarker) :
    791       BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID,
    792                           CommandMarker)
    793   { }
    794 
    795   static bool classof(const Comment *C) {
    796     return C->getCommentKind() == TParamCommandCommentKind;
    797   }
    798 
    799   bool hasParamName() const {
    800     return getNumArgs() > 0;
    801   }
    802 
    803   StringRef getParamName(const FullComment *FC) const;
    804 
    805   StringRef getParamNameAsWritten() const {
    806     return Args[0].Text;
    807   }
    808 
    809   SourceRange getParamNameRange() const {
    810     return Args[0].Range;
    811   }
    812 
    813   bool isPositionValid() const LLVM_READONLY {
    814     return !Position.empty();
    815   }
    816 
    817   unsigned getDepth() const {
    818     assert(isPositionValid());
    819     return Position.size();
    820   }
    821 
    822   unsigned getIndex(unsigned Depth) const {
    823     assert(isPositionValid());
    824     return Position[Depth];
    825   }
    826 
    827   void setPosition(ArrayRef<unsigned> NewPosition) {
    828     Position = NewPosition;
    829     assert(isPositionValid());
    830   }
    831 };
    832 
    833 /// A line of text contained in a verbatim block.
    834 class VerbatimBlockLineComment : public Comment {
    835   StringRef Text;
    836 
    837 public:
    838   VerbatimBlockLineComment(SourceLocation LocBegin,
    839                            StringRef Text) :
    840       Comment(VerbatimBlockLineCommentKind,
    841               LocBegin,
    842               LocBegin.getLocWithOffset(Text.size())),
    843       Text(Text)
    844   { }
    845 
    846   static bool classof(const Comment *C) {
    847     return C->getCommentKind() == VerbatimBlockLineCommentKind;
    848   }
    849 
    850   child_iterator child_begin() const { return NULL; }
    851 
    852   child_iterator child_end() const { return NULL; }
    853 
    854   StringRef getText() const LLVM_READONLY {
    855     return Text;
    856   }
    857 };
    858 
    859 /// A verbatim block command (e. g., preformatted code).  Verbatim block has an
    860 /// opening and a closing command and contains multiple lines of text
    861 /// (VerbatimBlockLineComment nodes).
    862 class VerbatimBlockComment : public BlockCommandComment {
    863 protected:
    864   StringRef CloseName;
    865   SourceLocation CloseNameLocBegin;
    866   ArrayRef<VerbatimBlockLineComment *> Lines;
    867 
    868 public:
    869   VerbatimBlockComment(SourceLocation LocBegin,
    870                        SourceLocation LocEnd,
    871                        unsigned CommandID) :
    872       BlockCommandComment(VerbatimBlockCommentKind,
    873                           LocBegin, LocEnd, CommandID,
    874                           CMK_At) // FIXME: improve source fidelity.
    875   { }
    876 
    877   static bool classof(const Comment *C) {
    878     return C->getCommentKind() == VerbatimBlockCommentKind;
    879   }
    880 
    881   child_iterator child_begin() const {
    882     return reinterpret_cast<child_iterator>(Lines.begin());
    883   }
    884 
    885   child_iterator child_end() const {
    886     return reinterpret_cast<child_iterator>(Lines.end());
    887   }
    888 
    889   void setCloseName(StringRef Name, SourceLocation LocBegin) {
    890     CloseName = Name;
    891     CloseNameLocBegin = LocBegin;
    892   }
    893 
    894   void setLines(ArrayRef<VerbatimBlockLineComment *> L) {
    895     Lines = L;
    896   }
    897 
    898   StringRef getCloseName() const {
    899     return CloseName;
    900   }
    901 
    902   unsigned getNumLines() const {
    903     return Lines.size();
    904   }
    905 
    906   StringRef getText(unsigned LineIdx) const {
    907     return Lines[LineIdx]->getText();
    908   }
    909 };
    910 
    911 /// A verbatim line command.  Verbatim line has an opening command, a single
    912 /// line of text (up to the newline after the opening command) and has no
    913 /// closing command.
    914 class VerbatimLineComment : public BlockCommandComment {
    915 protected:
    916   StringRef Text;
    917   SourceLocation TextBegin;
    918 
    919 public:
    920   VerbatimLineComment(SourceLocation LocBegin,
    921                       SourceLocation LocEnd,
    922                       unsigned CommandID,
    923                       SourceLocation TextBegin,
    924                       StringRef Text) :
    925       BlockCommandComment(VerbatimLineCommentKind,
    926                           LocBegin, LocEnd,
    927                           CommandID,
    928                           CMK_At), // FIXME: improve source fidelity.
    929       Text(Text),
    930       TextBegin(TextBegin)
    931   { }
    932 
    933   static bool classof(const Comment *C) {
    934     return C->getCommentKind() == VerbatimLineCommentKind;
    935   }
    936 
    937   child_iterator child_begin() const { return NULL; }
    938 
    939   child_iterator child_end() const { return NULL; }
    940 
    941   StringRef getText() const {
    942     return Text;
    943   }
    944 
    945   SourceRange getTextRange() const {
    946     return SourceRange(TextBegin, getLocEnd());
    947   }
    948 };
    949 
    950 /// Information about the declaration, useful to clients of FullComment.
    951 struct DeclInfo {
    952   /// Declaration the comment is actually attached to (in the source).
    953   /// Should not be NULL.
    954   const Decl *CommentDecl;
    955 
    956   /// CurrentDecl is the declaration with which the FullComment is associated.
    957   ///
    958   /// It can be different from \c CommentDecl.  It happens when we we decide
    959   /// that the comment originally attached to \c CommentDecl is fine for
    960   /// \c CurrentDecl too (for example, for a redeclaration or an overrider of
    961   /// \c CommentDecl).
    962   ///
    963   /// The information in the DeclInfo corresponds to CurrentDecl.
    964   const Decl *CurrentDecl;
    965 
    966   /// Parameters that can be referenced by \\param if \c CommentDecl is something
    967   /// that we consider a "function".
    968   ArrayRef<const ParmVarDecl *> ParamVars;
    969 
    970   /// Function result type if \c CommentDecl is something that we consider
    971   /// a "function".
    972   QualType ResultType;
    973 
    974   /// Template parameters that can be referenced by \\tparam if \c CommentDecl is
    975   /// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is
    976   /// true).
    977   const TemplateParameterList *TemplateParameters;
    978 
    979   /// A simplified description of \c CommentDecl kind that should be good enough
    980   /// for documentation rendering purposes.
    981   enum DeclKind {
    982     /// Everything else not explicitly mentioned below.
    983     OtherKind,
    984 
    985     /// Something that we consider a "function":
    986     /// \li function,
    987     /// \li function template,
    988     /// \li function template specialization,
    989     /// \li member function,
    990     /// \li member function template,
    991     /// \li member function template specialization,
    992     /// \li ObjC method,
    993     /// \li a typedef for a function pointer, member function pointer,
    994     ///     ObjC block.
    995     FunctionKind,
    996 
    997     /// Something that we consider a "class":
    998     /// \li class/struct,
    999     /// \li class template,
   1000     /// \li class template (partial) specialization.
   1001     ClassKind,
   1002 
   1003     /// Something that we consider a "variable":
   1004     /// \li namespace scope variables;
   1005     /// \li static and non-static class data members;
   1006     /// \li enumerators.
   1007     VariableKind,
   1008 
   1009     /// A C++ namespace.
   1010     NamespaceKind,
   1011 
   1012     /// A C++ typedef-name (a 'typedef' decl specifier or alias-declaration),
   1013     /// see \c TypedefNameDecl.
   1014     TypedefKind,
   1015 
   1016     /// An enumeration or scoped enumeration.
   1017     EnumKind
   1018   };
   1019 
   1020   /// What kind of template specialization \c CommentDecl is.
   1021   enum TemplateDeclKind {
   1022     NotTemplate,
   1023     Template,
   1024     TemplateSpecialization,
   1025     TemplatePartialSpecialization
   1026   };
   1027 
   1028   /// If false, only \c CommentDecl is valid.
   1029   unsigned IsFilled : 1;
   1030 
   1031   /// Simplified kind of \c CommentDecl, see \c DeclKind enum.
   1032   unsigned Kind : 3;
   1033 
   1034   /// Is \c CommentDecl a template declaration.
   1035   unsigned TemplateKind : 2;
   1036 
   1037   /// Is \c CommentDecl an ObjCMethodDecl.
   1038   unsigned IsObjCMethod : 1;
   1039 
   1040   /// Is \c CommentDecl a non-static member function of C++ class or
   1041   /// instance method of ObjC class.
   1042   /// Can be true only if \c IsFunctionDecl is true.
   1043   unsigned IsInstanceMethod : 1;
   1044 
   1045   /// Is \c CommentDecl a static member function of C++ class or
   1046   /// class method of ObjC class.
   1047   /// Can be true only if \c IsFunctionDecl is true.
   1048   unsigned IsClassMethod : 1;
   1049 
   1050   void fill();
   1051 
   1052   DeclKind getKind() const LLVM_READONLY {
   1053     return static_cast<DeclKind>(Kind);
   1054   }
   1055 
   1056   TemplateDeclKind getTemplateKind() const LLVM_READONLY {
   1057     return static_cast<TemplateDeclKind>(TemplateKind);
   1058   }
   1059 };
   1060 
   1061 /// A full comment attached to a declaration, contains block content.
   1062 class FullComment : public Comment {
   1063   ArrayRef<BlockContentComment *> Blocks;
   1064   DeclInfo *ThisDeclInfo;
   1065 
   1066 public:
   1067   FullComment(ArrayRef<BlockContentComment *> Blocks, DeclInfo *D) :
   1068       Comment(FullCommentKind, SourceLocation(), SourceLocation()),
   1069       Blocks(Blocks), ThisDeclInfo(D) {
   1070     if (Blocks.empty())
   1071       return;
   1072 
   1073     setSourceRange(SourceRange(Blocks.front()->getLocStart(),
   1074                                Blocks.back()->getLocEnd()));
   1075     setLocation(Blocks.front()->getLocStart());
   1076   }
   1077 
   1078   static bool classof(const Comment *C) {
   1079     return C->getCommentKind() == FullCommentKind;
   1080   }
   1081 
   1082   child_iterator child_begin() const {
   1083     return reinterpret_cast<child_iterator>(Blocks.begin());
   1084   }
   1085 
   1086   child_iterator child_end() const {
   1087     return reinterpret_cast<child_iterator>(Blocks.end());
   1088   }
   1089 
   1090   const Decl *getDecl() const LLVM_READONLY {
   1091     return ThisDeclInfo->CommentDecl;
   1092   }
   1093 
   1094   const DeclInfo *getDeclInfo() const LLVM_READONLY {
   1095     if (!ThisDeclInfo->IsFilled)
   1096       ThisDeclInfo->fill();
   1097     return ThisDeclInfo;
   1098   }
   1099 
   1100   DeclInfo *getThisDeclInfo() const LLVM_READONLY {
   1101     return ThisDeclInfo;
   1102   }
   1103 
   1104   ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
   1105 
   1106 };
   1107 } // end namespace comments
   1108 } // end namespace clang
   1109 
   1110 #endif
   1111 
   1112