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