Comment.h revision beef1cb6ebfaea4542fb6d6686caae27787a75e0
1//===--- Comment.h - Comment AST nodes --------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This file defines comment AST nodes.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_AST_COMMENT_H
15#define LLVM_CLANG_AST_COMMENT_H
16
17#include "clang/Basic/SourceLocation.h"
18#include "llvm/ADT/ArrayRef.h"
19#include "llvm/ADT/StringRef.h"
20
21namespace clang {
22namespace comments {
23
24/// Any part of the comment.
25/// Abstract class.
26class Comment {
27protected:
28  /// Preferred location to show caret.
29  SourceLocation Loc;
30
31  /// Source range of this AST node.
32  SourceRange Range;
33
34  class CommentBitfields {
35    friend class Comment;
36
37    /// Type of this AST node.
38    unsigned Kind : 8;
39  };
40  enum { NumCommentBits = 8 };
41
42  class InlineContentCommentBitfields {
43    friend class InlineContentComment;
44
45    unsigned : NumCommentBits;
46
47    /// True if there is a newline after this inline content node.
48    /// (There is no separate AST node for a newline.)
49    unsigned HasTrailingNewline : 1;
50  };
51  enum { NumInlineContentCommentBitfields = 9 };
52
53  class HTMLStartTagCommentBitfields {
54    friend class HTMLStartTagComment;
55
56    unsigned : NumInlineContentCommentBitfields;
57
58    /// True if this tag is self-closing (e. g., <br />).  This is based on tag
59    /// spelling in comment (plain <br> would not set this flag).
60    unsigned IsSelfClosing : 1;
61  };
62
63  class ParamCommandCommentBitfields {
64    friend class ParamCommandComment;
65
66    unsigned : NumCommentBits;
67
68    /// Parameter passing direction, see ParamCommandComment::PassDirection.
69    unsigned Direction : 2;
70
71    /// True if direction was specified explicitly in the comment.
72    unsigned IsDirectionExplicit : 1;
73  };
74  enum { NumParamCommandCommentBitfields = 11 };
75
76  union {
77    CommentBitfields CommentBits;
78    InlineContentCommentBitfields InlineContentCommentBits;
79    HTMLStartTagCommentBitfields HTMLStartTagCommentBits;
80    ParamCommandCommentBitfields ParamCommandCommentBits;
81  };
82
83  void setSourceRange(SourceRange SR) {
84    Range = SR;
85  }
86
87  void setLocation(SourceLocation L) {
88    Loc = L;
89  }
90
91public:
92  enum CommentKind {
93    NoCommentKind = 0,
94#define COMMENT(CLASS, PARENT) CLASS##Kind,
95#define COMMENT_RANGE(BASE, FIRST, LAST) \
96    First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind,
97#define LAST_COMMENT_RANGE(BASE, FIRST, LAST) \
98    First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind
99#define ABSTRACT_COMMENT(COMMENT)
100#include "clang/AST/CommentNodes.inc"
101  };
102
103  Comment(CommentKind K,
104          SourceLocation LocBegin,
105          SourceLocation LocEnd) :
106      Loc(LocBegin), Range(SourceRange(LocBegin, LocEnd)) {
107    CommentBits.Kind = K;
108  }
109
110  CommentKind getCommentKind() const {
111    return static_cast<CommentKind>(CommentBits.Kind);
112  }
113
114  const char *getCommentKindName() const;
115
116  LLVM_ATTRIBUTE_USED void dump() const;
117  LLVM_ATTRIBUTE_USED void dump(SourceManager &SM) const;
118
119  static bool classof(const Comment *) { return true; }
120
121  SourceRange getSourceRange() const LLVM_READONLY { return Range; }
122
123  SourceLocation getLocStart() const LLVM_READONLY {
124    return Range.getBegin();
125  }
126
127  SourceLocation getLocEnd() const LLVM_READONLY {
128    return Range.getEnd();
129  }
130
131  SourceLocation getLocation() const LLVM_READONLY { return Loc; }
132
133  typedef Comment * const *child_iterator;
134
135  child_iterator child_begin() const;
136  child_iterator child_end() const;
137
138  // TODO: const child iterator
139
140  unsigned child_count() const {
141    return child_end() - child_begin();
142  }
143};
144
145/// Inline content (contained within a block).
146/// Abstract class.
147class InlineContentComment : public Comment {
148protected:
149  InlineContentComment(CommentKind K,
150                       SourceLocation LocBegin,
151                       SourceLocation LocEnd) :
152      Comment(K, LocBegin, LocEnd) {
153    InlineContentCommentBits.HasTrailingNewline = 0;
154  }
155
156public:
157  static bool classof(const Comment *C) {
158    return C->getCommentKind() >= FirstInlineContentCommentConstant &&
159           C->getCommentKind() <= LastInlineContentCommentConstant;
160  }
161
162  static bool classof(const InlineContentComment *) { return true; }
163
164  void addTrailingNewline() {
165    InlineContentCommentBits.HasTrailingNewline = 1;
166  }
167
168  bool hasTrailingNewline() const {
169    return InlineContentCommentBits.HasTrailingNewline;
170  }
171};
172
173/// Plain text.
174class TextComment : public InlineContentComment {
175  StringRef Text;
176
177public:
178  TextComment(SourceLocation LocBegin,
179              SourceLocation LocEnd,
180              StringRef Text) :
181      InlineContentComment(TextCommentKind, LocBegin, LocEnd),
182      Text(Text)
183  { }
184
185  static bool classof(const Comment *C) {
186    return C->getCommentKind() == TextCommentKind;
187  }
188
189  static bool classof(const TextComment *) { return true; }
190
191  child_iterator child_begin() const { return NULL; }
192
193  child_iterator child_end() const { return NULL; }
194
195  StringRef getText() const LLVM_READONLY { return Text; }
196
197  bool isWhitespace() const;
198};
199
200/// A command with word-like arguments that is considered inline content.
201class InlineCommandComment : public InlineContentComment {
202public:
203  struct Argument {
204    SourceRange Range;
205    StringRef Text;
206
207    Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { }
208  };
209
210protected:
211  /// Command name.
212  StringRef Name;
213
214  /// Command arguments.
215  llvm::ArrayRef<Argument> Args;
216
217public:
218  InlineCommandComment(SourceLocation LocBegin,
219                       SourceLocation LocEnd,
220                       StringRef Name,
221                       llvm::ArrayRef<Argument> Args) :
222    InlineContentComment(InlineCommandCommentKind, LocBegin, LocEnd),
223    Name(Name), Args(Args)
224  { }
225
226  static bool classof(const Comment *C) {
227    return C->getCommentKind() == InlineCommandCommentKind;
228  }
229
230  static bool classof(const InlineCommandComment *) { return true; }
231
232  child_iterator child_begin() const { return NULL; }
233
234  child_iterator child_end() const { return NULL; }
235
236  StringRef getCommandName() const {
237    return Name;
238  }
239
240  SourceRange getCommandNameRange() const {
241    return SourceRange(getLocStart().getLocWithOffset(-1),
242                       getLocEnd());
243  }
244
245  unsigned getNumArgs() const {
246    return Args.size();
247  }
248
249  StringRef getArgText(unsigned Idx) const {
250    return Args[Idx].Text;
251  }
252
253  SourceRange getArgRange(unsigned Idx) const {
254    return Args[Idx].Range;
255  }
256};
257
258/// Abstract class for opening and closing HTML tags.  HTML tags are always
259/// treated as inline content (regardless HTML semantics); opening and closing
260/// tags are not matched.
261class HTMLTagComment : public InlineContentComment {
262protected:
263  StringRef TagName;
264  SourceRange TagNameRange;
265
266  HTMLTagComment(CommentKind K,
267                 SourceLocation LocBegin,
268                 SourceLocation LocEnd,
269                 StringRef TagName,
270                 SourceLocation TagNameBegin,
271                 SourceLocation TagNameEnd) :
272      InlineContentComment(K, LocBegin, LocEnd),
273      TagName(TagName),
274      TagNameRange(TagNameBegin, TagNameEnd) {
275    setLocation(TagNameBegin);
276  }
277
278public:
279  static bool classof(const Comment *C) {
280    return C->getCommentKind() >= FirstHTMLTagCommentConstant &&
281           C->getCommentKind() <= LastHTMLTagCommentConstant;
282  }
283
284  static bool classof(const HTMLTagComment *) { return true; }
285
286  StringRef getTagName() const LLVM_READONLY { return TagName; }
287
288  SourceRange getTagNameSourceRange() const LLVM_READONLY {
289    SourceLocation L = getLocation();
290    return SourceRange(L.getLocWithOffset(1),
291                       L.getLocWithOffset(1 + TagName.size()));
292  }
293};
294
295/// An opening HTML tag with attributes.
296class HTMLStartTagComment : public HTMLTagComment {
297public:
298  class Attribute {
299  public:
300    SourceLocation NameLocBegin;
301    StringRef Name;
302
303    SourceLocation EqualsLoc;
304
305    SourceRange ValueRange;
306    StringRef Value;
307
308    Attribute() { }
309
310    Attribute(SourceLocation NameLocBegin, StringRef Name) :
311        NameLocBegin(NameLocBegin), Name(Name),
312        EqualsLoc(SourceLocation()),
313        ValueRange(SourceRange()), Value(StringRef())
314    { }
315
316    Attribute(SourceLocation NameLocBegin, StringRef Name,
317              SourceLocation EqualsLoc,
318              SourceRange ValueRange, StringRef Value) :
319        NameLocBegin(NameLocBegin), Name(Name),
320        EqualsLoc(EqualsLoc),
321        ValueRange(ValueRange), Value(Value)
322    { }
323
324    SourceLocation getNameLocEnd() const {
325      return NameLocBegin.getLocWithOffset(Name.size());
326    }
327
328    SourceRange getNameRange() const {
329      return SourceRange(NameLocBegin, getNameLocEnd());
330    }
331  };
332
333private:
334  ArrayRef<Attribute> Attributes;
335
336public:
337  HTMLStartTagComment(SourceLocation LocBegin,
338                      StringRef TagName) :
339      HTMLTagComment(HTMLStartTagCommentKind,
340                     LocBegin, LocBegin.getLocWithOffset(1 + TagName.size()),
341                     TagName,
342                     LocBegin.getLocWithOffset(1),
343                     LocBegin.getLocWithOffset(1 + TagName.size())) {
344    HTMLStartTagCommentBits.IsSelfClosing = false;
345  }
346
347  static bool classof(const Comment *C) {
348    return C->getCommentKind() == HTMLStartTagCommentKind;
349  }
350
351  static bool classof(const HTMLStartTagComment *) { return true; }
352
353  child_iterator child_begin() const { return NULL; }
354
355  child_iterator child_end() const { return NULL; }
356
357  unsigned getNumAttrs() const {
358    return Attributes.size();
359  }
360
361  const Attribute &getAttr(unsigned Idx) const {
362    return Attributes[Idx];
363  }
364
365  void setAttrs(ArrayRef<Attribute> Attrs) {
366    Attributes = Attrs;
367    if (!Attrs.empty()) {
368      const Attribute &Attr = Attrs.back();
369      SourceLocation L = Attr.ValueRange.getEnd();
370      if (L.isValid())
371        Range.setEnd(L);
372      else {
373        Range.setEnd(Attr.getNameLocEnd());
374      }
375    }
376  }
377
378  void setGreaterLoc(SourceLocation GreaterLoc) {
379    Range.setEnd(GreaterLoc);
380  }
381
382  bool isSelfClosing() const {
383    return HTMLStartTagCommentBits.IsSelfClosing;
384  }
385
386  void setSelfClosing() {
387    HTMLStartTagCommentBits.IsSelfClosing = true;
388  }
389};
390
391/// A closing HTML tag.
392class HTMLEndTagComment : public HTMLTagComment {
393public:
394  HTMLEndTagComment(SourceLocation LocBegin,
395                    SourceLocation LocEnd,
396                    StringRef TagName) :
397      HTMLTagComment(HTMLEndTagCommentKind,
398                     LocBegin, LocEnd,
399                     TagName,
400                     LocBegin.getLocWithOffset(2),
401                     LocBegin.getLocWithOffset(2 + TagName.size()))
402  { }
403
404  static bool classof(const Comment *C) {
405    return C->getCommentKind() == HTMLEndTagCommentKind;
406  }
407
408  static bool classof(const HTMLEndTagComment *) { return true; }
409
410  child_iterator child_begin() const { return NULL; }
411
412  child_iterator child_end() const { return NULL; }
413};
414
415/// Block content (contains inline content).
416/// Abstract class.
417class BlockContentComment : public Comment {
418protected:
419  BlockContentComment(CommentKind K,
420                      SourceLocation LocBegin,
421                      SourceLocation LocEnd) :
422      Comment(K, LocBegin, LocEnd)
423  { }
424
425public:
426  static bool classof(const Comment *C) {
427    return C->getCommentKind() >= FirstBlockContentCommentConstant &&
428           C->getCommentKind() <= LastBlockContentCommentConstant;
429  }
430
431  static bool classof(const BlockContentComment *) { return true; }
432};
433
434/// A single paragraph that contains inline content.
435class ParagraphComment : public BlockContentComment {
436  llvm::ArrayRef<InlineContentComment *> Content;
437
438public:
439  ParagraphComment(llvm::ArrayRef<InlineContentComment *> Content) :
440      BlockContentComment(ParagraphCommentKind,
441                          SourceLocation(),
442                          SourceLocation()),
443      Content(Content) {
444    if (Content.empty())
445      return;
446
447    setSourceRange(SourceRange(Content.front()->getLocStart(),
448                               Content.back()->getLocEnd()));
449    setLocation(Content.front()->getLocStart());
450  }
451
452  static bool classof(const Comment *C) {
453    return C->getCommentKind() == ParagraphCommentKind;
454  }
455
456  static bool classof(const ParagraphComment *) { return true; }
457
458  child_iterator child_begin() const {
459    return reinterpret_cast<child_iterator>(Content.begin());
460  }
461
462  child_iterator child_end() const {
463    return reinterpret_cast<child_iterator>(Content.end());
464  }
465
466  bool isWhitespace() const;
467};
468
469/// A command that has zero or more word-like arguments (number of word-like
470/// arguments depends on command name) and a paragraph as an argument
471/// (e. g., \\brief).
472class BlockCommandComment : public BlockContentComment {
473public:
474  struct Argument {
475    SourceRange Range;
476    StringRef Text;
477
478    Argument() { }
479    Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { }
480  };
481
482protected:
483  /// Command name.
484  StringRef Name;
485
486  /// Word-like arguments.
487  llvm::ArrayRef<Argument> Args;
488
489  /// Paragraph argument.
490  ParagraphComment *Paragraph;
491
492  BlockCommandComment(CommentKind K,
493                      SourceLocation LocBegin,
494                      SourceLocation LocEnd,
495                      StringRef Name) :
496      BlockContentComment(K, LocBegin, LocEnd),
497      Name(Name),
498      Paragraph(NULL) {
499    setLocation(getCommandNameRange().getBegin());
500  }
501
502public:
503  BlockCommandComment(SourceLocation LocBegin,
504                      SourceLocation LocEnd,
505                      StringRef Name) :
506      BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd),
507      Name(Name),
508      Paragraph(NULL) {
509    setLocation(getCommandNameRange().getBegin());
510  }
511
512  static bool classof(const Comment *C) {
513    return C->getCommentKind() >= FirstBlockCommandCommentConstant &&
514           C->getCommentKind() <= LastBlockCommandCommentConstant;
515  }
516
517  static bool classof(const BlockCommandComment *) { return true; }
518
519  child_iterator child_begin() const {
520    return reinterpret_cast<child_iterator>(&Paragraph);
521  }
522
523  child_iterator child_end() const {
524    return reinterpret_cast<child_iterator>(&Paragraph + 1);
525  }
526
527  StringRef getCommandName() const {
528    return Name;
529  }
530
531  SourceRange getCommandNameRange() const {
532    return SourceRange(getLocStart().getLocWithOffset(1),
533                       getLocStart().getLocWithOffset(1 + Name.size()));
534  }
535
536  unsigned getNumArgs() const {
537    return Args.size();
538  }
539
540  StringRef getArgText(unsigned Idx) const {
541    return Args[Idx].Text;
542  }
543
544  SourceRange getArgRange(unsigned Idx) const {
545    return Args[Idx].Range;
546  }
547
548  void setArgs(llvm::ArrayRef<Argument> A) {
549    Args = A;
550    if (Args.size() > 0) {
551      SourceLocation NewLocEnd = Args.back().Range.getEnd();
552      if (NewLocEnd.isValid())
553        setSourceRange(SourceRange(getLocStart(), NewLocEnd));
554    }
555  }
556
557  ParagraphComment *getParagraph() const LLVM_READONLY {
558    return Paragraph;
559  }
560
561  void setParagraph(ParagraphComment *PC) {
562    Paragraph = PC;
563    SourceLocation NewLocEnd = PC->getLocEnd();
564    if (NewLocEnd.isValid())
565      setSourceRange(SourceRange(getLocStart(), NewLocEnd));
566  }
567};
568
569/// Doxygen \\param command.
570class ParamCommandComment : public BlockCommandComment {
571private:
572  /// Parameter index in the function declaration.
573  unsigned ParamIndex;
574
575public:
576  enum { InvalidParamIndex = ~0U };
577
578  ParamCommandComment(SourceLocation LocBegin,
579                      SourceLocation LocEnd,
580                      StringRef Name) :
581      BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, Name),
582      ParamIndex(InvalidParamIndex) {
583    ParamCommandCommentBits.Direction = In;
584    ParamCommandCommentBits.IsDirectionExplicit = false;
585  }
586
587  static bool classof(const Comment *C) {
588    return C->getCommentKind() == ParamCommandCommentKind;
589  }
590
591  static bool classof(const ParamCommandComment *) { return true; }
592
593  enum PassDirection {
594    In,
595    Out,
596    InOut
597  };
598
599  static const char *getDirectionAsString(PassDirection D);
600
601  PassDirection getDirection() const LLVM_READONLY {
602    return static_cast<PassDirection>(ParamCommandCommentBits.Direction);
603  }
604
605  bool isDirectionExplicit() const LLVM_READONLY {
606    return ParamCommandCommentBits.IsDirectionExplicit;
607  }
608
609  void setDirection(PassDirection Direction, bool Explicit) {
610    ParamCommandCommentBits.Direction = Direction;
611    ParamCommandCommentBits.IsDirectionExplicit = Explicit;
612  }
613
614  bool hasParamName() const {
615    return getNumArgs() > 0;
616  }
617
618  StringRef getParamName() const {
619    return Args[0].Text;
620  }
621
622  SourceRange getParamNameRange() const {
623    return Args[0].Range;
624  }
625
626  bool isParamIndexValid() const LLVM_READONLY {
627    return ParamIndex != InvalidParamIndex;
628  }
629
630  unsigned getParamIndex() const LLVM_READONLY {
631    return ParamIndex;
632  }
633
634  void setParamIndex(unsigned Index) {
635    ParamIndex = Index;
636    assert(isParamIndexValid());
637  }
638};
639
640/// A line of text contained in a verbatim block.
641class VerbatimBlockLineComment : public Comment {
642  StringRef Text;
643
644public:
645  VerbatimBlockLineComment(SourceLocation LocBegin,
646                           StringRef Text) :
647      Comment(VerbatimBlockLineCommentKind,
648              LocBegin,
649              LocBegin.getLocWithOffset(Text.size())),
650      Text(Text)
651  { }
652
653  static bool classof(const Comment *C) {
654    return C->getCommentKind() == VerbatimBlockLineCommentKind;
655  }
656
657  static bool classof(const VerbatimBlockLineComment *) { return true; }
658
659  child_iterator child_begin() const { return NULL; }
660
661  child_iterator child_end() const { return NULL; }
662
663  StringRef getText() const LLVM_READONLY {
664    return Text;
665  }
666};
667
668/// A verbatim block command (e. g., preformatted code).  Verbatim block has an
669/// opening and a closing command and contains multiple lines of text
670/// (VerbatimBlockLineComment nodes).
671class VerbatimBlockComment : public BlockCommandComment {
672protected:
673  StringRef CloseName;
674  SourceLocation CloseNameLocBegin;
675  llvm::ArrayRef<VerbatimBlockLineComment *> Lines;
676
677public:
678  VerbatimBlockComment(SourceLocation LocBegin,
679                       SourceLocation LocEnd,
680                       StringRef Name) :
681      BlockCommandComment(VerbatimBlockCommentKind,
682                          LocBegin, LocEnd, Name)
683  { }
684
685  static bool classof(const Comment *C) {
686    return C->getCommentKind() == VerbatimBlockCommentKind;
687  }
688
689  static bool classof(const VerbatimBlockComment *) { return true; }
690
691  child_iterator child_begin() const {
692    return reinterpret_cast<child_iterator>(Lines.begin());
693  }
694
695  child_iterator child_end() const {
696    return reinterpret_cast<child_iterator>(Lines.end());
697  }
698
699  void setCloseName(StringRef Name, SourceLocation LocBegin) {
700    CloseName = Name;
701    CloseNameLocBegin = LocBegin;
702  }
703
704  void setLines(llvm::ArrayRef<VerbatimBlockLineComment *> L) {
705    Lines = L;
706  }
707
708  StringRef getCloseName() const {
709    return CloseName;
710  }
711
712  unsigned getNumLines() const {
713    return Lines.size();
714  }
715
716  StringRef getText(unsigned LineIdx) const {
717    return Lines[LineIdx]->getText();
718  }
719};
720
721/// A verbatim line command.  Verbatim line has an opening command, a single
722/// line of text (up to the newline after the opening command) and has no
723/// closing command.
724class VerbatimLineComment : public BlockCommandComment {
725protected:
726  StringRef Text;
727  SourceLocation TextBegin;
728
729public:
730  VerbatimLineComment(SourceLocation LocBegin,
731                      SourceLocation LocEnd,
732                      StringRef Name,
733                      SourceLocation TextBegin,
734                      StringRef Text) :
735      BlockCommandComment(VerbatimLineCommentKind,
736                          LocBegin, LocEnd,
737                          Name),
738      Text(Text),
739      TextBegin(TextBegin)
740  { }
741
742  static bool classof(const Comment *C) {
743    return C->getCommentKind() == VerbatimLineCommentKind;
744  }
745
746  static bool classof(const VerbatimLineComment *) { return true; }
747
748  child_iterator child_begin() const { return NULL; }
749
750  child_iterator child_end() const { return NULL; }
751
752  StringRef getText() const {
753    return Text;
754  }
755
756  SourceRange getTextRange() const {
757    return SourceRange(TextBegin, getLocEnd());
758  }
759};
760
761/// A full comment attached to a declaration, contains block content.
762class FullComment : public Comment {
763  llvm::ArrayRef<BlockContentComment *> Blocks;
764
765public:
766  FullComment(llvm::ArrayRef<BlockContentComment *> Blocks) :
767      Comment(FullCommentKind, SourceLocation(), SourceLocation()),
768      Blocks(Blocks) {
769    if (Blocks.empty())
770      return;
771
772    setSourceRange(SourceRange(Blocks.front()->getLocStart(),
773                               Blocks.back()->getLocEnd()));
774    setLocation(Blocks.front()->getLocStart());
775  }
776
777  static bool classof(const Comment *C) {
778    return C->getCommentKind() == FullCommentKind;
779  }
780
781  static bool classof(const FullComment *) { return true; }
782
783  child_iterator child_begin() const {
784    return reinterpret_cast<child_iterator>(Blocks.begin());
785  }
786
787  child_iterator child_end() const {
788    return reinterpret_cast<child_iterator>(Blocks.end());
789  }
790};
791
792} // end namespace comments
793} // end namespace clang
794
795#endif
796
797