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

source code of clang/include/clang/AST/Comment.h