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