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