Comment.h revision 808383d2d6d58a7c7db85f8c7618fb74d821309f
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 { 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.
770class TParamCommandComment : public BlockCommandComment {
771private:
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
786public:
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.
834class VerbatimBlockLineComment : public Comment {
835  StringRef Text;
836
837public:
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).
862class VerbatimBlockComment : public BlockCommandComment {
863protected:
864  StringRef CloseName;
865  SourceLocation CloseNameLocBegin;
866  ArrayRef<VerbatimBlockLineComment *> Lines;
867
868public:
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.
914class VerbatimLineComment : public BlockCommandComment {
915protected:
916  StringRef Text;
917  SourceLocation TextBegin;
918
919public:
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.
951struct 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.
1062class FullComment : public Comment {
1063  ArrayRef<BlockContentComment *> Blocks;
1064  DeclInfo *ThisDeclInfo;
1065
1066public:
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
1112