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