| //===--- Comment.h - Comment AST nodes --------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines comment AST nodes. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_AST_COMMENT_H |
| #define LLVM_CLANG_AST_COMMENT_H |
| |
| #include "clang/AST/CommentCommandTraits.h" |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/AST/Type.h" |
| #include "clang/Basic/SourceLocation.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/StringRef.h" |
| |
| namespace clang { |
| class Decl; |
| class ParmVarDecl; |
| class TemplateParameterList; |
| |
| namespace comments { |
| class FullComment; |
| |
| /// Describes the syntax that was used in a documentation command. |
| /// |
| /// Exact values of this enumeration are important because they used to select |
| /// parts of diagnostic messages. Audit diagnostics before changing or adding |
| /// a new value. |
| enum CommandMarkerKind { |
| /// Command started with a backslash character: |
| /// \code |
| /// \foo |
| /// \endcode |
| CMK_Backslash = 0, |
| |
| /// Command started with an 'at' character: |
| /// \code |
| /// @foo |
| /// \endcode |
| CMK_At = 1 |
| }; |
| |
| /// Any part of the comment. |
| /// Abstract class. |
| class Comment { |
| protected: |
| /// Preferred location to show caret. |
| SourceLocation Loc; |
| |
| /// Source range of this AST node. |
| SourceRange Range; |
| |
| class CommentBitfields { |
| friend class Comment; |
| |
| /// Type of this AST node. |
| unsigned Kind : 8; |
| }; |
| enum { NumCommentBits = 8 }; |
| |
| class InlineContentCommentBitfields { |
| friend class InlineContentComment; |
| |
| unsigned : NumCommentBits; |
| |
| /// True if there is a newline after this inline content node. |
| /// (There is no separate AST node for a newline.) |
| unsigned HasTrailingNewline : 1; |
| }; |
| enum { NumInlineContentCommentBits = NumCommentBits + 1 }; |
| |
| class TextCommentBitfields { |
| friend class TextComment; |
| |
| unsigned : NumInlineContentCommentBits; |
| |
| /// True if \c IsWhitespace field contains a valid value. |
| mutable unsigned IsWhitespaceValid : 1; |
| |
| /// True if this comment AST node contains only whitespace. |
| mutable unsigned IsWhitespace : 1; |
| }; |
| enum { NumTextCommentBits = NumInlineContentCommentBits + 2 }; |
| |
| class InlineCommandCommentBitfields { |
| friend class InlineCommandComment; |
| |
| unsigned : NumInlineContentCommentBits; |
| |
| unsigned RenderKind : 2; |
| unsigned CommandID : CommandInfo::NumCommandIDBits; |
| }; |
| enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 2 + |
| CommandInfo::NumCommandIDBits }; |
| |
| class HTMLTagCommentBitfields { |
| friend class HTMLTagComment; |
| |
| unsigned : NumInlineContentCommentBits; |
| |
| /// True if we found that this tag is malformed in some way. |
| unsigned IsMalformed : 1; |
| }; |
| enum { NumHTMLTagCommentBits = NumInlineContentCommentBits + 1 }; |
| |
| class HTMLStartTagCommentBitfields { |
| friend class HTMLStartTagComment; |
| |
| unsigned : NumHTMLTagCommentBits; |
| |
| /// True if this tag is self-closing (e. g., <br />). This is based on tag |
| /// spelling in comment (plain <br> would not set this flag). |
| unsigned IsSelfClosing : 1; |
| }; |
| enum { NumHTMLStartTagCommentBits = NumHTMLTagCommentBits + 1 }; |
| |
| class ParagraphCommentBitfields { |
| friend class ParagraphComment; |
| |
| unsigned : NumCommentBits; |
| |
| /// True if \c IsWhitespace field contains a valid value. |
| mutable unsigned IsWhitespaceValid : 1; |
| |
| /// True if this comment AST node contains only whitespace. |
| mutable unsigned IsWhitespace : 1; |
| }; |
| enum { NumParagraphCommentBits = NumCommentBits + 2 }; |
| |
| class BlockCommandCommentBitfields { |
| friend class BlockCommandComment; |
| |
| unsigned : NumCommentBits; |
| |
| unsigned CommandID : CommandInfo::NumCommandIDBits; |
| |
| /// Describes the syntax that was used in a documentation command. |
| /// Contains values from CommandMarkerKind enum. |
| unsigned CommandMarker : 1; |
| }; |
| enum { NumBlockCommandCommentBits = NumCommentBits + |
| CommandInfo::NumCommandIDBits + 1 }; |
| |
| class ParamCommandCommentBitfields { |
| friend class ParamCommandComment; |
| |
| unsigned : NumBlockCommandCommentBits; |
| |
| /// Parameter passing direction, see ParamCommandComment::PassDirection. |
| unsigned Direction : 2; |
| |
| /// True if direction was specified explicitly in the comment. |
| unsigned IsDirectionExplicit : 1; |
| }; |
| enum { NumParamCommandCommentBits = NumBlockCommandCommentBits + 3 }; |
| |
| union { |
| CommentBitfields CommentBits; |
| InlineContentCommentBitfields InlineContentCommentBits; |
| TextCommentBitfields TextCommentBits; |
| InlineCommandCommentBitfields InlineCommandCommentBits; |
| HTMLTagCommentBitfields HTMLTagCommentBits; |
| HTMLStartTagCommentBitfields HTMLStartTagCommentBits; |
| ParagraphCommentBitfields ParagraphCommentBits; |
| BlockCommandCommentBitfields BlockCommandCommentBits; |
| ParamCommandCommentBitfields ParamCommandCommentBits; |
| }; |
| |
| void setSourceRange(SourceRange SR) { |
| Range = SR; |
| } |
| |
| void setLocation(SourceLocation L) { |
| Loc = L; |
| } |
| |
| public: |
| enum CommentKind { |
| NoCommentKind = 0, |
| #define COMMENT(CLASS, PARENT) CLASS##Kind, |
| #define COMMENT_RANGE(BASE, FIRST, LAST) \ |
| First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind, |
| #define LAST_COMMENT_RANGE(BASE, FIRST, LAST) \ |
| First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind |
| #define ABSTRACT_COMMENT(COMMENT) |
| #include "clang/AST/CommentNodes.inc" |
| }; |
| |
| Comment(CommentKind K, |
| SourceLocation LocBegin, |
| SourceLocation LocEnd) : |
| Loc(LocBegin), Range(SourceRange(LocBegin, LocEnd)) { |
| CommentBits.Kind = K; |
| } |
| |
| CommentKind getCommentKind() const { |
| return static_cast<CommentKind>(CommentBits.Kind); |
| } |
| |
| const char *getCommentKindName() const; |
| |
| void dump() const; |
| void dumpColor() const; |
| void dump(const ASTContext &Context) const; |
| void dump(raw_ostream &OS, const CommandTraits *Traits, |
| const SourceManager *SM) const; |
| |
| SourceRange getSourceRange() const LLVM_READONLY { return Range; } |
| |
| SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } |
| |
| SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } |
| |
| SourceLocation getLocation() const LLVM_READONLY { return Loc; } |
| |
| typedef Comment * const *child_iterator; |
| |
| child_iterator child_begin() const; |
| child_iterator child_end() const; |
| |
| // TODO: const child iterator |
| |
| unsigned child_count() const { |
| return child_end() - child_begin(); |
| } |
| }; |
| |
| /// Inline content (contained within a block). |
| /// Abstract class. |
| class InlineContentComment : public Comment { |
| protected: |
| InlineContentComment(CommentKind K, |
| SourceLocation LocBegin, |
| SourceLocation LocEnd) : |
| Comment(K, LocBegin, LocEnd) { |
| InlineContentCommentBits.HasTrailingNewline = 0; |
| } |
| |
| public: |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() >= FirstInlineContentCommentConstant && |
| C->getCommentKind() <= LastInlineContentCommentConstant; |
| } |
| |
| void addTrailingNewline() { |
| InlineContentCommentBits.HasTrailingNewline = 1; |
| } |
| |
| bool hasTrailingNewline() const { |
| return InlineContentCommentBits.HasTrailingNewline; |
| } |
| }; |
| |
| /// Plain text. |
| class TextComment : public InlineContentComment { |
| StringRef Text; |
| |
| public: |
| TextComment(SourceLocation LocBegin, |
| SourceLocation LocEnd, |
| StringRef Text) : |
| InlineContentComment(TextCommentKind, LocBegin, LocEnd), |
| Text(Text) { |
| TextCommentBits.IsWhitespaceValid = false; |
| } |
| |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() == TextCommentKind; |
| } |
| |
| child_iterator child_begin() const { return nullptr; } |
| |
| child_iterator child_end() const { return nullptr; } |
| |
| StringRef getText() const LLVM_READONLY { return Text; } |
| |
| bool isWhitespace() const { |
| if (TextCommentBits.IsWhitespaceValid) |
| return TextCommentBits.IsWhitespace; |
| |
| TextCommentBits.IsWhitespace = isWhitespaceNoCache(); |
| TextCommentBits.IsWhitespaceValid = true; |
| return TextCommentBits.IsWhitespace; |
| } |
| |
| private: |
| bool isWhitespaceNoCache() const; |
| }; |
| |
| /// A command with word-like arguments that is considered inline content. |
| class InlineCommandComment : public InlineContentComment { |
| public: |
| struct Argument { |
| SourceRange Range; |
| StringRef Text; |
| |
| Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { } |
| }; |
| |
| /// The most appropriate rendering mode for this command, chosen on command |
| /// semantics in Doxygen. |
| enum RenderKind { |
| RenderNormal, |
| RenderBold, |
| RenderMonospaced, |
| RenderEmphasized |
| }; |
| |
| protected: |
| /// Command arguments. |
| ArrayRef<Argument> Args; |
| |
| public: |
| InlineCommandComment(SourceLocation LocBegin, |
| SourceLocation LocEnd, |
| unsigned CommandID, |
| RenderKind RK, |
| ArrayRef<Argument> Args) : |
| InlineContentComment(InlineCommandCommentKind, LocBegin, LocEnd), |
| Args(Args) { |
| InlineCommandCommentBits.RenderKind = RK; |
| InlineCommandCommentBits.CommandID = CommandID; |
| } |
| |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() == InlineCommandCommentKind; |
| } |
| |
| child_iterator child_begin() const { return nullptr; } |
| |
| child_iterator child_end() const { return nullptr; } |
| |
| unsigned getCommandID() const { |
| return InlineCommandCommentBits.CommandID; |
| } |
| |
| StringRef getCommandName(const CommandTraits &Traits) const { |
| return Traits.getCommandInfo(getCommandID())->Name; |
| } |
| |
| SourceRange getCommandNameRange() const { |
| return SourceRange(getBeginLoc().getLocWithOffset(-1), getEndLoc()); |
| } |
| |
| RenderKind getRenderKind() const { |
| return static_cast<RenderKind>(InlineCommandCommentBits.RenderKind); |
| } |
| |
| unsigned getNumArgs() const { |
| return Args.size(); |
| } |
| |
| StringRef getArgText(unsigned Idx) const { |
| return Args[Idx].Text; |
| } |
| |
| SourceRange getArgRange(unsigned Idx) const { |
| return Args[Idx].Range; |
| } |
| }; |
| |
| /// Abstract class for opening and closing HTML tags. HTML tags are always |
| /// treated as inline content (regardless HTML semantics). |
| class HTMLTagComment : public InlineContentComment { |
| protected: |
| StringRef TagName; |
| SourceRange TagNameRange; |
| |
| HTMLTagComment(CommentKind K, |
| SourceLocation LocBegin, |
| SourceLocation LocEnd, |
| StringRef TagName, |
| SourceLocation TagNameBegin, |
| SourceLocation TagNameEnd) : |
| InlineContentComment(K, LocBegin, LocEnd), |
| TagName(TagName), |
| TagNameRange(TagNameBegin, TagNameEnd) { |
| setLocation(TagNameBegin); |
| HTMLTagCommentBits.IsMalformed = 0; |
| } |
| |
| public: |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() >= FirstHTMLTagCommentConstant && |
| C->getCommentKind() <= LastHTMLTagCommentConstant; |
| } |
| |
| StringRef getTagName() const LLVM_READONLY { return TagName; } |
| |
| SourceRange getTagNameSourceRange() const LLVM_READONLY { |
| SourceLocation L = getLocation(); |
| return SourceRange(L.getLocWithOffset(1), |
| L.getLocWithOffset(1 + TagName.size())); |
| } |
| |
| bool isMalformed() const { |
| return HTMLTagCommentBits.IsMalformed; |
| } |
| |
| void setIsMalformed() { |
| HTMLTagCommentBits.IsMalformed = 1; |
| } |
| }; |
| |
| /// An opening HTML tag with attributes. |
| class HTMLStartTagComment : public HTMLTagComment { |
| public: |
| class Attribute { |
| public: |
| SourceLocation NameLocBegin; |
| StringRef Name; |
| |
| SourceLocation EqualsLoc; |
| |
| SourceRange ValueRange; |
| StringRef Value; |
| |
| Attribute() { } |
| |
| Attribute(SourceLocation NameLocBegin, StringRef Name) : |
| NameLocBegin(NameLocBegin), Name(Name), |
| EqualsLoc(SourceLocation()), |
| ValueRange(SourceRange()), Value(StringRef()) |
| { } |
| |
| Attribute(SourceLocation NameLocBegin, StringRef Name, |
| SourceLocation EqualsLoc, |
| SourceRange ValueRange, StringRef Value) : |
| NameLocBegin(NameLocBegin), Name(Name), |
| EqualsLoc(EqualsLoc), |
| ValueRange(ValueRange), Value(Value) |
| { } |
| |
| SourceLocation getNameLocEnd() const { |
| return NameLocBegin.getLocWithOffset(Name.size()); |
| } |
| |
| SourceRange getNameRange() const { |
| return SourceRange(NameLocBegin, getNameLocEnd()); |
| } |
| }; |
| |
| private: |
| ArrayRef<Attribute> Attributes; |
| |
| public: |
| HTMLStartTagComment(SourceLocation LocBegin, |
| StringRef TagName) : |
| HTMLTagComment(HTMLStartTagCommentKind, |
| LocBegin, LocBegin.getLocWithOffset(1 + TagName.size()), |
| TagName, |
| LocBegin.getLocWithOffset(1), |
| LocBegin.getLocWithOffset(1 + TagName.size())) { |
| HTMLStartTagCommentBits.IsSelfClosing = false; |
| } |
| |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() == HTMLStartTagCommentKind; |
| } |
| |
| child_iterator child_begin() const { return nullptr; } |
| |
| child_iterator child_end() const { return nullptr; } |
| |
| unsigned getNumAttrs() const { |
| return Attributes.size(); |
| } |
| |
| const Attribute &getAttr(unsigned Idx) const { |
| return Attributes[Idx]; |
| } |
| |
| void setAttrs(ArrayRef<Attribute> Attrs) { |
| Attributes = Attrs; |
| if (!Attrs.empty()) { |
| const Attribute &Attr = Attrs.back(); |
| SourceLocation L = Attr.ValueRange.getEnd(); |
| if (L.isValid()) |
| Range.setEnd(L); |
| else { |
| Range.setEnd(Attr.getNameLocEnd()); |
| } |
| } |
| } |
| |
| void setGreaterLoc(SourceLocation GreaterLoc) { |
| Range.setEnd(GreaterLoc); |
| } |
| |
| bool isSelfClosing() const { |
| return HTMLStartTagCommentBits.IsSelfClosing; |
| } |
| |
| void setSelfClosing() { |
| HTMLStartTagCommentBits.IsSelfClosing = true; |
| } |
| }; |
| |
| /// A closing HTML tag. |
| class HTMLEndTagComment : public HTMLTagComment { |
| public: |
| HTMLEndTagComment(SourceLocation LocBegin, |
| SourceLocation LocEnd, |
| StringRef TagName) : |
| HTMLTagComment(HTMLEndTagCommentKind, |
| LocBegin, LocEnd, |
| TagName, |
| LocBegin.getLocWithOffset(2), |
| LocBegin.getLocWithOffset(2 + TagName.size())) |
| { } |
| |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() == HTMLEndTagCommentKind; |
| } |
| |
| child_iterator child_begin() const { return nullptr; } |
| |
| child_iterator child_end() const { return nullptr; } |
| }; |
| |
| /// Block content (contains inline content). |
| /// Abstract class. |
| class BlockContentComment : public Comment { |
| protected: |
| BlockContentComment(CommentKind K, |
| SourceLocation LocBegin, |
| SourceLocation LocEnd) : |
| Comment(K, LocBegin, LocEnd) |
| { } |
| |
| public: |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() >= FirstBlockContentCommentConstant && |
| C->getCommentKind() <= LastBlockContentCommentConstant; |
| } |
| }; |
| |
| /// A single paragraph that contains inline content. |
| class ParagraphComment : public BlockContentComment { |
| ArrayRef<InlineContentComment *> Content; |
| |
| public: |
| ParagraphComment(ArrayRef<InlineContentComment *> Content) : |
| BlockContentComment(ParagraphCommentKind, |
| SourceLocation(), |
| SourceLocation()), |
| Content(Content) { |
| if (Content.empty()) { |
| ParagraphCommentBits.IsWhitespace = true; |
| ParagraphCommentBits.IsWhitespaceValid = true; |
| return; |
| } |
| |
| ParagraphCommentBits.IsWhitespaceValid = false; |
| |
| setSourceRange(SourceRange(Content.front()->getBeginLoc(), |
| Content.back()->getEndLoc())); |
| setLocation(Content.front()->getBeginLoc()); |
| } |
| |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() == ParagraphCommentKind; |
| } |
| |
| child_iterator child_begin() const { |
| return reinterpret_cast<child_iterator>(Content.begin()); |
| } |
| |
| child_iterator child_end() const { |
| return reinterpret_cast<child_iterator>(Content.end()); |
| } |
| |
| bool isWhitespace() const { |
| if (ParagraphCommentBits.IsWhitespaceValid) |
| return ParagraphCommentBits.IsWhitespace; |
| |
| ParagraphCommentBits.IsWhitespace = isWhitespaceNoCache(); |
| ParagraphCommentBits.IsWhitespaceValid = true; |
| return ParagraphCommentBits.IsWhitespace; |
| } |
| |
| private: |
| bool isWhitespaceNoCache() const; |
| }; |
| |
| /// A command that has zero or more word-like arguments (number of word-like |
| /// arguments depends on command name) and a paragraph as an argument |
| /// (e. g., \\brief). |
| class BlockCommandComment : public BlockContentComment { |
| public: |
| struct Argument { |
| SourceRange Range; |
| StringRef Text; |
| |
| Argument() { } |
| Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { } |
| }; |
| |
| protected: |
| /// Word-like arguments. |
| ArrayRef<Argument> Args; |
| |
| /// Paragraph argument. |
| ParagraphComment *Paragraph; |
| |
| BlockCommandComment(CommentKind K, |
| SourceLocation LocBegin, |
| SourceLocation LocEnd, |
| unsigned CommandID, |
| CommandMarkerKind CommandMarker) : |
| BlockContentComment(K, LocBegin, LocEnd), |
| Paragraph(nullptr) { |
| setLocation(getCommandNameBeginLoc()); |
| BlockCommandCommentBits.CommandID = CommandID; |
| BlockCommandCommentBits.CommandMarker = CommandMarker; |
| } |
| |
| public: |
| BlockCommandComment(SourceLocation LocBegin, |
| SourceLocation LocEnd, |
| unsigned CommandID, |
| CommandMarkerKind CommandMarker) : |
| BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd), |
| Paragraph(nullptr) { |
| setLocation(getCommandNameBeginLoc()); |
| BlockCommandCommentBits.CommandID = CommandID; |
| BlockCommandCommentBits.CommandMarker = CommandMarker; |
| } |
| |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() >= FirstBlockCommandCommentConstant && |
| C->getCommentKind() <= LastBlockCommandCommentConstant; |
| } |
| |
| child_iterator child_begin() const { |
| return reinterpret_cast<child_iterator>(&Paragraph); |
| } |
| |
| child_iterator child_end() const { |
| return reinterpret_cast<child_iterator>(&Paragraph + 1); |
| } |
| |
| unsigned getCommandID() const { |
| return BlockCommandCommentBits.CommandID; |
| } |
| |
| StringRef getCommandName(const CommandTraits &Traits) const { |
| return Traits.getCommandInfo(getCommandID())->Name; |
| } |
| |
| SourceLocation getCommandNameBeginLoc() const { |
| return getBeginLoc().getLocWithOffset(1); |
| } |
| |
| SourceRange getCommandNameRange(const CommandTraits &Traits) const { |
| StringRef Name = getCommandName(Traits); |
| return SourceRange(getCommandNameBeginLoc(), |
| getBeginLoc().getLocWithOffset(1 + Name.size())); |
| } |
| |
| unsigned getNumArgs() const { |
| return Args.size(); |
| } |
| |
| StringRef getArgText(unsigned Idx) const { |
| return Args[Idx].Text; |
| } |
| |
| SourceRange getArgRange(unsigned Idx) const { |
| return Args[Idx].Range; |
| } |
| |
| void setArgs(ArrayRef<Argument> A) { |
| Args = A; |
| if (Args.size() > 0) { |
| SourceLocation NewLocEnd = Args.back().Range.getEnd(); |
| if (NewLocEnd.isValid()) |
| setSourceRange(SourceRange(getBeginLoc(), NewLocEnd)); |
| } |
| } |
| |
| ParagraphComment *getParagraph() const LLVM_READONLY { |
| return Paragraph; |
| } |
| |
| bool hasNonWhitespaceParagraph() const { |
| return Paragraph && !Paragraph->isWhitespace(); |
| } |
| |
| void setParagraph(ParagraphComment *PC) { |
| Paragraph = PC; |
| SourceLocation NewLocEnd = PC->getEndLoc(); |
| if (NewLocEnd.isValid()) |
| setSourceRange(SourceRange(getBeginLoc(), NewLocEnd)); |
| } |
| |
| CommandMarkerKind getCommandMarker() const LLVM_READONLY { |
| return static_cast<CommandMarkerKind>( |
| BlockCommandCommentBits.CommandMarker); |
| } |
| }; |
| |
| /// Doxygen \\param command. |
| class ParamCommandComment : public BlockCommandComment { |
| private: |
| /// Parameter index in the function declaration. |
| unsigned ParamIndex; |
| |
| public: |
| enum : unsigned { |
| InvalidParamIndex = ~0U, |
| VarArgParamIndex = ~0U/*InvalidParamIndex*/ - 1U |
| }; |
| |
| ParamCommandComment(SourceLocation LocBegin, |
| SourceLocation LocEnd, |
| unsigned CommandID, |
| CommandMarkerKind CommandMarker) : |
| BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, |
| CommandID, CommandMarker), |
| ParamIndex(InvalidParamIndex) { |
| ParamCommandCommentBits.Direction = In; |
| ParamCommandCommentBits.IsDirectionExplicit = false; |
| } |
| |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() == ParamCommandCommentKind; |
| } |
| |
| enum PassDirection { |
| In, |
| Out, |
| InOut |
| }; |
| |
| static const char *getDirectionAsString(PassDirection D); |
| |
| PassDirection getDirection() const LLVM_READONLY { |
| return static_cast<PassDirection>(ParamCommandCommentBits.Direction); |
| } |
| |
| bool isDirectionExplicit() const LLVM_READONLY { |
| return ParamCommandCommentBits.IsDirectionExplicit; |
| } |
| |
| void setDirection(PassDirection Direction, bool Explicit) { |
| ParamCommandCommentBits.Direction = Direction; |
| ParamCommandCommentBits.IsDirectionExplicit = Explicit; |
| } |
| |
| bool hasParamName() const { |
| return getNumArgs() > 0; |
| } |
| |
| StringRef getParamName(const FullComment *FC) const; |
| |
| StringRef getParamNameAsWritten() const { |
| return Args[0].Text; |
| } |
| |
| SourceRange getParamNameRange() const { |
| return Args[0].Range; |
| } |
| |
| bool isParamIndexValid() const LLVM_READONLY { |
| return ParamIndex != InvalidParamIndex; |
| } |
| |
| bool isVarArgParam() const LLVM_READONLY { |
| return ParamIndex == VarArgParamIndex; |
| } |
| |
| void setIsVarArgParam() { |
| ParamIndex = VarArgParamIndex; |
| assert(isParamIndexValid()); |
| } |
| |
| unsigned getParamIndex() const LLVM_READONLY { |
| assert(isParamIndexValid()); |
| assert(!isVarArgParam()); |
| return ParamIndex; |
| } |
| |
| void setParamIndex(unsigned Index) { |
| ParamIndex = Index; |
| assert(isParamIndexValid()); |
| assert(!isVarArgParam()); |
| } |
| }; |
| |
| /// Doxygen \\tparam command, describes a template parameter. |
| class TParamCommandComment : public BlockCommandComment { |
| private: |
| /// If this template parameter name was resolved (found in template parameter |
| /// list), then this stores a list of position indexes in all template |
| /// parameter lists. |
| /// |
| /// For example: |
| /// \verbatim |
| /// template<typename C, template<typename T> class TT> |
| /// void test(TT<int> aaa); |
| /// \endverbatim |
| /// For C: Position = { 0 } |
| /// For TT: Position = { 1 } |
| /// For T: Position = { 1, 0 } |
| ArrayRef<unsigned> Position; |
| |
| public: |
| TParamCommandComment(SourceLocation LocBegin, |
| SourceLocation LocEnd, |
| unsigned CommandID, |
| CommandMarkerKind CommandMarker) : |
| BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID, |
| CommandMarker) |
| { } |
| |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() == TParamCommandCommentKind; |
| } |
| |
| bool hasParamName() const { |
| return getNumArgs() > 0; |
| } |
| |
| StringRef getParamName(const FullComment *FC) const; |
| |
| StringRef getParamNameAsWritten() const { |
| return Args[0].Text; |
| } |
| |
| SourceRange getParamNameRange() const { |
| return Args[0].Range; |
| } |
| |
| bool isPositionValid() const LLVM_READONLY { |
| return !Position.empty(); |
| } |
| |
| unsigned getDepth() const { |
| assert(isPositionValid()); |
| return Position.size(); |
| } |
| |
| unsigned getIndex(unsigned Depth) const { |
| assert(isPositionValid()); |
| return Position[Depth]; |
| } |
| |
| void setPosition(ArrayRef<unsigned> NewPosition) { |
| Position = NewPosition; |
| assert(isPositionValid()); |
| } |
| }; |
| |
| /// A line of text contained in a verbatim block. |
| class VerbatimBlockLineComment : public Comment { |
| StringRef Text; |
| |
| public: |
| VerbatimBlockLineComment(SourceLocation LocBegin, |
| StringRef Text) : |
| Comment(VerbatimBlockLineCommentKind, |
| LocBegin, |
| LocBegin.getLocWithOffset(Text.size())), |
| Text(Text) |
| { } |
| |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() == VerbatimBlockLineCommentKind; |
| } |
| |
| child_iterator child_begin() const { return nullptr; } |
| |
| child_iterator child_end() const { return nullptr; } |
| |
| StringRef getText() const LLVM_READONLY { |
| return Text; |
| } |
| }; |
| |
| /// A verbatim block command (e. g., preformatted code). Verbatim block has an |
| /// opening and a closing command and contains multiple lines of text |
| /// (VerbatimBlockLineComment nodes). |
| class VerbatimBlockComment : public BlockCommandComment { |
| protected: |
| StringRef CloseName; |
| SourceLocation CloseNameLocBegin; |
| ArrayRef<VerbatimBlockLineComment *> Lines; |
| |
| public: |
| VerbatimBlockComment(SourceLocation LocBegin, |
| SourceLocation LocEnd, |
| unsigned CommandID) : |
| BlockCommandComment(VerbatimBlockCommentKind, |
| LocBegin, LocEnd, CommandID, |
| CMK_At) // FIXME: improve source fidelity. |
| { } |
| |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() == VerbatimBlockCommentKind; |
| } |
| |
| child_iterator child_begin() const { |
| return reinterpret_cast<child_iterator>(Lines.begin()); |
| } |
| |
| child_iterator child_end() const { |
| return reinterpret_cast<child_iterator>(Lines.end()); |
| } |
| |
| void setCloseName(StringRef Name, SourceLocation LocBegin) { |
| CloseName = Name; |
| CloseNameLocBegin = LocBegin; |
| } |
| |
| void setLines(ArrayRef<VerbatimBlockLineComment *> L) { |
| Lines = L; |
| } |
| |
| StringRef getCloseName() const { |
| return CloseName; |
| } |
| |
| unsigned getNumLines() const { |
| return Lines.size(); |
| } |
| |
| StringRef getText(unsigned LineIdx) const { |
| return Lines[LineIdx]->getText(); |
| } |
| }; |
| |
| /// A verbatim line command. Verbatim line has an opening command, a single |
| /// line of text (up to the newline after the opening command) and has no |
| /// closing command. |
| class VerbatimLineComment : public BlockCommandComment { |
| protected: |
| StringRef Text; |
| SourceLocation TextBegin; |
| |
| public: |
| VerbatimLineComment(SourceLocation LocBegin, |
| SourceLocation LocEnd, |
| unsigned CommandID, |
| SourceLocation TextBegin, |
| StringRef Text) : |
| BlockCommandComment(VerbatimLineCommentKind, |
| LocBegin, LocEnd, |
| CommandID, |
| CMK_At), // FIXME: improve source fidelity. |
| Text(Text), |
| TextBegin(TextBegin) |
| { } |
| |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() == VerbatimLineCommentKind; |
| } |
| |
| child_iterator child_begin() const { return nullptr; } |
| |
| child_iterator child_end() const { return nullptr; } |
| |
| StringRef getText() const { |
| return Text; |
| } |
| |
| SourceRange getTextRange() const { |
| return SourceRange(TextBegin, getEndLoc()); |
| } |
| }; |
| |
| /// Information about the declaration, useful to clients of FullComment. |
| struct DeclInfo { |
| /// Declaration the comment is actually attached to (in the source). |
| /// Should not be NULL. |
| const Decl *CommentDecl; |
| |
| /// CurrentDecl is the declaration with which the FullComment is associated. |
| /// |
| /// It can be different from \c CommentDecl. It happens when we decide |
| /// that the comment originally attached to \c CommentDecl is fine for |
| /// \c CurrentDecl too (for example, for a redeclaration or an overrider of |
| /// \c CommentDecl). |
| /// |
| /// The information in the DeclInfo corresponds to CurrentDecl. |
| const Decl *CurrentDecl; |
| |
| /// Parameters that can be referenced by \\param if \c CommentDecl is something |
| /// that we consider a "function". |
| ArrayRef<const ParmVarDecl *> ParamVars; |
| |
| /// Function return type if \c CommentDecl is something that we consider |
| /// a "function". |
| QualType ReturnType; |
| |
| /// Template parameters that can be referenced by \\tparam if \c CommentDecl is |
| /// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is |
| /// true). |
| const TemplateParameterList *TemplateParameters; |
| |
| /// A simplified description of \c CommentDecl kind that should be good enough |
| /// for documentation rendering purposes. |
| enum DeclKind { |
| /// Everything else not explicitly mentioned below. |
| OtherKind, |
| |
| /// Something that we consider a "function": |
| /// \li function, |
| /// \li function template, |
| /// \li function template specialization, |
| /// \li member function, |
| /// \li member function template, |
| /// \li member function template specialization, |
| /// \li ObjC method, |
| /// \li a typedef for a function pointer, member function pointer, |
| /// ObjC block. |
| FunctionKind, |
| |
| /// Something that we consider a "class": |
| /// \li class/struct, |
| /// \li class template, |
| /// \li class template (partial) specialization. |
| ClassKind, |
| |
| /// Something that we consider a "variable": |
| /// \li namespace scope variables; |
| /// \li static and non-static class data members; |
| /// \li enumerators. |
| VariableKind, |
| |
| /// A C++ namespace. |
| NamespaceKind, |
| |
| /// A C++ typedef-name (a 'typedef' decl specifier or alias-declaration), |
| /// see \c TypedefNameDecl. |
| TypedefKind, |
| |
| /// An enumeration or scoped enumeration. |
| EnumKind |
| }; |
| |
| /// What kind of template specialization \c CommentDecl is. |
| enum TemplateDeclKind { |
| NotTemplate, |
| Template, |
| TemplateSpecialization, |
| TemplatePartialSpecialization |
| }; |
| |
| /// If false, only \c CommentDecl is valid. |
| unsigned IsFilled : 1; |
| |
| /// Simplified kind of \c CommentDecl, see \c DeclKind enum. |
| unsigned Kind : 3; |
| |
| /// Is \c CommentDecl a template declaration. |
| unsigned TemplateKind : 2; |
| |
| /// Is \c CommentDecl an ObjCMethodDecl. |
| unsigned IsObjCMethod : 1; |
| |
| /// Is \c CommentDecl a non-static member function of C++ class or |
| /// instance method of ObjC class. |
| /// Can be true only if \c IsFunctionDecl is true. |
| unsigned IsInstanceMethod : 1; |
| |
| /// Is \c CommentDecl a static member function of C++ class or |
| /// class method of ObjC class. |
| /// Can be true only if \c IsFunctionDecl is true. |
| unsigned IsClassMethod : 1; |
| |
| void fill(); |
| |
| DeclKind getKind() const LLVM_READONLY { |
| return static_cast<DeclKind>(Kind); |
| } |
| |
| TemplateDeclKind getTemplateKind() const LLVM_READONLY { |
| return static_cast<TemplateDeclKind>(TemplateKind); |
| } |
| }; |
| |
| /// A full comment attached to a declaration, contains block content. |
| class FullComment : public Comment { |
| ArrayRef<BlockContentComment *> Blocks; |
| DeclInfo *ThisDeclInfo; |
| |
| public: |
| FullComment(ArrayRef<BlockContentComment *> Blocks, DeclInfo *D) : |
| Comment(FullCommentKind, SourceLocation(), SourceLocation()), |
| Blocks(Blocks), ThisDeclInfo(D) { |
| if (Blocks.empty()) |
| return; |
| |
| setSourceRange( |
| SourceRange(Blocks.front()->getBeginLoc(), Blocks.back()->getEndLoc())); |
| setLocation(Blocks.front()->getBeginLoc()); |
| } |
| |
| static bool classof(const Comment *C) { |
| return C->getCommentKind() == FullCommentKind; |
| } |
| |
| child_iterator child_begin() const { |
| return reinterpret_cast<child_iterator>(Blocks.begin()); |
| } |
| |
| child_iterator child_end() const { |
| return reinterpret_cast<child_iterator>(Blocks.end()); |
| } |
| |
| const Decl *getDecl() const LLVM_READONLY { |
| return ThisDeclInfo->CommentDecl; |
| } |
| |
| const DeclInfo *getDeclInfo() const LLVM_READONLY { |
| if (!ThisDeclInfo->IsFilled) |
| ThisDeclInfo->fill(); |
| return ThisDeclInfo; |
| } |
| |
| ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; } |
| |
| }; |
| } // end namespace comments |
| } // end namespace clang |
| |
| #endif |
| |