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