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