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