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