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