xref: /freebsd-src/contrib/llvm-project/clang/include/clang/AST/Comment.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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 enum class InlineCommandRenderKind;
31 enum 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.
38 enum 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 
52 enum 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.
65 class Comment {
66 protected:
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 
220 public:
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.
265 class InlineContentComment : public Comment {
266 protected:
267   InlineContentComment(CommentKind K,
268                        SourceLocation LocBegin,
269                        SourceLocation LocEnd) :
270       Comment(K, LocBegin, LocEnd) {
271     InlineContentCommentBits.HasTrailingNewline = 0;
272   }
273 
274 public:
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.
291 class TextComment : public InlineContentComment {
292   StringRef Text;
293 
294 public:
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 
320 private:
321   bool isWhitespaceNoCache() const;
322 };
323 
324 /// The most appropriate rendering mode for this command, chosen on command
325 /// semantics in Doxygen.
326 enum 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.
335 class InlineCommandComment : public InlineContentComment {
336 protected:
337   /// Command arguments.
338   ArrayRef<Argument> Args;
339 
340 public:
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(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).
391 class HTMLTagComment : public InlineContentComment {
392 protected:
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 
409 public:
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(1),
420                        L.getLocWithOffset(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.
433 class HTMLStartTagComment : public HTMLTagComment {
434 public:
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(Name.size());
457     }
458 
459     SourceRange getNameRange() const {
460       return SourceRange(NameLocBegin, getNameLocEnd());
461     }
462   };
463 
464 private:
465   ArrayRef<Attribute> Attributes;
466 
467 public:
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.
519 class HTMLEndTagComment : public HTMLTagComment {
520 public:
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.
538 class BlockContentComment : public Comment {
539 protected:
540   BlockContentComment(CommentKind K,
541                       SourceLocation LocBegin,
542                       SourceLocation LocEnd) :
543       Comment(K, LocBegin, LocEnd)
544   { }
545 
546 public:
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.
555 class ParagraphComment : public BlockContentComment {
556   ArrayRef<InlineContentComment *> Content;
557 
558 public:
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 
597 private:
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).
604 class BlockCommandComment : public BlockContentComment {
605 protected:
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 
624 public:
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(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 
708 enum class ParamCommandPassDirection { In, Out, InOut };
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 
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.
793 class TParamCommandComment : public BlockCommandComment {
794 private:
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 
809 public:
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.
854 class VerbatimBlockLineComment : public Comment {
855   StringRef Text;
856 
857 public:
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).
879 class VerbatimBlockComment : public BlockCommandComment {
880 protected:
881   StringRef CloseName;
882   SourceLocation CloseNameLocBegin;
883   ArrayRef<VerbatimBlockLineComment *> Lines;
884 
885 public:
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.
930 class VerbatimLineComment : public BlockCommandComment {
931 protected:
932   StringRef Text;
933   SourceLocation TextBegin;
934 
935 public:
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.
962 struct 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.
1083 class FullComment : public Comment {
1084   ArrayRef<BlockContentComment *> Blocks;
1085   DeclInfo *ThisDeclInfo;
1086 
1087 public:
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