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