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