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