Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:29

0001 //===--- Comment.h - Comment AST nodes --------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 //  This file defines comment AST nodes.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_CLANG_AST_COMMENT_H
0014 #define LLVM_CLANG_AST_COMMENT_H
0015 
0016 #include "clang/AST/CommentCommandTraits.h"
0017 #include "clang/AST/DeclObjC.h"
0018 #include "clang/AST/Type.h"
0019 #include "clang/Basic/SourceLocation.h"
0020 #include "llvm/ADT/ArrayRef.h"
0021 #include "llvm/ADT/StringRef.h"
0022 
0023 namespace clang {
0024 class Decl;
0025 class ParmVarDecl;
0026 class TemplateParameterList;
0027 
0028 namespace comments {
0029 class FullComment;
0030 enum class InlineCommandRenderKind;
0031 enum class ParamCommandPassDirection;
0032 
0033 /// Describes the syntax that was used in a documentation command.
0034 ///
0035 /// Exact values of this enumeration are important because they used to select
0036 /// parts of diagnostic messages.  Audit diagnostics before changing or adding
0037 /// a new value.
0038 enum CommandMarkerKind {
0039   /// Command started with a backslash character:
0040   /// \code
0041   ///   \foo
0042   /// \endcode
0043   CMK_Backslash = 0,
0044 
0045   /// Command started with an 'at' character:
0046   /// \code
0047   ///   @foo
0048   /// \endcode
0049   CMK_At = 1
0050 };
0051 
0052 enum class CommentKind {
0053   None = 0,
0054 #define COMMENT(CLASS, PARENT) CLASS,
0055 #define COMMENT_RANGE(BASE, FIRST, LAST)                                       \
0056   First##BASE##Constant = FIRST, Last##BASE##Constant = LAST,
0057 #define LAST_COMMENT_RANGE(BASE, FIRST, LAST)                                  \
0058   First##BASE##Constant = FIRST, Last##BASE##Constant = LAST
0059 #define ABSTRACT_COMMENT(COMMENT)
0060 #include "clang/AST/CommentNodes.inc"
0061 };
0062 
0063 /// Any part of the comment.
0064 /// Abstract class.
0065 class Comment {
0066 protected:
0067   /// Preferred location to show caret.
0068   SourceLocation Loc;
0069 
0070   /// Source range of this AST node.
0071   SourceRange Range;
0072 
0073   class CommentBitfields {
0074     friend class Comment;
0075 
0076     /// Type of this AST node.
0077     LLVM_PREFERRED_TYPE(CommentKind)
0078     unsigned Kind : 8;
0079   };
0080   enum { NumCommentBits = 8 };
0081 
0082   class InlineContentCommentBitfields {
0083     friend class InlineContentComment;
0084 
0085     LLVM_PREFERRED_TYPE(CommentBitfields)
0086     unsigned : NumCommentBits;
0087 
0088     /// True if there is a newline after this inline content node.
0089     /// (There is no separate AST node for a newline.)
0090     LLVM_PREFERRED_TYPE(bool)
0091     unsigned HasTrailingNewline : 1;
0092   };
0093   enum { NumInlineContentCommentBits = NumCommentBits + 1 };
0094 
0095   class TextCommentBitfields {
0096     friend class TextComment;
0097 
0098     LLVM_PREFERRED_TYPE(InlineContentCommentBitfields)
0099     unsigned : NumInlineContentCommentBits;
0100 
0101     /// True if \c IsWhitespace field contains a valid value.
0102     LLVM_PREFERRED_TYPE(bool)
0103     mutable unsigned IsWhitespaceValid : 1;
0104 
0105     /// True if this comment AST node contains only whitespace.
0106     LLVM_PREFERRED_TYPE(bool)
0107     mutable unsigned IsWhitespace : 1;
0108   };
0109   enum { NumTextCommentBits = NumInlineContentCommentBits + 2 };
0110 
0111   class InlineCommandCommentBitfields {
0112     friend class InlineCommandComment;
0113 
0114     LLVM_PREFERRED_TYPE(InlineContentCommentBitfields)
0115     unsigned : NumInlineContentCommentBits;
0116 
0117     LLVM_PREFERRED_TYPE(InlineCommandRenderKind)
0118     unsigned RenderKind : 3;
0119 
0120     LLVM_PREFERRED_TYPE(CommandTraits::KnownCommandIDs)
0121     unsigned CommandID : CommandInfo::NumCommandIDBits;
0122   };
0123   enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 3 +
0124                                        CommandInfo::NumCommandIDBits };
0125 
0126   class HTMLTagCommentBitfields {
0127     friend class HTMLTagComment;
0128 
0129     LLVM_PREFERRED_TYPE(InlineContentCommentBitfields)
0130     unsigned : NumInlineContentCommentBits;
0131 
0132     /// True if we found that this tag is malformed in some way.
0133     LLVM_PREFERRED_TYPE(bool)
0134     unsigned IsMalformed : 1;
0135   };
0136   enum { NumHTMLTagCommentBits = NumInlineContentCommentBits + 1 };
0137 
0138   class HTMLStartTagCommentBitfields {
0139     friend class HTMLStartTagComment;
0140 
0141     LLVM_PREFERRED_TYPE(HTMLTagCommentBitfields)
0142     unsigned : NumHTMLTagCommentBits;
0143 
0144     /// True if this tag is self-closing (e. g., <br />).  This is based on tag
0145     /// spelling in comment (plain <br> would not set this flag).
0146     LLVM_PREFERRED_TYPE(bool)
0147     unsigned IsSelfClosing : 1;
0148   };
0149   enum { NumHTMLStartTagCommentBits = NumHTMLTagCommentBits + 1 };
0150 
0151   class ParagraphCommentBitfields {
0152     friend class ParagraphComment;
0153 
0154     LLVM_PREFERRED_TYPE(CommentBitfields)
0155     unsigned : NumCommentBits;
0156 
0157     /// True if \c IsWhitespace field contains a valid value.
0158     LLVM_PREFERRED_TYPE(bool)
0159     mutable unsigned IsWhitespaceValid : 1;
0160 
0161     /// True if this comment AST node contains only whitespace.
0162     LLVM_PREFERRED_TYPE(bool)
0163     mutable unsigned IsWhitespace : 1;
0164   };
0165   enum { NumParagraphCommentBits = NumCommentBits + 2 };
0166 
0167   class BlockCommandCommentBitfields {
0168     friend class BlockCommandComment;
0169 
0170     LLVM_PREFERRED_TYPE(CommentBitfields)
0171     unsigned : NumCommentBits;
0172 
0173     LLVM_PREFERRED_TYPE(CommandTraits::KnownCommandIDs)
0174     unsigned CommandID : CommandInfo::NumCommandIDBits;
0175 
0176     /// Describes the syntax that was used in a documentation command.
0177     /// Contains values from CommandMarkerKind enum.
0178     LLVM_PREFERRED_TYPE(CommandMarkerKind)
0179     unsigned CommandMarker : 1;
0180   };
0181   enum { NumBlockCommandCommentBits = NumCommentBits +
0182                                       CommandInfo::NumCommandIDBits + 1 };
0183 
0184   class ParamCommandCommentBitfields {
0185     friend class ParamCommandComment;
0186 
0187     LLVM_PREFERRED_TYPE(BlockCommandCommentBitfields)
0188     unsigned : NumBlockCommandCommentBits;
0189 
0190     /// Parameter passing direction.
0191     LLVM_PREFERRED_TYPE(ParamCommandPassDirection)
0192     unsigned Direction : 2;
0193 
0194     /// True if direction was specified explicitly in the comment.
0195     LLVM_PREFERRED_TYPE(bool)
0196     unsigned IsDirectionExplicit : 1;
0197   };
0198   enum { NumParamCommandCommentBits = NumBlockCommandCommentBits + 3 };
0199 
0200   union {
0201     CommentBitfields CommentBits;
0202     InlineContentCommentBitfields InlineContentCommentBits;
0203     TextCommentBitfields TextCommentBits;
0204     InlineCommandCommentBitfields InlineCommandCommentBits;
0205     HTMLTagCommentBitfields HTMLTagCommentBits;
0206     HTMLStartTagCommentBitfields HTMLStartTagCommentBits;
0207     ParagraphCommentBitfields ParagraphCommentBits;
0208     BlockCommandCommentBitfields BlockCommandCommentBits;
0209     ParamCommandCommentBitfields ParamCommandCommentBits;
0210   };
0211 
0212   void setSourceRange(SourceRange SR) {
0213     Range = SR;
0214   }
0215 
0216   void setLocation(SourceLocation L) {
0217     Loc = L;
0218   }
0219 
0220 public:
0221   struct Argument {
0222     SourceRange Range;
0223     StringRef Text;
0224   };
0225 
0226   Comment(CommentKind K,
0227           SourceLocation LocBegin,
0228           SourceLocation LocEnd) :
0229       Loc(LocBegin), Range(SourceRange(LocBegin, LocEnd)) {
0230     CommentBits.Kind = llvm::to_underlying(K);
0231   }
0232 
0233   CommentKind getCommentKind() const {
0234     return static_cast<CommentKind>(CommentBits.Kind);
0235   }
0236 
0237   const char *getCommentKindName() const;
0238 
0239   void dump() const;
0240   void dumpColor() const;
0241   void dump(raw_ostream &OS, const ASTContext &Context) const;
0242 
0243   SourceRange getSourceRange() const LLVM_READONLY { return Range; }
0244 
0245   SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); }
0246 
0247   SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); }
0248 
0249   SourceLocation getLocation() const LLVM_READONLY { return Loc; }
0250 
0251   typedef Comment * const *child_iterator;
0252 
0253   child_iterator child_begin() const;
0254   child_iterator child_end() const;
0255 
0256   // TODO: const child iterator
0257 
0258   unsigned child_count() const {
0259     return child_end() - child_begin();
0260   }
0261 };
0262 
0263 /// Inline content (contained within a block).
0264 /// Abstract class.
0265 class InlineContentComment : public Comment {
0266 protected:
0267   InlineContentComment(CommentKind K,
0268                        SourceLocation LocBegin,
0269                        SourceLocation LocEnd) :
0270       Comment(K, LocBegin, LocEnd) {
0271     InlineContentCommentBits.HasTrailingNewline = 0;
0272   }
0273 
0274 public:
0275   static bool classof(const Comment *C) {
0276     return C->getCommentKind() >=
0277                CommentKind::FirstInlineContentCommentConstant &&
0278            C->getCommentKind() <= CommentKind::LastInlineContentCommentConstant;
0279   }
0280 
0281   void addTrailingNewline() {
0282     InlineContentCommentBits.HasTrailingNewline = 1;
0283   }
0284 
0285   bool hasTrailingNewline() const {
0286     return InlineContentCommentBits.HasTrailingNewline;
0287   }
0288 };
0289 
0290 /// Plain text.
0291 class TextComment : public InlineContentComment {
0292   StringRef Text;
0293 
0294 public:
0295   TextComment(SourceLocation LocBegin, SourceLocation LocEnd, StringRef Text)
0296       : InlineContentComment(CommentKind::TextComment, LocBegin, LocEnd),
0297         Text(Text) {
0298     TextCommentBits.IsWhitespaceValid = false;
0299   }
0300 
0301   static bool classof(const Comment *C) {
0302     return C->getCommentKind() == CommentKind::TextComment;
0303   }
0304 
0305   child_iterator child_begin() const { return nullptr; }
0306 
0307   child_iterator child_end() const { return nullptr; }
0308 
0309   StringRef getText() const LLVM_READONLY { return Text; }
0310 
0311   bool isWhitespace() const {
0312     if (TextCommentBits.IsWhitespaceValid)
0313       return TextCommentBits.IsWhitespace;
0314 
0315     TextCommentBits.IsWhitespace = isWhitespaceNoCache();
0316     TextCommentBits.IsWhitespaceValid = true;
0317     return TextCommentBits.IsWhitespace;
0318   }
0319 
0320 private:
0321   bool isWhitespaceNoCache() const;
0322 };
0323 
0324 /// The most appropriate rendering mode for this command, chosen on command
0325 /// semantics in Doxygen.
0326 enum class InlineCommandRenderKind {
0327   Normal,
0328   Bold,
0329   Monospaced,
0330   Emphasized,
0331   Anchor
0332 };
0333 
0334 /// A command with word-like arguments that is considered inline content.
0335 class InlineCommandComment : public InlineContentComment {
0336 protected:
0337   /// Command arguments.
0338   ArrayRef<Argument> Args;
0339 
0340 public:
0341   InlineCommandComment(SourceLocation LocBegin, SourceLocation LocEnd,
0342                        unsigned CommandID, InlineCommandRenderKind RK,
0343                        ArrayRef<Argument> Args)
0344       : InlineContentComment(CommentKind::InlineCommandComment, LocBegin,
0345                              LocEnd),
0346         Args(Args) {
0347     InlineCommandCommentBits.RenderKind = llvm::to_underlying(RK);
0348     InlineCommandCommentBits.CommandID = CommandID;
0349   }
0350 
0351   static bool classof(const Comment *C) {
0352     return C->getCommentKind() == CommentKind::InlineCommandComment;
0353   }
0354 
0355   child_iterator child_begin() const { return nullptr; }
0356 
0357   child_iterator child_end() const { return nullptr; }
0358 
0359   unsigned getCommandID() const {
0360     return InlineCommandCommentBits.CommandID;
0361   }
0362 
0363   StringRef getCommandName(const CommandTraits &Traits) const {
0364     return Traits.getCommandInfo(getCommandID())->Name;
0365   }
0366 
0367   SourceRange getCommandNameRange() const {
0368     return SourceRange(getBeginLoc().getLocWithOffset(-1), getEndLoc());
0369   }
0370 
0371   InlineCommandRenderKind getRenderKind() const {
0372     return static_cast<InlineCommandRenderKind>(
0373         InlineCommandCommentBits.RenderKind);
0374   }
0375 
0376   unsigned getNumArgs() const {
0377     return Args.size();
0378   }
0379 
0380   StringRef getArgText(unsigned Idx) const {
0381     return Args[Idx].Text;
0382   }
0383 
0384   SourceRange getArgRange(unsigned Idx) const {
0385     return Args[Idx].Range;
0386   }
0387 };
0388 
0389 /// Abstract class for opening and closing HTML tags.  HTML tags are always
0390 /// treated as inline content (regardless HTML semantics).
0391 class HTMLTagComment : public InlineContentComment {
0392 protected:
0393   StringRef TagName;
0394   SourceRange TagNameRange;
0395 
0396   HTMLTagComment(CommentKind K,
0397                  SourceLocation LocBegin,
0398                  SourceLocation LocEnd,
0399                  StringRef TagName,
0400                  SourceLocation TagNameBegin,
0401                  SourceLocation TagNameEnd) :
0402       InlineContentComment(K, LocBegin, LocEnd),
0403       TagName(TagName),
0404       TagNameRange(TagNameBegin, TagNameEnd) {
0405     setLocation(TagNameBegin);
0406     HTMLTagCommentBits.IsMalformed = 0;
0407   }
0408 
0409 public:
0410   static bool classof(const Comment *C) {
0411     return C->getCommentKind() >= CommentKind::FirstHTMLTagCommentConstant &&
0412            C->getCommentKind() <= CommentKind::LastHTMLTagCommentConstant;
0413   }
0414 
0415   StringRef getTagName() const LLVM_READONLY { return TagName; }
0416 
0417   SourceRange getTagNameSourceRange() const LLVM_READONLY {
0418     SourceLocation L = getLocation();
0419     return SourceRange(L.getLocWithOffset(1),
0420                        L.getLocWithOffset(1 + TagName.size()));
0421   }
0422 
0423   bool isMalformed() const {
0424     return HTMLTagCommentBits.IsMalformed;
0425   }
0426 
0427   void setIsMalformed() {
0428     HTMLTagCommentBits.IsMalformed = 1;
0429   }
0430 };
0431 
0432 /// An opening HTML tag with attributes.
0433 class HTMLStartTagComment : public HTMLTagComment {
0434 public:
0435   class Attribute {
0436   public:
0437     SourceLocation NameLocBegin;
0438     StringRef Name;
0439 
0440     SourceLocation EqualsLoc;
0441 
0442     SourceRange ValueRange;
0443     StringRef Value;
0444 
0445     Attribute() { }
0446 
0447     Attribute(SourceLocation NameLocBegin, StringRef Name)
0448         : NameLocBegin(NameLocBegin), Name(Name), EqualsLoc(SourceLocation()) {}
0449 
0450     Attribute(SourceLocation NameLocBegin, StringRef Name,
0451               SourceLocation EqualsLoc, SourceRange ValueRange, StringRef Value)
0452         : NameLocBegin(NameLocBegin), Name(Name), EqualsLoc(EqualsLoc),
0453           ValueRange(ValueRange), Value(Value) {}
0454 
0455     SourceLocation getNameLocEnd() const {
0456       return NameLocBegin.getLocWithOffset(Name.size());
0457     }
0458 
0459     SourceRange getNameRange() const {
0460       return SourceRange(NameLocBegin, getNameLocEnd());
0461     }
0462   };
0463 
0464 private:
0465   ArrayRef<Attribute> Attributes;
0466 
0467 public:
0468   HTMLStartTagComment(SourceLocation LocBegin, StringRef TagName)
0469       : HTMLTagComment(CommentKind::HTMLStartTagComment, LocBegin,
0470                        LocBegin.getLocWithOffset(1 + TagName.size()), TagName,
0471                        LocBegin.getLocWithOffset(1),
0472                        LocBegin.getLocWithOffset(1 + TagName.size())) {
0473     HTMLStartTagCommentBits.IsSelfClosing = false;
0474   }
0475 
0476   static bool classof(const Comment *C) {
0477     return C->getCommentKind() == CommentKind::HTMLStartTagComment;
0478   }
0479 
0480   child_iterator child_begin() const { return nullptr; }
0481 
0482   child_iterator child_end() const { return nullptr; }
0483 
0484   unsigned getNumAttrs() const {
0485     return Attributes.size();
0486   }
0487 
0488   const Attribute &getAttr(unsigned Idx) const {
0489     return Attributes[Idx];
0490   }
0491 
0492   void setAttrs(ArrayRef<Attribute> Attrs) {
0493     Attributes = Attrs;
0494     if (!Attrs.empty()) {
0495       const Attribute &Attr = Attrs.back();
0496       SourceLocation L = Attr.ValueRange.getEnd();
0497       if (L.isValid())
0498         Range.setEnd(L);
0499       else {
0500         Range.setEnd(Attr.getNameLocEnd());
0501       }
0502     }
0503   }
0504 
0505   void setGreaterLoc(SourceLocation GreaterLoc) {
0506     Range.setEnd(GreaterLoc);
0507   }
0508 
0509   bool isSelfClosing() const {
0510     return HTMLStartTagCommentBits.IsSelfClosing;
0511   }
0512 
0513   void setSelfClosing() {
0514     HTMLStartTagCommentBits.IsSelfClosing = true;
0515   }
0516 };
0517 
0518 /// A closing HTML tag.
0519 class HTMLEndTagComment : public HTMLTagComment {
0520 public:
0521   HTMLEndTagComment(SourceLocation LocBegin, SourceLocation LocEnd,
0522                     StringRef TagName)
0523       : HTMLTagComment(CommentKind::HTMLEndTagComment, LocBegin, LocEnd,
0524                        TagName, LocBegin.getLocWithOffset(2),
0525                        LocBegin.getLocWithOffset(2 + TagName.size())) {}
0526 
0527   static bool classof(const Comment *C) {
0528     return C->getCommentKind() == CommentKind::HTMLEndTagComment;
0529   }
0530 
0531   child_iterator child_begin() const { return nullptr; }
0532 
0533   child_iterator child_end() const { return nullptr; }
0534 };
0535 
0536 /// Block content (contains inline content).
0537 /// Abstract class.
0538 class BlockContentComment : public Comment {
0539 protected:
0540   BlockContentComment(CommentKind K,
0541                       SourceLocation LocBegin,
0542                       SourceLocation LocEnd) :
0543       Comment(K, LocBegin, LocEnd)
0544   { }
0545 
0546 public:
0547   static bool classof(const Comment *C) {
0548     return C->getCommentKind() >=
0549                CommentKind::FirstBlockContentCommentConstant &&
0550            C->getCommentKind() <= CommentKind::LastBlockContentCommentConstant;
0551   }
0552 };
0553 
0554 /// A single paragraph that contains inline content.
0555 class ParagraphComment : public BlockContentComment {
0556   ArrayRef<InlineContentComment *> Content;
0557 
0558 public:
0559   ParagraphComment(ArrayRef<InlineContentComment *> Content)
0560       : BlockContentComment(CommentKind::ParagraphComment, SourceLocation(),
0561                             SourceLocation()),
0562         Content(Content) {
0563     if (Content.empty()) {
0564       ParagraphCommentBits.IsWhitespace = true;
0565       ParagraphCommentBits.IsWhitespaceValid = true;
0566       return;
0567     }
0568 
0569     ParagraphCommentBits.IsWhitespaceValid = false;
0570 
0571     setSourceRange(SourceRange(Content.front()->getBeginLoc(),
0572                                Content.back()->getEndLoc()));
0573     setLocation(Content.front()->getBeginLoc());
0574   }
0575 
0576   static bool classof(const Comment *C) {
0577     return C->getCommentKind() == CommentKind::ParagraphComment;
0578   }
0579 
0580   child_iterator child_begin() const {
0581     return reinterpret_cast<child_iterator>(Content.begin());
0582   }
0583 
0584   child_iterator child_end() const {
0585     return reinterpret_cast<child_iterator>(Content.end());
0586   }
0587 
0588   bool isWhitespace() const {
0589     if (ParagraphCommentBits.IsWhitespaceValid)
0590       return ParagraphCommentBits.IsWhitespace;
0591 
0592     ParagraphCommentBits.IsWhitespace = isWhitespaceNoCache();
0593     ParagraphCommentBits.IsWhitespaceValid = true;
0594     return ParagraphCommentBits.IsWhitespace;
0595   }
0596 
0597 private:
0598   bool isWhitespaceNoCache() const;
0599 };
0600 
0601 /// A command that has zero or more word-like arguments (number of word-like
0602 /// arguments depends on command name) and a paragraph as an argument
0603 /// (e. g., \\brief).
0604 class BlockCommandComment : public BlockContentComment {
0605 protected:
0606   /// Word-like arguments.
0607   ArrayRef<Argument> Args;
0608 
0609   /// Paragraph argument.
0610   ParagraphComment *Paragraph;
0611 
0612   BlockCommandComment(CommentKind K,
0613                       SourceLocation LocBegin,
0614                       SourceLocation LocEnd,
0615                       unsigned CommandID,
0616                       CommandMarkerKind CommandMarker) :
0617       BlockContentComment(K, LocBegin, LocEnd),
0618       Paragraph(nullptr) {
0619     setLocation(getCommandNameBeginLoc());
0620     BlockCommandCommentBits.CommandID = CommandID;
0621     BlockCommandCommentBits.CommandMarker = CommandMarker;
0622   }
0623 
0624 public:
0625   BlockCommandComment(SourceLocation LocBegin, SourceLocation LocEnd,
0626                       unsigned CommandID, CommandMarkerKind CommandMarker)
0627       : BlockContentComment(CommentKind::BlockCommandComment, LocBegin, LocEnd),
0628         Paragraph(nullptr) {
0629     setLocation(getCommandNameBeginLoc());
0630     BlockCommandCommentBits.CommandID = CommandID;
0631     BlockCommandCommentBits.CommandMarker = CommandMarker;
0632   }
0633 
0634   static bool classof(const Comment *C) {
0635     return C->getCommentKind() >=
0636                CommentKind::FirstBlockCommandCommentConstant &&
0637            C->getCommentKind() <= CommentKind::LastBlockCommandCommentConstant;
0638   }
0639 
0640   child_iterator child_begin() const {
0641     return reinterpret_cast<child_iterator>(&Paragraph);
0642   }
0643 
0644   child_iterator child_end() const {
0645     return reinterpret_cast<child_iterator>(&Paragraph + 1);
0646   }
0647 
0648   unsigned getCommandID() const {
0649     return BlockCommandCommentBits.CommandID;
0650   }
0651 
0652   StringRef getCommandName(const CommandTraits &Traits) const {
0653     return Traits.getCommandInfo(getCommandID())->Name;
0654   }
0655 
0656   SourceLocation getCommandNameBeginLoc() const {
0657     return getBeginLoc().getLocWithOffset(1);
0658   }
0659 
0660   SourceRange getCommandNameRange(const CommandTraits &Traits) const {
0661     StringRef Name = getCommandName(Traits);
0662     return SourceRange(getCommandNameBeginLoc(),
0663                        getBeginLoc().getLocWithOffset(1 + Name.size()));
0664   }
0665 
0666   unsigned getNumArgs() const {
0667     return Args.size();
0668   }
0669 
0670   StringRef getArgText(unsigned Idx) const {
0671     return Args[Idx].Text;
0672   }
0673 
0674   SourceRange getArgRange(unsigned Idx) const {
0675     return Args[Idx].Range;
0676   }
0677 
0678   void setArgs(ArrayRef<Argument> A) {
0679     Args = A;
0680     if (Args.size() > 0) {
0681       SourceLocation NewLocEnd = Args.back().Range.getEnd();
0682       if (NewLocEnd.isValid())
0683         setSourceRange(SourceRange(getBeginLoc(), NewLocEnd));
0684     }
0685   }
0686 
0687   ParagraphComment *getParagraph() const LLVM_READONLY {
0688     return Paragraph;
0689   }
0690 
0691   bool hasNonWhitespaceParagraph() const {
0692     return Paragraph && !Paragraph->isWhitespace();
0693   }
0694 
0695   void setParagraph(ParagraphComment *PC) {
0696     Paragraph = PC;
0697     SourceLocation NewLocEnd = PC->getEndLoc();
0698     if (NewLocEnd.isValid())
0699       setSourceRange(SourceRange(getBeginLoc(), NewLocEnd));
0700   }
0701 
0702   CommandMarkerKind getCommandMarker() const LLVM_READONLY {
0703     return static_cast<CommandMarkerKind>(
0704         BlockCommandCommentBits.CommandMarker);
0705   }
0706 };
0707 
0708 enum class ParamCommandPassDirection { In, Out, InOut };
0709 
0710 /// Doxygen \\param command.
0711 class ParamCommandComment : public BlockCommandComment {
0712 private:
0713   /// Parameter index in the function declaration.
0714   unsigned ParamIndex;
0715 
0716 public:
0717   enum : unsigned {
0718     InvalidParamIndex = ~0U,
0719     VarArgParamIndex = ~0U/*InvalidParamIndex*/ - 1U
0720   };
0721 
0722   ParamCommandComment(SourceLocation LocBegin, SourceLocation LocEnd,
0723                       unsigned CommandID, CommandMarkerKind CommandMarker)
0724       : BlockCommandComment(CommentKind::ParamCommandComment, LocBegin, LocEnd,
0725                             CommandID, CommandMarker),
0726         ParamIndex(InvalidParamIndex) {
0727     ParamCommandCommentBits.Direction =
0728         llvm::to_underlying(ParamCommandPassDirection::In);
0729     ParamCommandCommentBits.IsDirectionExplicit = false;
0730   }
0731 
0732   static bool classof(const Comment *C) {
0733     return C->getCommentKind() == CommentKind::ParamCommandComment;
0734   }
0735 
0736   static const char *getDirectionAsString(ParamCommandPassDirection D);
0737 
0738   ParamCommandPassDirection getDirection() const LLVM_READONLY {
0739     return static_cast<ParamCommandPassDirection>(
0740         ParamCommandCommentBits.Direction);
0741   }
0742 
0743   bool isDirectionExplicit() const LLVM_READONLY {
0744     return ParamCommandCommentBits.IsDirectionExplicit;
0745   }
0746 
0747   void setDirection(ParamCommandPassDirection Direction, bool Explicit) {
0748     ParamCommandCommentBits.Direction = llvm::to_underlying(Direction);
0749     ParamCommandCommentBits.IsDirectionExplicit = Explicit;
0750   }
0751 
0752   bool hasParamName() const {
0753     return getNumArgs() > 0;
0754   }
0755 
0756   StringRef getParamName(const FullComment *FC) const;
0757 
0758   StringRef getParamNameAsWritten() const {
0759     return Args[0].Text;
0760   }
0761 
0762   SourceRange getParamNameRange() const {
0763     return Args[0].Range;
0764   }
0765 
0766   bool isParamIndexValid() const LLVM_READONLY {
0767     return ParamIndex != InvalidParamIndex;
0768   }
0769 
0770   bool isVarArgParam() const LLVM_READONLY {
0771     return ParamIndex == VarArgParamIndex;
0772   }
0773 
0774   void setIsVarArgParam() {
0775     ParamIndex = VarArgParamIndex;
0776     assert(isParamIndexValid());
0777   }
0778 
0779   unsigned getParamIndex() const LLVM_READONLY {
0780     assert(isParamIndexValid());
0781     assert(!isVarArgParam());
0782     return ParamIndex;
0783   }
0784 
0785   void setParamIndex(unsigned Index) {
0786     ParamIndex = Index;
0787     assert(isParamIndexValid());
0788     assert(!isVarArgParam());
0789   }
0790 };
0791 
0792 /// Doxygen \\tparam command, describes a template parameter.
0793 class TParamCommandComment : public BlockCommandComment {
0794 private:
0795   /// If this template parameter name was resolved (found in template parameter
0796   /// list), then this stores a list of position indexes in all template
0797   /// parameter lists.
0798   ///
0799   /// For example:
0800   /// \verbatim
0801   ///     template<typename C, template<typename T> class TT>
0802   ///     void test(TT<int> aaa);
0803   /// \endverbatim
0804   /// For C:  Position = { 0 }
0805   /// For TT: Position = { 1 }
0806   /// For T:  Position = { 1, 0 }
0807   ArrayRef<unsigned> Position;
0808 
0809 public:
0810   TParamCommandComment(SourceLocation LocBegin, SourceLocation LocEnd,
0811                        unsigned CommandID, CommandMarkerKind CommandMarker)
0812       : BlockCommandComment(CommentKind::TParamCommandComment, LocBegin, LocEnd,
0813                             CommandID, CommandMarker) {}
0814 
0815   static bool classof(const Comment *C) {
0816     return C->getCommentKind() == CommentKind::TParamCommandComment;
0817   }
0818 
0819   bool hasParamName() const {
0820     return getNumArgs() > 0;
0821   }
0822 
0823   StringRef getParamName(const FullComment *FC) const;
0824 
0825   StringRef getParamNameAsWritten() const {
0826     return Args[0].Text;
0827   }
0828 
0829   SourceRange getParamNameRange() const {
0830     return Args[0].Range;
0831   }
0832 
0833   bool isPositionValid() const LLVM_READONLY {
0834     return !Position.empty();
0835   }
0836 
0837   unsigned getDepth() const {
0838     assert(isPositionValid());
0839     return Position.size();
0840   }
0841 
0842   unsigned getIndex(unsigned Depth) const {
0843     assert(isPositionValid());
0844     return Position[Depth];
0845   }
0846 
0847   void setPosition(ArrayRef<unsigned> NewPosition) {
0848     Position = NewPosition;
0849     assert(isPositionValid());
0850   }
0851 };
0852 
0853 /// A line of text contained in a verbatim block.
0854 class VerbatimBlockLineComment : public Comment {
0855   StringRef Text;
0856 
0857 public:
0858   VerbatimBlockLineComment(SourceLocation LocBegin, StringRef Text)
0859       : Comment(CommentKind::VerbatimBlockLineComment, LocBegin,
0860                 LocBegin.getLocWithOffset(Text.size())),
0861         Text(Text) {}
0862 
0863   static bool classof(const Comment *C) {
0864     return C->getCommentKind() == CommentKind::VerbatimBlockLineComment;
0865   }
0866 
0867   child_iterator child_begin() const { return nullptr; }
0868 
0869   child_iterator child_end() const { return nullptr; }
0870 
0871   StringRef getText() const LLVM_READONLY {
0872     return Text;
0873   }
0874 };
0875 
0876 /// A verbatim block command (e. g., preformatted code).  Verbatim block has an
0877 /// opening and a closing command and contains multiple lines of text
0878 /// (VerbatimBlockLineComment nodes).
0879 class VerbatimBlockComment : public BlockCommandComment {
0880 protected:
0881   StringRef CloseName;
0882   SourceLocation CloseNameLocBegin;
0883   ArrayRef<VerbatimBlockLineComment *> Lines;
0884 
0885 public:
0886   VerbatimBlockComment(SourceLocation LocBegin, SourceLocation LocEnd,
0887                        unsigned CommandID)
0888       : BlockCommandComment(CommentKind::VerbatimBlockComment, LocBegin, LocEnd,
0889                             CommandID,
0890                             CMK_At) // FIXME: improve source fidelity.
0891   {}
0892 
0893   static bool classof(const Comment *C) {
0894     return C->getCommentKind() == CommentKind::VerbatimBlockComment;
0895   }
0896 
0897   child_iterator child_begin() const {
0898     return reinterpret_cast<child_iterator>(Lines.begin());
0899   }
0900 
0901   child_iterator child_end() const {
0902     return reinterpret_cast<child_iterator>(Lines.end());
0903   }
0904 
0905   void setCloseName(StringRef Name, SourceLocation LocBegin) {
0906     CloseName = Name;
0907     CloseNameLocBegin = LocBegin;
0908   }
0909 
0910   void setLines(ArrayRef<VerbatimBlockLineComment *> L) {
0911     Lines = L;
0912   }
0913 
0914   StringRef getCloseName() const {
0915     return CloseName;
0916   }
0917 
0918   unsigned getNumLines() const {
0919     return Lines.size();
0920   }
0921 
0922   StringRef getText(unsigned LineIdx) const {
0923     return Lines[LineIdx]->getText();
0924   }
0925 };
0926 
0927 /// A verbatim line command.  Verbatim line has an opening command, a single
0928 /// line of text (up to the newline after the opening command) and has no
0929 /// closing command.
0930 class VerbatimLineComment : public BlockCommandComment {
0931 protected:
0932   StringRef Text;
0933   SourceLocation TextBegin;
0934 
0935 public:
0936   VerbatimLineComment(SourceLocation LocBegin, SourceLocation LocEnd,
0937                       unsigned CommandID, SourceLocation TextBegin,
0938                       StringRef Text)
0939       : BlockCommandComment(CommentKind::VerbatimLineComment, LocBegin, LocEnd,
0940                             CommandID,
0941                             CMK_At), // FIXME: improve source fidelity.
0942         Text(Text), TextBegin(TextBegin) {}
0943 
0944   static bool classof(const Comment *C) {
0945     return C->getCommentKind() == CommentKind::VerbatimLineComment;
0946   }
0947 
0948   child_iterator child_begin() const { return nullptr; }
0949 
0950   child_iterator child_end() const { return nullptr; }
0951 
0952   StringRef getText() const {
0953     return Text;
0954   }
0955 
0956   SourceRange getTextRange() const {
0957     return SourceRange(TextBegin, getEndLoc());
0958   }
0959 };
0960 
0961 /// Information about the declaration, useful to clients of FullComment.
0962 struct DeclInfo {
0963   /// Declaration the comment is actually attached to (in the source).
0964   /// Should not be NULL.
0965   const Decl *CommentDecl;
0966 
0967   /// CurrentDecl is the declaration with which the FullComment is associated.
0968   ///
0969   /// It can be different from \c CommentDecl.  It happens when we decide
0970   /// that the comment originally attached to \c CommentDecl is fine for
0971   /// \c CurrentDecl too (for example, for a redeclaration or an overrider of
0972   /// \c CommentDecl).
0973   ///
0974   /// The information in the DeclInfo corresponds to CurrentDecl.
0975   const Decl *CurrentDecl;
0976 
0977   /// Parameters that can be referenced by \\param if \c CommentDecl is something
0978   /// that we consider a "function".
0979   ArrayRef<const ParmVarDecl *> ParamVars;
0980 
0981   /// Function return type if \c CommentDecl is something that we consider
0982   /// a "function".
0983   QualType ReturnType;
0984 
0985   /// Template parameters that can be referenced by \\tparam if \c CommentDecl is
0986   /// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is
0987   /// true).
0988   const TemplateParameterList *TemplateParameters;
0989 
0990   /// A simplified description of \c CommentDecl kind that should be good enough
0991   /// for documentation rendering purposes.
0992   enum DeclKind {
0993     /// Everything else not explicitly mentioned below.
0994     OtherKind,
0995 
0996     /// Something that we consider a "function":
0997     /// \li function,
0998     /// \li function template,
0999     /// \li function template specialization,
1000     /// \li member function,
1001     /// \li member function template,
1002     /// \li member function template specialization,
1003     /// \li ObjC method,
1004     FunctionKind,
1005 
1006     /// Something that we consider a "class":
1007     /// \li class/struct,
1008     /// \li class template,
1009     /// \li class template (partial) specialization.
1010     ClassKind,
1011 
1012     /// Something that we consider a "variable":
1013     /// \li namespace scope variables and variable templates;
1014     /// \li static and non-static class data members and member templates;
1015     /// \li enumerators.
1016     VariableKind,
1017 
1018     /// A C++ namespace.
1019     NamespaceKind,
1020 
1021     /// A C++ typedef-name (a 'typedef' decl specifier or alias-declaration),
1022     /// see \c TypedefNameDecl.
1023     TypedefKind,
1024 
1025     /// An enumeration or scoped enumeration.
1026     EnumKind
1027   };
1028 
1029   /// What kind of template specialization \c CommentDecl is.
1030   enum TemplateDeclKind {
1031     NotTemplate,
1032     Template,
1033     TemplateSpecialization,
1034     TemplatePartialSpecialization
1035   };
1036 
1037   /// If false, only \c CommentDecl is valid.
1038   LLVM_PREFERRED_TYPE(bool)
1039   unsigned IsFilled : 1;
1040 
1041   /// Simplified kind of \c CommentDecl, see \c DeclKind enum.
1042   LLVM_PREFERRED_TYPE(DeclKind)
1043   unsigned Kind : 3;
1044 
1045   /// Is \c CommentDecl a template declaration.
1046   LLVM_PREFERRED_TYPE(TemplateDeclKind)
1047   unsigned TemplateKind : 2;
1048 
1049   /// Is \c CommentDecl an ObjCMethodDecl.
1050   LLVM_PREFERRED_TYPE(bool)
1051   unsigned IsObjCMethod : 1;
1052 
1053   /// Is \c CommentDecl a non-static member function of C++ class or
1054   /// instance method of ObjC class.
1055   /// Can be true only if \c IsFunctionDecl is true.
1056   LLVM_PREFERRED_TYPE(bool)
1057   unsigned IsInstanceMethod : 1;
1058 
1059   /// Is \c CommentDecl a static member function of C++ class or
1060   /// class method of ObjC class.
1061   /// Can be true only if \c IsFunctionDecl is true.
1062   LLVM_PREFERRED_TYPE(bool)
1063   unsigned IsClassMethod : 1;
1064 
1065   /// Is \c CommentDecl something we consider a "function" that's variadic.
1066   LLVM_PREFERRED_TYPE(bool)
1067   unsigned IsVariadic : 1;
1068 
1069   void fill();
1070 
1071   DeclKind getKind() const LLVM_READONLY {
1072     return static_cast<DeclKind>(Kind);
1073   }
1074 
1075   TemplateDeclKind getTemplateKind() const LLVM_READONLY {
1076     return static_cast<TemplateDeclKind>(TemplateKind);
1077   }
1078 
1079   bool involvesFunctionType() const { return !ReturnType.isNull(); }
1080 };
1081 
1082 /// A full comment attached to a declaration, contains block content.
1083 class FullComment : public Comment {
1084   ArrayRef<BlockContentComment *> Blocks;
1085   DeclInfo *ThisDeclInfo;
1086 
1087 public:
1088   FullComment(ArrayRef<BlockContentComment *> Blocks, DeclInfo *D)
1089       : Comment(CommentKind::FullComment, SourceLocation(), SourceLocation()),
1090         Blocks(Blocks), ThisDeclInfo(D) {
1091     if (Blocks.empty())
1092       return;
1093 
1094     setSourceRange(
1095         SourceRange(Blocks.front()->getBeginLoc(), Blocks.back()->getEndLoc()));
1096     setLocation(Blocks.front()->getBeginLoc());
1097   }
1098 
1099   static bool classof(const Comment *C) {
1100     return C->getCommentKind() == CommentKind::FullComment;
1101   }
1102 
1103   child_iterator child_begin() const {
1104     return reinterpret_cast<child_iterator>(Blocks.begin());
1105   }
1106 
1107   child_iterator child_end() const {
1108     return reinterpret_cast<child_iterator>(Blocks.end());
1109   }
1110 
1111   const Decl *getDecl() const LLVM_READONLY {
1112     return ThisDeclInfo->CommentDecl;
1113   }
1114 
1115   const DeclInfo *getDeclInfo() const LLVM_READONLY {
1116     if (!ThisDeclInfo->IsFilled)
1117       ThisDeclInfo->fill();
1118     return ThisDeclInfo;
1119   }
1120 
1121   ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
1122 
1123 };
1124 } // end namespace comments
1125 } // end namespace clang
1126 
1127 #endif
1128