Comment.h revision c5b0054693b3b3cafe6a13549358c22e07fcd4ff
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
24namespace clang {
25class Decl;
26class ParmVarDecl;
27class TemplateParameterList;
28
29namespace comments {
30class 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.
37enum 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.
53class Comment {
54protected:
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
172public:
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.
229class InlineContentComment : public Comment {
230protected:
231  InlineContentComment(CommentKind K,
232                       SourceLocation LocBegin,
233                       SourceLocation LocEnd) :
234      Comment(K, LocBegin, LocEnd) {
235    InlineContentCommentBits.HasTrailingNewline = 0;
236  }
237
238public:
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.
254class TextComment : public InlineContentComment {
255  StringRef Text;
256
257public:
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
285private:
286  bool isWhitespaceNoCache() const;
287};
288
289/// A command with word-like arguments that is considered inline content.
290class InlineCommandComment : public InlineContentComment {
291public:
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
308protected:
309  /// Command arguments.
310  ArrayRef<Argument> Args;
311
312public:
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.
365class HTMLTagComment : public InlineContentComment {
366protected:
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
382public:
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.
398class HTMLStartTagComment : public HTMLTagComment {
399public:
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
435private:
436  ArrayRef<Attribute> Attributes;
437
438public:
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.
492class HTMLEndTagComment : public HTMLTagComment {
493public:
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.
515class BlockContentComment : public Comment {
516protected:
517  BlockContentComment(CommentKind K,
518                      SourceLocation LocBegin,
519                      SourceLocation LocEnd) :
520      Comment(K, LocBegin, LocEnd)
521  { }
522
523public:
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.
531class ParagraphComment : public BlockContentComment {
532  ArrayRef<InlineContentComment *> Content;
533
534public:
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
574private:
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).
581class BlockCommandComment : public BlockContentComment {
582public:
583  struct Argument {
584    SourceRange Range;
585    StringRef Text;
586
587    Argument() { }
588    Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { }
589  };
590
591protected:
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
610public:
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.
696class ParamCommandComment : public BlockCommandComment {
697private:
698  /// Parameter index in the function declaration.
699  unsigned ParamIndex;
700
701public:
702  enum {
703    InvalidParamIndex = ~0U,
704    VarArgParamIndex = InvalidParamIndex - 1U
705  };
706
707  ParamCommandComment(SourceLocation LocBegin,
708                      SourceLocation LocEnd,
709                      unsigned CommandID,
710                      CommandMarkerKind CommandMarker) :
711      BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd,
712                          CommandID, CommandMarker),
713      ParamIndex(InvalidParamIndex) {
714    ParamCommandCommentBits.Direction = In;
715    ParamCommandCommentBits.IsDirectionExplicit = false;
716  }
717
718  static bool classof(const Comment *C) {
719    return C->getCommentKind() == ParamCommandCommentKind;
720  }
721
722  enum PassDirection {
723    In,
724    Out,
725    InOut
726  };
727
728  static const char *getDirectionAsString(PassDirection D);
729
730  PassDirection getDirection() const LLVM_READONLY {
731    return static_cast<PassDirection>(ParamCommandCommentBits.Direction);
732  }
733
734  bool isDirectionExplicit() const LLVM_READONLY {
735    return ParamCommandCommentBits.IsDirectionExplicit;
736  }
737
738  void setDirection(PassDirection Direction, bool Explicit) {
739    ParamCommandCommentBits.Direction = Direction;
740    ParamCommandCommentBits.IsDirectionExplicit = Explicit;
741  }
742
743  bool hasParamName() const {
744    return getNumArgs() > 0;
745  }
746
747  StringRef getParamName(const FullComment *FC) const;
748
749  StringRef getParamNameAsWritten() const {
750    return Args[0].Text;
751  }
752
753  SourceRange getParamNameRange() const {
754    return Args[0].Range;
755  }
756
757  bool isParamIndexValid() const LLVM_READONLY {
758    return ParamIndex != InvalidParamIndex;
759  }
760
761  bool isVarArgParam() const LLVM_READONLY {
762    return ParamIndex == VarArgParamIndex;
763  }
764
765  void setIsVarArgParam() {
766    ParamIndex = VarArgParamIndex;
767    assert(isParamIndexValid());
768  }
769
770  unsigned getParamIndex() const LLVM_READONLY {
771    assert(isParamIndexValid());
772    assert(!isVarArgParam());
773    return ParamIndex;
774  }
775
776  void setParamIndex(unsigned Index) {
777    ParamIndex = Index;
778    assert(isParamIndexValid());
779    assert(!isVarArgParam());
780  }
781};
782
783/// Doxygen \\tparam command, describes a template parameter.
784class TParamCommandComment : public BlockCommandComment {
785private:
786  /// If this template parameter name was resolved (found in template parameter
787  /// list), then this stores a list of position indexes in all template
788  /// parameter lists.
789  ///
790  /// For example:
791  /// \verbatim
792  ///     template<typename C, template<typename T> class TT>
793  ///     void test(TT<int> aaa);
794  /// \endverbatim
795  /// For C:  Position = { 0 }
796  /// For TT: Position = { 1 }
797  /// For T:  Position = { 1, 0 }
798  ArrayRef<unsigned> Position;
799
800public:
801  TParamCommandComment(SourceLocation LocBegin,
802                       SourceLocation LocEnd,
803                       unsigned CommandID,
804                       CommandMarkerKind CommandMarker) :
805      BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID,
806                          CommandMarker)
807  { }
808
809  static bool classof(const Comment *C) {
810    return C->getCommentKind() == TParamCommandCommentKind;
811  }
812
813  bool hasParamName() const {
814    return getNumArgs() > 0;
815  }
816
817  StringRef getParamName(const FullComment *FC) const;
818
819  StringRef getParamNameAsWritten() const {
820    return Args[0].Text;
821  }
822
823  SourceRange getParamNameRange() const {
824    return Args[0].Range;
825  }
826
827  bool isPositionValid() const LLVM_READONLY {
828    return !Position.empty();
829  }
830
831  unsigned getDepth() const {
832    assert(isPositionValid());
833    return Position.size();
834  }
835
836  unsigned getIndex(unsigned Depth) const {
837    assert(isPositionValid());
838    return Position[Depth];
839  }
840
841  void setPosition(ArrayRef<unsigned> NewPosition) {
842    Position = NewPosition;
843    assert(isPositionValid());
844  }
845};
846
847/// A line of text contained in a verbatim block.
848class VerbatimBlockLineComment : public Comment {
849  StringRef Text;
850
851public:
852  VerbatimBlockLineComment(SourceLocation LocBegin,
853                           StringRef Text) :
854      Comment(VerbatimBlockLineCommentKind,
855              LocBegin,
856              LocBegin.getLocWithOffset(Text.size())),
857      Text(Text)
858  { }
859
860  static bool classof(const Comment *C) {
861    return C->getCommentKind() == VerbatimBlockLineCommentKind;
862  }
863
864  child_iterator child_begin() const { return NULL; }
865
866  child_iterator child_end() const { return NULL; }
867
868  StringRef getText() const LLVM_READONLY {
869    return Text;
870  }
871};
872
873/// A verbatim block command (e. g., preformatted code).  Verbatim block has an
874/// opening and a closing command and contains multiple lines of text
875/// (VerbatimBlockLineComment nodes).
876class VerbatimBlockComment : public BlockCommandComment {
877protected:
878  StringRef CloseName;
879  SourceLocation CloseNameLocBegin;
880  ArrayRef<VerbatimBlockLineComment *> Lines;
881
882public:
883  VerbatimBlockComment(SourceLocation LocBegin,
884                       SourceLocation LocEnd,
885                       unsigned CommandID) :
886      BlockCommandComment(VerbatimBlockCommentKind,
887                          LocBegin, LocEnd, CommandID,
888                          CMK_At) // FIXME: improve source fidelity.
889  { }
890
891  static bool classof(const Comment *C) {
892    return C->getCommentKind() == VerbatimBlockCommentKind;
893  }
894
895  child_iterator child_begin() const {
896    return reinterpret_cast<child_iterator>(Lines.begin());
897  }
898
899  child_iterator child_end() const {
900    return reinterpret_cast<child_iterator>(Lines.end());
901  }
902
903  void setCloseName(StringRef Name, SourceLocation LocBegin) {
904    CloseName = Name;
905    CloseNameLocBegin = LocBegin;
906  }
907
908  void setLines(ArrayRef<VerbatimBlockLineComment *> L) {
909    Lines = L;
910  }
911
912  StringRef getCloseName() const {
913    return CloseName;
914  }
915
916  unsigned getNumLines() const {
917    return Lines.size();
918  }
919
920  StringRef getText(unsigned LineIdx) const {
921    return Lines[LineIdx]->getText();
922  }
923};
924
925/// A verbatim line command.  Verbatim line has an opening command, a single
926/// line of text (up to the newline after the opening command) and has no
927/// closing command.
928class VerbatimLineComment : public BlockCommandComment {
929protected:
930  StringRef Text;
931  SourceLocation TextBegin;
932
933public:
934  VerbatimLineComment(SourceLocation LocBegin,
935                      SourceLocation LocEnd,
936                      unsigned CommandID,
937                      SourceLocation TextBegin,
938                      StringRef Text) :
939      BlockCommandComment(VerbatimLineCommentKind,
940                          LocBegin, LocEnd,
941                          CommandID,
942                          CMK_At), // FIXME: improve source fidelity.
943      Text(Text),
944      TextBegin(TextBegin)
945  { }
946
947  static bool classof(const Comment *C) {
948    return C->getCommentKind() == VerbatimLineCommentKind;
949  }
950
951  child_iterator child_begin() const { return NULL; }
952
953  child_iterator child_end() const { return NULL; }
954
955  StringRef getText() const {
956    return Text;
957  }
958
959  SourceRange getTextRange() const {
960    return SourceRange(TextBegin, getLocEnd());
961  }
962};
963
964/// Information about the declaration, useful to clients of FullComment.
965struct DeclInfo {
966  /// Declaration the comment is actually attached to (in the source).
967  /// Should not be NULL.
968  const Decl *CommentDecl;
969
970  /// CurrentDecl is the declaration with which the FullComment is associated.
971  ///
972  /// It can be different from \c CommentDecl.  It happens when we we decide
973  /// that the comment originally attached to \c CommentDecl is fine for
974  /// \c CurrentDecl too (for example, for a redeclaration or an overrider of
975  /// \c CommentDecl).
976  ///
977  /// The information in the DeclInfo corresponds to CurrentDecl.
978  const Decl *CurrentDecl;
979
980  /// Parameters that can be referenced by \\param if \c CommentDecl is something
981  /// that we consider a "function".
982  ArrayRef<const ParmVarDecl *> ParamVars;
983
984  /// Function result type if \c CommentDecl is something that we consider
985  /// a "function".
986  QualType ResultType;
987
988  /// Template parameters that can be referenced by \\tparam if \c CommentDecl is
989  /// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is
990  /// true).
991  const TemplateParameterList *TemplateParameters;
992
993  /// A simplified description of \c CommentDecl kind that should be good enough
994  /// for documentation rendering purposes.
995  enum DeclKind {
996    /// Everything else not explicitly mentioned below.
997    OtherKind,
998
999    /// Something that we consider a "function":
1000    /// \li function,
1001    /// \li function template,
1002    /// \li function template specialization,
1003    /// \li member function,
1004    /// \li member function template,
1005    /// \li member function template specialization,
1006    /// \li ObjC method,
1007    /// \li a typedef for a function pointer, member function pointer,
1008    ///     ObjC block.
1009    FunctionKind,
1010
1011    /// Something that we consider a "class":
1012    /// \li class/struct,
1013    /// \li class template,
1014    /// \li class template (partial) specialization.
1015    ClassKind,
1016
1017    /// Something that we consider a "variable":
1018    /// \li namespace scope variables;
1019    /// \li static and non-static class data members;
1020    /// \li enumerators.
1021    VariableKind,
1022
1023    /// A C++ namespace.
1024    NamespaceKind,
1025
1026    /// A C++ typedef-name (a 'typedef' decl specifier or alias-declaration),
1027    /// see \c TypedefNameDecl.
1028    TypedefKind,
1029
1030    /// An enumeration or scoped enumeration.
1031    EnumKind
1032  };
1033
1034  /// What kind of template specialization \c CommentDecl is.
1035  enum TemplateDeclKind {
1036    NotTemplate,
1037    Template,
1038    TemplateSpecialization,
1039    TemplatePartialSpecialization
1040  };
1041
1042  /// If false, only \c CommentDecl is valid.
1043  unsigned IsFilled : 1;
1044
1045  /// Simplified kind of \c CommentDecl, see \c DeclKind enum.
1046  unsigned Kind : 3;
1047
1048  /// Is \c CommentDecl a template declaration.
1049  unsigned TemplateKind : 2;
1050
1051  /// Is \c CommentDecl an ObjCMethodDecl.
1052  unsigned IsObjCMethod : 1;
1053
1054  /// Is \c CommentDecl a non-static member function of C++ class or
1055  /// instance method of ObjC class.
1056  /// Can be true only if \c IsFunctionDecl is true.
1057  unsigned IsInstanceMethod : 1;
1058
1059  /// Is \c CommentDecl a static member function of C++ class or
1060  /// class method of ObjC class.
1061  /// Can be true only if \c IsFunctionDecl is true.
1062  unsigned IsClassMethod : 1;
1063
1064  void fill();
1065
1066  DeclKind getKind() const LLVM_READONLY {
1067    return static_cast<DeclKind>(Kind);
1068  }
1069
1070  TemplateDeclKind getTemplateKind() const LLVM_READONLY {
1071    return static_cast<TemplateDeclKind>(TemplateKind);
1072  }
1073};
1074
1075/// A full comment attached to a declaration, contains block content.
1076class FullComment : public Comment {
1077  ArrayRef<BlockContentComment *> Blocks;
1078  DeclInfo *ThisDeclInfo;
1079
1080public:
1081  FullComment(ArrayRef<BlockContentComment *> Blocks, DeclInfo *D) :
1082      Comment(FullCommentKind, SourceLocation(), SourceLocation()),
1083      Blocks(Blocks), ThisDeclInfo(D) {
1084    if (Blocks.empty())
1085      return;
1086
1087    setSourceRange(SourceRange(Blocks.front()->getLocStart(),
1088                               Blocks.back()->getLocEnd()));
1089    setLocation(Blocks.front()->getLocStart());
1090  }
1091
1092  static bool classof(const Comment *C) {
1093    return C->getCommentKind() == FullCommentKind;
1094  }
1095
1096  child_iterator child_begin() const {
1097    return reinterpret_cast<child_iterator>(Blocks.begin());
1098  }
1099
1100  child_iterator child_end() const {
1101    return reinterpret_cast<child_iterator>(Blocks.end());
1102  }
1103
1104  const Decl *getDecl() const LLVM_READONLY {
1105    return ThisDeclInfo->CommentDecl;
1106  }
1107
1108  const DeclInfo *getDeclInfo() const LLVM_READONLY {
1109    if (!ThisDeclInfo->IsFilled)
1110      ThisDeclInfo->fill();
1111    return ThisDeclInfo;
1112  }
1113
1114  DeclInfo *getThisDeclInfo() const LLVM_READONLY {
1115    return ThisDeclInfo;
1116  }
1117
1118  ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
1119
1120};
1121} // end namespace comments
1122} // end namespace clang
1123
1124#endif
1125
1126