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