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