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