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