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