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