Comment.h revision a5ef44ff5d93a3be6ca67782828157a71894cf0c
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/Basic/SourceLocation.h" 18#include "llvm/ADT/ArrayRef.h" 19#include "llvm/ADT/StringRef.h" 20 21namespace clang { 22namespace comments { 23 24/// Any part of the comment. 25/// Abstract class. 26class Comment { 27protected: 28 /// Preferred location to show caret. 29 SourceLocation Loc; 30 31 /// Source range of this AST node. 32 SourceRange Range; 33 34 class CommentBitfields { 35 friend class Comment; 36 37 /// Type of this AST node. 38 unsigned Kind : 8; 39 }; 40 enum { NumCommentBits = 8 }; 41 42 class InlineContentCommentBitfields { 43 friend class InlineContentComment; 44 45 unsigned : NumCommentBits; 46 47 /// True if there is a newline after this inline content node. 48 /// (There is no separate AST node for a newline.) 49 unsigned HasTrailingNewline : 1; 50 }; 51 enum { NumInlineContentCommentBitfields = 9 }; 52 53 class HTMLOpenTagCommentBitfields { 54 friend class HTMLOpenTagComment; 55 56 unsigned : NumInlineContentCommentBitfields; 57 58 /// True if this tag is self-closing (e. g., <br />). This is based on tag 59 /// spelling in comment (plain <br> would not set this flag). 60 unsigned IsSelfClosing : 1; 61 }; 62 63 class ParamCommandCommentBitfields { 64 friend class ParamCommandComment; 65 66 unsigned : NumCommentBits; 67 68 /// Parameter passing direction, see ParamCommandComment::PassDirection. 69 unsigned Direction : 2; 70 71 /// True if direction was specified explicitly in the comment. 72 unsigned IsDirectionExplicit : 1; 73 }; 74 enum { NumParamCommandCommentBitfields = 11 }; 75 76 union { 77 CommentBitfields CommentBits; 78 InlineContentCommentBitfields InlineContentCommentBits; 79 HTMLOpenTagCommentBitfields HTMLOpenTagCommentBits; 80 ParamCommandCommentBitfields ParamCommandCommentBits; 81 }; 82 83 void setSourceRange(SourceRange SR) { 84 Range = SR; 85 } 86 87 void setLocation(SourceLocation L) { 88 Loc = L; 89 } 90 91public: 92 enum CommentKind { 93 NoCommentKind = 0, 94#define COMMENT(CLASS, PARENT) CLASS##Kind, 95#define COMMENT_RANGE(BASE, FIRST, LAST) \ 96 First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind, 97#define LAST_COMMENT_RANGE(BASE, FIRST, LAST) \ 98 First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind 99#define ABSTRACT_COMMENT(COMMENT) 100#include "clang/AST/CommentNodes.inc" 101 }; 102 103 Comment(CommentKind K, 104 SourceLocation LocBegin, 105 SourceLocation LocEnd) : 106 Loc(LocBegin), Range(SourceRange(LocBegin, LocEnd)) { 107 CommentBits.Kind = K; 108 } 109 110 CommentKind getCommentKind() const { 111 return static_cast<CommentKind>(CommentBits.Kind); 112 } 113 114 const char *getCommentKindName() const; 115 116 LLVM_ATTRIBUTE_USED void dump() const; 117 LLVM_ATTRIBUTE_USED void dump(SourceManager &SM) const; 118 119 static bool classof(const Comment *) { return true; } 120 121 SourceRange getSourceRange() const LLVM_READONLY { return Range; } 122 123 SourceLocation getLocStart() const LLVM_READONLY { 124 return Range.getBegin(); 125 } 126 127 SourceLocation getLocEnd() const LLVM_READONLY { 128 return Range.getEnd(); 129 } 130 131 SourceLocation getLocation() const LLVM_READONLY { return Loc; } 132 133 typedef Comment * const *child_iterator; 134 135 child_iterator child_begin() const; 136 child_iterator child_end() const; 137 138 // TODO: const child iterator 139 140 unsigned child_count() const { 141 return child_end() - child_begin(); 142 } 143}; 144 145/// Inline content (contained within a block). 146/// Abstract class. 147class InlineContentComment : public Comment { 148protected: 149 InlineContentComment(CommentKind K, 150 SourceLocation LocBegin, 151 SourceLocation LocEnd) : 152 Comment(K, LocBegin, LocEnd) { 153 InlineContentCommentBits.HasTrailingNewline = 0; 154 } 155 156public: 157 static bool classof(const Comment *C) { 158 return C->getCommentKind() >= FirstInlineContentCommentConstant && 159 C->getCommentKind() <= LastInlineContentCommentConstant; 160 } 161 162 static bool classof(const InlineContentComment *) { return true; } 163 164 void addTrailingNewline() { 165 InlineContentCommentBits.HasTrailingNewline = 1; 166 } 167 168 bool hasTrailingNewline() const { 169 return InlineContentCommentBits.HasTrailingNewline; 170 } 171}; 172 173/// Plain text. 174class TextComment : public InlineContentComment { 175 StringRef Text; 176 177public: 178 TextComment(SourceLocation LocBegin, 179 SourceLocation LocEnd, 180 StringRef Text) : 181 InlineContentComment(TextCommentKind, LocBegin, LocEnd), 182 Text(Text) 183 { } 184 185 static bool classof(const Comment *C) { 186 return C->getCommentKind() == TextCommentKind; 187 } 188 189 static bool classof(const TextComment *) { return true; } 190 191 child_iterator child_begin() const { return NULL; } 192 193 child_iterator child_end() const { return NULL; } 194 195 StringRef getText() const LLVM_READONLY { return Text; } 196 197 bool isWhitespace() const; 198}; 199 200/// A command with word-like arguments that is considered inline content. 201class InlineCommandComment : public InlineContentComment { 202public: 203 struct Argument { 204 SourceRange Range; 205 StringRef Text; 206 207 Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { } 208 }; 209 210protected: 211 /// Command name. 212 StringRef Name; 213 214 /// Command arguments. 215 llvm::ArrayRef<Argument> Args; 216 217public: 218 InlineCommandComment(SourceLocation LocBegin, 219 SourceLocation LocEnd, 220 StringRef Name, 221 llvm::ArrayRef<Argument> Args) : 222 InlineContentComment(InlineCommandCommentKind, LocBegin, LocEnd), 223 Name(Name), Args(Args) 224 { } 225 226 static bool classof(const Comment *C) { 227 return C->getCommentKind() == InlineCommandCommentKind; 228 } 229 230 static bool classof(const InlineCommandComment *) { return true; } 231 232 child_iterator child_begin() const { return NULL; } 233 234 child_iterator child_end() const { return NULL; } 235 236 StringRef getCommandName() const { 237 return Name; 238 } 239 240 SourceRange getCommandNameRange() const { 241 return SourceRange(getLocStart().getLocWithOffset(-1), 242 getLocEnd()); 243 } 244 245 unsigned getArgCount() const { 246 return Args.size(); 247 } 248 249 StringRef getArgText(unsigned Idx) const { 250 return Args[Idx].Text; 251 } 252 253 SourceRange getArgRange(unsigned Idx) const { 254 return Args[Idx].Range; 255 } 256}; 257 258/// Abstract class for opening and closing HTML tags. HTML tags are always 259/// treated as inline content (regardless HTML semantics); opening and closing 260/// tags are not matched. 261class HTMLTagComment : public InlineContentComment { 262protected: 263 StringRef TagName; 264 SourceRange TagNameRange; 265 266 HTMLTagComment(CommentKind K, 267 SourceLocation LocBegin, 268 SourceLocation LocEnd, 269 StringRef TagName, 270 SourceLocation TagNameBegin, 271 SourceLocation TagNameEnd) : 272 InlineContentComment(K, LocBegin, LocEnd), 273 TagName(TagName), 274 TagNameRange(TagNameBegin, TagNameEnd) { 275 setLocation(TagNameBegin); 276 } 277 278public: 279 static bool classof(const Comment *C) { 280 return C->getCommentKind() >= FirstHTMLTagCommentConstant && 281 C->getCommentKind() <= LastHTMLTagCommentConstant; 282 } 283 284 static bool classof(const HTMLTagComment *) { return true; } 285 286 StringRef getTagName() const LLVM_READONLY { return TagName; } 287 288 SourceRange getTagNameSourceRange() const LLVM_READONLY { 289 SourceLocation L = getLocation(); 290 return SourceRange(L.getLocWithOffset(1), 291 L.getLocWithOffset(1 + TagName.size())); 292 } 293}; 294 295/// An opening HTML tag with attributes. 296class HTMLOpenTagComment : public HTMLTagComment { 297public: 298 class Attribute { 299 public: 300 SourceLocation NameLocBegin; 301 StringRef Name; 302 303 SourceLocation EqualsLoc; 304 305 SourceRange ValueRange; 306 StringRef Value; 307 308 Attribute() { } 309 310 Attribute(SourceLocation NameLocBegin, StringRef Name) : 311 NameLocBegin(NameLocBegin), Name(Name), 312 EqualsLoc(SourceLocation()), 313 ValueRange(SourceRange()), Value(StringRef()) 314 { } 315 316 Attribute(SourceLocation NameLocBegin, StringRef Name, 317 SourceLocation EqualsLoc, 318 SourceRange ValueRange, StringRef Value) : 319 NameLocBegin(NameLocBegin), Name(Name), 320 EqualsLoc(EqualsLoc), 321 ValueRange(ValueRange), Value(Value) 322 { } 323 324 SourceLocation getNameLocEnd() const { 325 return NameLocBegin.getLocWithOffset(Name.size()); 326 } 327 328 SourceRange getNameRange() const { 329 return SourceRange(NameLocBegin, getNameLocEnd()); 330 } 331 }; 332 333private: 334 ArrayRef<Attribute> Attributes; 335 336public: 337 HTMLOpenTagComment(SourceLocation LocBegin, 338 StringRef TagName) : 339 HTMLTagComment(HTMLOpenTagCommentKind, 340 LocBegin, LocBegin.getLocWithOffset(1 + TagName.size()), 341 TagName, 342 LocBegin.getLocWithOffset(1), 343 LocBegin.getLocWithOffset(1 + TagName.size())) { 344 HTMLOpenTagCommentBits.IsSelfClosing = false; 345 } 346 347 static bool classof(const Comment *C) { 348 return C->getCommentKind() == HTMLOpenTagCommentKind; 349 } 350 351 static bool classof(const HTMLOpenTagComment *) { return true; } 352 353 child_iterator child_begin() const { return NULL; } 354 355 child_iterator child_end() const { return NULL; } 356 357 unsigned getAttrCount() const { 358 return Attributes.size(); 359 } 360 361 const Attribute &getAttr(unsigned Idx) const { 362 return Attributes[Idx]; 363 } 364 365 void setAttrs(ArrayRef<Attribute> Attrs) { 366 Attributes = Attrs; 367 if (!Attrs.empty()) { 368 const Attribute &Attr = Attrs.back(); 369 SourceLocation L = Attr.ValueRange.getEnd(); 370 if (L.isValid()) 371 Range.setEnd(L); 372 else { 373 Range.setEnd(Attr.getNameLocEnd()); 374 } 375 } 376 } 377 378 void setGreaterLoc(SourceLocation GreaterLoc) { 379 Range.setEnd(GreaterLoc); 380 } 381 382 bool isSelfClosing() const { 383 return HTMLOpenTagCommentBits.IsSelfClosing; 384 } 385 386 void setSelfClosing() { 387 HTMLOpenTagCommentBits.IsSelfClosing = true; 388 } 389}; 390 391/// A closing HTML tag. 392class HTMLCloseTagComment : public HTMLTagComment { 393public: 394 HTMLCloseTagComment(SourceLocation LocBegin, 395 SourceLocation LocEnd, 396 StringRef TagName) : 397 HTMLTagComment(HTMLCloseTagCommentKind, 398 LocBegin, LocEnd, 399 TagName, 400 LocBegin.getLocWithOffset(2), 401 LocBegin.getLocWithOffset(2 + TagName.size())) 402 { } 403 404 static bool classof(const Comment *C) { 405 return C->getCommentKind() == HTMLCloseTagCommentKind; 406 } 407 408 static bool classof(const HTMLCloseTagComment *) { return true; } 409 410 child_iterator child_begin() const { return NULL; } 411 412 child_iterator child_end() const { return NULL; } 413}; 414 415/// Block content (contains inline content). 416/// Abstract class. 417class BlockContentComment : public Comment { 418protected: 419 BlockContentComment(CommentKind K, 420 SourceLocation LocBegin, 421 SourceLocation LocEnd) : 422 Comment(K, LocBegin, LocEnd) 423 { } 424 425public: 426 static bool classof(const Comment *C) { 427 return C->getCommentKind() >= FirstBlockContentCommentConstant && 428 C->getCommentKind() <= LastBlockContentCommentConstant; 429 } 430 431 static bool classof(const BlockContentComment *) { return true; } 432}; 433 434/// A single paragraph that contains inline content. 435class ParagraphComment : public BlockContentComment { 436 llvm::ArrayRef<InlineContentComment *> Content; 437 438public: 439 ParagraphComment(llvm::ArrayRef<InlineContentComment *> Content) : 440 BlockContentComment(ParagraphCommentKind, 441 SourceLocation(), 442 SourceLocation()), 443 Content(Content) { 444 if (Content.empty()) 445 return; 446 447 setSourceRange(SourceRange(Content.front()->getLocStart(), 448 Content.back()->getLocEnd())); 449 setLocation(Content.front()->getLocStart()); 450 } 451 452 static bool classof(const Comment *C) { 453 return C->getCommentKind() == ParagraphCommentKind; 454 } 455 456 static bool classof(const ParagraphComment *) { return true; } 457 458 child_iterator child_begin() const { 459 return reinterpret_cast<child_iterator>(Content.begin()); 460 } 461 462 child_iterator child_end() const { 463 return reinterpret_cast<child_iterator>(Content.end()); 464 } 465 466 bool isWhitespace() const; 467}; 468 469/// A command that has zero or more word-like arguments (number of word-like 470/// arguments depends on command name) and a paragraph as an argument 471/// (e. g., \\brief). 472class BlockCommandComment : public BlockContentComment { 473public: 474 struct Argument { 475 SourceRange Range; 476 StringRef Text; 477 478 Argument() { } 479 Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { } 480 }; 481 482protected: 483 /// Command name. 484 StringRef Name; 485 486 /// Word-like arguments. 487 llvm::ArrayRef<Argument> Args; 488 489 /// Paragraph argument. 490 ParagraphComment *Paragraph; 491 492 BlockCommandComment(CommentKind K, 493 SourceLocation LocBegin, 494 SourceLocation LocEnd, 495 StringRef Name) : 496 BlockContentComment(K, LocBegin, LocEnd), 497 Name(Name), 498 Paragraph(NULL) { 499 setLocation(getCommandNameRange().getBegin()); 500 } 501 502public: 503 BlockCommandComment(SourceLocation LocBegin, 504 SourceLocation LocEnd, 505 StringRef Name) : 506 BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd), 507 Name(Name), 508 Paragraph(NULL) { 509 setLocation(getCommandNameRange().getBegin()); 510 } 511 512 static bool classof(const Comment *C) { 513 return C->getCommentKind() == BlockCommandCommentKind; 514 } 515 516 static bool classof(const BlockCommandComment *) { return true; } 517 518 child_iterator child_begin() const { 519 return reinterpret_cast<child_iterator>(&Paragraph); 520 } 521 522 child_iterator child_end() const { 523 return reinterpret_cast<child_iterator>(&Paragraph + 1); 524 } 525 526 StringRef getCommandName() const { 527 return Name; 528 } 529 530 SourceRange getCommandNameRange() const { 531 return SourceRange(getLocStart().getLocWithOffset(1), 532 getLocStart().getLocWithOffset(1 + Name.size())); 533 } 534 535 unsigned getArgCount() const { 536 return Args.size(); 537 } 538 539 StringRef getArgText(unsigned Idx) const { 540 return Args[Idx].Text; 541 } 542 543 SourceRange getArgRange(unsigned Idx) const { 544 return Args[Idx].Range; 545 } 546 547 void setArgs(llvm::ArrayRef<Argument> A) { 548 Args = A; 549 if (Args.size() > 0) { 550 SourceLocation NewLocEnd = Args.back().Range.getEnd(); 551 if (NewLocEnd.isValid()) 552 setSourceRange(SourceRange(getLocStart(), NewLocEnd)); 553 } 554 } 555 556 ParagraphComment *getParagraph() const LLVM_READONLY { 557 return Paragraph; 558 } 559 560 void setParagraph(ParagraphComment *PC) { 561 Paragraph = PC; 562 SourceLocation NewLocEnd = PC->getLocEnd(); 563 if (NewLocEnd.isValid()) 564 setSourceRange(SourceRange(getLocStart(), NewLocEnd)); 565 } 566}; 567 568/// Doxygen \\param command. 569class ParamCommandComment : public BlockCommandComment { 570private: 571 /// Parameter index in the function declaration. 572 unsigned ParamIndex; 573 574public: 575 enum { InvalidParamIndex = ~0U }; 576 577 ParamCommandComment(SourceLocation LocBegin, 578 SourceLocation LocEnd, 579 StringRef Name) : 580 BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, Name), 581 ParamIndex(InvalidParamIndex) { 582 ParamCommandCommentBits.Direction = In; 583 ParamCommandCommentBits.IsDirectionExplicit = false; 584 } 585 586 static bool classof(const Comment *C) { 587 return C->getCommentKind() == ParamCommandCommentKind; 588 } 589 590 static bool classof(const ParamCommandComment *) { return true; } 591 592 enum PassDirection { 593 In, 594 Out, 595 InOut 596 }; 597 598 static const char *getDirectionAsString(PassDirection D); 599 600 PassDirection getDirection() const LLVM_READONLY { 601 return static_cast<PassDirection>(ParamCommandCommentBits.Direction); 602 } 603 604 bool isDirectionExplicit() const LLVM_READONLY { 605 return ParamCommandCommentBits.IsDirectionExplicit; 606 } 607 608 void setDirection(PassDirection Direction, bool Explicit) { 609 ParamCommandCommentBits.Direction = Direction; 610 ParamCommandCommentBits.IsDirectionExplicit = Explicit; 611 } 612 613 bool hasParamName() const { 614 return getArgCount() > 0; 615 } 616 617 StringRef getParamName() const { 618 return Args[0].Text; 619 } 620 621 SourceRange getParamNameRange() const { 622 return Args[0].Range; 623 } 624 625 bool isParamIndexValid() const LLVM_READONLY { 626 return ParamIndex != InvalidParamIndex; 627 } 628 629 unsigned getParamIndex() const LLVM_READONLY { 630 return ParamIndex; 631 } 632 633 void setParamIndex(unsigned Index) { 634 ParamIndex = Index; 635 assert(isParamIndexValid()); 636 } 637}; 638 639/// A line of text contained in a verbatim block. 640class VerbatimBlockLineComment : public Comment { 641 StringRef Text; 642 643public: 644 VerbatimBlockLineComment(SourceLocation LocBegin, 645 StringRef Text) : 646 Comment(VerbatimBlockLineCommentKind, 647 LocBegin, 648 LocBegin.getLocWithOffset(Text.size())), 649 Text(Text) 650 { } 651 652 static bool classof(const Comment *C) { 653 return C->getCommentKind() == VerbatimBlockLineCommentKind; 654 } 655 656 static bool classof(const VerbatimBlockLineComment *) { return true; } 657 658 child_iterator child_begin() const { return NULL; } 659 660 child_iterator child_end() const { return NULL; } 661 662 StringRef getText() const LLVM_READONLY { 663 return Text; 664 } 665}; 666 667/// Verbatim block (e. g., preformatted code). Verbatim block has an opening 668/// and a closing command and contains multiple lines of text 669/// (VerbatimBlockLineComment nodes). 670class VerbatimBlockComment : public BlockCommandComment { 671protected: 672 StringRef CloseName; 673 SourceLocation CloseNameLocBegin; 674 llvm::ArrayRef<VerbatimBlockLineComment *> Lines; 675 676public: 677 VerbatimBlockComment(SourceLocation LocBegin, 678 SourceLocation LocEnd, 679 StringRef Name) : 680 BlockCommandComment(VerbatimBlockCommentKind, 681 LocBegin, LocEnd, Name) 682 { } 683 684 static bool classof(const Comment *C) { 685 return C->getCommentKind() == VerbatimBlockCommentKind; 686 } 687 688 static bool classof(const VerbatimBlockComment *) { return true; } 689 690 child_iterator child_begin() const { 691 return reinterpret_cast<child_iterator>(Lines.begin()); 692 } 693 694 child_iterator child_end() const { 695 return reinterpret_cast<child_iterator>(Lines.end()); 696 } 697 698 void setCloseName(StringRef Name, SourceLocation LocBegin) { 699 CloseName = Name; 700 CloseNameLocBegin = LocBegin; 701 } 702 703 void setLines(llvm::ArrayRef<VerbatimBlockLineComment *> L) { 704 Lines = L; 705 } 706 707 StringRef getCloseName() const { 708 return CloseName; 709 } 710 711 unsigned getLineCount() const { 712 return Lines.size(); 713 } 714 715 StringRef getText(unsigned LineIdx) const { 716 return Lines[LineIdx]->getText(); 717 } 718}; 719 720/// Verbatim line. Verbatim line has an opening command and a single line of 721/// text (up to the newline after the opening command). 722class VerbatimLineComment : public BlockCommandComment { 723protected: 724 StringRef Text; 725 SourceLocation TextBegin; 726 727public: 728 VerbatimLineComment(SourceLocation LocBegin, 729 SourceLocation LocEnd, 730 StringRef Name, 731 SourceLocation TextBegin, 732 StringRef Text) : 733 BlockCommandComment(VerbatimLineCommentKind, 734 LocBegin, LocEnd, 735 Name), 736 Text(Text), 737 TextBegin(TextBegin) 738 { } 739 740 static bool classof(const Comment *C) { 741 return C->getCommentKind() == VerbatimLineCommentKind; 742 } 743 744 static bool classof(const VerbatimLineComment *) { return true; } 745 746 child_iterator child_begin() const { return NULL; } 747 748 child_iterator child_end() const { return NULL; } 749 750 StringRef getText() const { 751 return Text; 752 } 753 754 SourceRange getTextRange() const { 755 return SourceRange(TextBegin, getLocEnd()); 756 } 757}; 758 759/// A full comment attached to a declaration, contains block content. 760class FullComment : public Comment { 761 llvm::ArrayRef<BlockContentComment *> Blocks; 762 763public: 764 FullComment(llvm::ArrayRef<BlockContentComment *> Blocks) : 765 Comment(FullCommentKind, SourceLocation(), SourceLocation()), 766 Blocks(Blocks) { 767 if (Blocks.empty()) 768 return; 769 770 setSourceRange(SourceRange(Blocks.front()->getLocStart(), 771 Blocks.back()->getLocEnd())); 772 setLocation(Blocks.front()->getLocStart()); 773 } 774 775 static bool classof(const Comment *C) { 776 return C->getCommentKind() == FullCommentKind; 777 } 778 779 static bool classof(const FullComment *) { return true; } 780 781 child_iterator child_begin() const { 782 return reinterpret_cast<child_iterator>(Blocks.begin()); 783 } 784 785 child_iterator child_end() const { 786 return reinterpret_cast<child_iterator>(Blocks.end()); 787 } 788}; 789 790} // end namespace comments 791} // end namespace clang 792 793#endif 794 795