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