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