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