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