Comment.h revision beef1cb6ebfaea4542fb6d6686caae27787a75e0
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 HTMLStartTagCommentBitfields { 54 friend class HTMLStartTagComment; 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 HTMLStartTagCommentBitfields HTMLStartTagCommentBits; 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 getNumArgs() 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 HTMLStartTagComment : 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 HTMLStartTagComment(SourceLocation LocBegin, 338 StringRef TagName) : 339 HTMLTagComment(HTMLStartTagCommentKind, 340 LocBegin, LocBegin.getLocWithOffset(1 + TagName.size()), 341 TagName, 342 LocBegin.getLocWithOffset(1), 343 LocBegin.getLocWithOffset(1 + TagName.size())) { 344 HTMLStartTagCommentBits.IsSelfClosing = false; 345 } 346 347 static bool classof(const Comment *C) { 348 return C->getCommentKind() == HTMLStartTagCommentKind; 349 } 350 351 static bool classof(const HTMLStartTagComment *) { return true; } 352 353 child_iterator child_begin() const { return NULL; } 354 355 child_iterator child_end() const { return NULL; } 356 357 unsigned getNumAttrs() 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 HTMLStartTagCommentBits.IsSelfClosing; 384 } 385 386 void setSelfClosing() { 387 HTMLStartTagCommentBits.IsSelfClosing = true; 388 } 389}; 390 391/// A closing HTML tag. 392class HTMLEndTagComment : public HTMLTagComment { 393public: 394 HTMLEndTagComment(SourceLocation LocBegin, 395 SourceLocation LocEnd, 396 StringRef TagName) : 397 HTMLTagComment(HTMLEndTagCommentKind, 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() == HTMLEndTagCommentKind; 406 } 407 408 static bool classof(const HTMLEndTagComment *) { 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() >= FirstBlockCommandCommentConstant && 514 C->getCommentKind() <= LastBlockCommandCommentConstant; 515 } 516 517 static bool classof(const BlockCommandComment *) { return true; } 518 519 child_iterator child_begin() const { 520 return reinterpret_cast<child_iterator>(&Paragraph); 521 } 522 523 child_iterator child_end() const { 524 return reinterpret_cast<child_iterator>(&Paragraph + 1); 525 } 526 527 StringRef getCommandName() const { 528 return Name; 529 } 530 531 SourceRange getCommandNameRange() const { 532 return SourceRange(getLocStart().getLocWithOffset(1), 533 getLocStart().getLocWithOffset(1 + Name.size())); 534 } 535 536 unsigned getNumArgs() const { 537 return Args.size(); 538 } 539 540 StringRef getArgText(unsigned Idx) const { 541 return Args[Idx].Text; 542 } 543 544 SourceRange getArgRange(unsigned Idx) const { 545 return Args[Idx].Range; 546 } 547 548 void setArgs(llvm::ArrayRef<Argument> A) { 549 Args = A; 550 if (Args.size() > 0) { 551 SourceLocation NewLocEnd = Args.back().Range.getEnd(); 552 if (NewLocEnd.isValid()) 553 setSourceRange(SourceRange(getLocStart(), NewLocEnd)); 554 } 555 } 556 557 ParagraphComment *getParagraph() const LLVM_READONLY { 558 return Paragraph; 559 } 560 561 void setParagraph(ParagraphComment *PC) { 562 Paragraph = PC; 563 SourceLocation NewLocEnd = PC->getLocEnd(); 564 if (NewLocEnd.isValid()) 565 setSourceRange(SourceRange(getLocStart(), NewLocEnd)); 566 } 567}; 568 569/// Doxygen \\param command. 570class ParamCommandComment : public BlockCommandComment { 571private: 572 /// Parameter index in the function declaration. 573 unsigned ParamIndex; 574 575public: 576 enum { InvalidParamIndex = ~0U }; 577 578 ParamCommandComment(SourceLocation LocBegin, 579 SourceLocation LocEnd, 580 StringRef Name) : 581 BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, Name), 582 ParamIndex(InvalidParamIndex) { 583 ParamCommandCommentBits.Direction = In; 584 ParamCommandCommentBits.IsDirectionExplicit = false; 585 } 586 587 static bool classof(const Comment *C) { 588 return C->getCommentKind() == ParamCommandCommentKind; 589 } 590 591 static bool classof(const ParamCommandComment *) { return true; } 592 593 enum PassDirection { 594 In, 595 Out, 596 InOut 597 }; 598 599 static const char *getDirectionAsString(PassDirection D); 600 601 PassDirection getDirection() const LLVM_READONLY { 602 return static_cast<PassDirection>(ParamCommandCommentBits.Direction); 603 } 604 605 bool isDirectionExplicit() const LLVM_READONLY { 606 return ParamCommandCommentBits.IsDirectionExplicit; 607 } 608 609 void setDirection(PassDirection Direction, bool Explicit) { 610 ParamCommandCommentBits.Direction = Direction; 611 ParamCommandCommentBits.IsDirectionExplicit = Explicit; 612 } 613 614 bool hasParamName() const { 615 return getNumArgs() > 0; 616 } 617 618 StringRef getParamName() const { 619 return Args[0].Text; 620 } 621 622 SourceRange getParamNameRange() const { 623 return Args[0].Range; 624 } 625 626 bool isParamIndexValid() const LLVM_READONLY { 627 return ParamIndex != InvalidParamIndex; 628 } 629 630 unsigned getParamIndex() const LLVM_READONLY { 631 return ParamIndex; 632 } 633 634 void setParamIndex(unsigned Index) { 635 ParamIndex = Index; 636 assert(isParamIndexValid()); 637 } 638}; 639 640/// A line of text contained in a verbatim block. 641class VerbatimBlockLineComment : public Comment { 642 StringRef Text; 643 644public: 645 VerbatimBlockLineComment(SourceLocation LocBegin, 646 StringRef Text) : 647 Comment(VerbatimBlockLineCommentKind, 648 LocBegin, 649 LocBegin.getLocWithOffset(Text.size())), 650 Text(Text) 651 { } 652 653 static bool classof(const Comment *C) { 654 return C->getCommentKind() == VerbatimBlockLineCommentKind; 655 } 656 657 static bool classof(const VerbatimBlockLineComment *) { return true; } 658 659 child_iterator child_begin() const { return NULL; } 660 661 child_iterator child_end() const { return NULL; } 662 663 StringRef getText() const LLVM_READONLY { 664 return Text; 665 } 666}; 667 668/// A verbatim block command (e. g., preformatted code). Verbatim block has an 669/// opening and a closing command and contains multiple lines of text 670/// (VerbatimBlockLineComment nodes). 671class VerbatimBlockComment : public BlockCommandComment { 672protected: 673 StringRef CloseName; 674 SourceLocation CloseNameLocBegin; 675 llvm::ArrayRef<VerbatimBlockLineComment *> Lines; 676 677public: 678 VerbatimBlockComment(SourceLocation LocBegin, 679 SourceLocation LocEnd, 680 StringRef Name) : 681 BlockCommandComment(VerbatimBlockCommentKind, 682 LocBegin, LocEnd, Name) 683 { } 684 685 static bool classof(const Comment *C) { 686 return C->getCommentKind() == VerbatimBlockCommentKind; 687 } 688 689 static bool classof(const VerbatimBlockComment *) { return true; } 690 691 child_iterator child_begin() const { 692 return reinterpret_cast<child_iterator>(Lines.begin()); 693 } 694 695 child_iterator child_end() const { 696 return reinterpret_cast<child_iterator>(Lines.end()); 697 } 698 699 void setCloseName(StringRef Name, SourceLocation LocBegin) { 700 CloseName = Name; 701 CloseNameLocBegin = LocBegin; 702 } 703 704 void setLines(llvm::ArrayRef<VerbatimBlockLineComment *> L) { 705 Lines = L; 706 } 707 708 StringRef getCloseName() const { 709 return CloseName; 710 } 711 712 unsigned getNumLines() const { 713 return Lines.size(); 714 } 715 716 StringRef getText(unsigned LineIdx) const { 717 return Lines[LineIdx]->getText(); 718 } 719}; 720 721/// A verbatim line command. Verbatim line has an opening command, a single 722/// line of text (up to the newline after the opening command) and has no 723/// closing command. 724class VerbatimLineComment : public BlockCommandComment { 725protected: 726 StringRef Text; 727 SourceLocation TextBegin; 728 729public: 730 VerbatimLineComment(SourceLocation LocBegin, 731 SourceLocation LocEnd, 732 StringRef Name, 733 SourceLocation TextBegin, 734 StringRef Text) : 735 BlockCommandComment(VerbatimLineCommentKind, 736 LocBegin, LocEnd, 737 Name), 738 Text(Text), 739 TextBegin(TextBegin) 740 { } 741 742 static bool classof(const Comment *C) { 743 return C->getCommentKind() == VerbatimLineCommentKind; 744 } 745 746 static bool classof(const VerbatimLineComment *) { return true; } 747 748 child_iterator child_begin() const { return NULL; } 749 750 child_iterator child_end() const { return NULL; } 751 752 StringRef getText() const { 753 return Text; 754 } 755 756 SourceRange getTextRange() const { 757 return SourceRange(TextBegin, getLocEnd()); 758 } 759}; 760 761/// A full comment attached to a declaration, contains block content. 762class FullComment : public Comment { 763 llvm::ArrayRef<BlockContentComment *> Blocks; 764 765public: 766 FullComment(llvm::ArrayRef<BlockContentComment *> Blocks) : 767 Comment(FullCommentKind, SourceLocation(), SourceLocation()), 768 Blocks(Blocks) { 769 if (Blocks.empty()) 770 return; 771 772 setSourceRange(SourceRange(Blocks.front()->getLocStart(), 773 Blocks.back()->getLocEnd())); 774 setLocation(Blocks.front()->getLocStart()); 775 } 776 777 static bool classof(const Comment *C) { 778 return C->getCommentKind() == FullCommentKind; 779 } 780 781 static bool classof(const FullComment *) { return true; } 782 783 child_iterator child_begin() const { 784 return reinterpret_cast<child_iterator>(Blocks.begin()); 785 } 786 787 child_iterator child_end() const { 788 return reinterpret_cast<child_iterator>(Blocks.end()); 789 } 790}; 791 792} // end namespace comments 793} // end namespace clang 794 795#endif 796 797