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