Comment.h revision a5ef44ff5d93a3be6ca67782828157a71894cf0c
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 HTMLOpenTagCommentBitfields {
54    friend class HTMLOpenTagComment;
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    HTMLOpenTagCommentBitfields HTMLOpenTagCommentBits;
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 getArgCount() 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 HTMLOpenTagComment : 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  HTMLOpenTagComment(SourceLocation LocBegin,
338                     StringRef TagName) :
339      HTMLTagComment(HTMLOpenTagCommentKind,
340                     LocBegin, LocBegin.getLocWithOffset(1 + TagName.size()),
341                     TagName,
342                     LocBegin.getLocWithOffset(1),
343                     LocBegin.getLocWithOffset(1 + TagName.size())) {
344    HTMLOpenTagCommentBits.IsSelfClosing = false;
345  }
346
347  static bool classof(const Comment *C) {
348    return C->getCommentKind() == HTMLOpenTagCommentKind;
349  }
350
351  static bool classof(const HTMLOpenTagComment *) { return true; }
352
353  child_iterator child_begin() const { return NULL; }
354
355  child_iterator child_end() const { return NULL; }
356
357  unsigned getAttrCount() 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 HTMLOpenTagCommentBits.IsSelfClosing;
384  }
385
386  void setSelfClosing() {
387    HTMLOpenTagCommentBits.IsSelfClosing = true;
388  }
389};
390
391/// A closing HTML tag.
392class HTMLCloseTagComment : public HTMLTagComment {
393public:
394  HTMLCloseTagComment(SourceLocation LocBegin,
395                      SourceLocation LocEnd,
396                      StringRef TagName) :
397      HTMLTagComment(HTMLCloseTagCommentKind,
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() == HTMLCloseTagCommentKind;
406  }
407
408  static bool classof(const HTMLCloseTagComment *) { 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() == BlockCommandCommentKind;
514  }
515
516  static bool classof(const BlockCommandComment *) { return true; }
517
518  child_iterator child_begin() const {
519    return reinterpret_cast<child_iterator>(&Paragraph);
520  }
521
522  child_iterator child_end() const {
523    return reinterpret_cast<child_iterator>(&Paragraph + 1);
524  }
525
526  StringRef getCommandName() const {
527    return Name;
528  }
529
530  SourceRange getCommandNameRange() const {
531    return SourceRange(getLocStart().getLocWithOffset(1),
532                       getLocStart().getLocWithOffset(1 + Name.size()));
533  }
534
535  unsigned getArgCount() const {
536    return Args.size();
537  }
538
539  StringRef getArgText(unsigned Idx) const {
540    return Args[Idx].Text;
541  }
542
543  SourceRange getArgRange(unsigned Idx) const {
544    return Args[Idx].Range;
545  }
546
547  void setArgs(llvm::ArrayRef<Argument> A) {
548    Args = A;
549    if (Args.size() > 0) {
550      SourceLocation NewLocEnd = Args.back().Range.getEnd();
551      if (NewLocEnd.isValid())
552        setSourceRange(SourceRange(getLocStart(), NewLocEnd));
553    }
554  }
555
556  ParagraphComment *getParagraph() const LLVM_READONLY {
557    return Paragraph;
558  }
559
560  void setParagraph(ParagraphComment *PC) {
561    Paragraph = PC;
562    SourceLocation NewLocEnd = PC->getLocEnd();
563    if (NewLocEnd.isValid())
564      setSourceRange(SourceRange(getLocStart(), NewLocEnd));
565  }
566};
567
568/// Doxygen \\param command.
569class ParamCommandComment : public BlockCommandComment {
570private:
571  /// Parameter index in the function declaration.
572  unsigned ParamIndex;
573
574public:
575  enum { InvalidParamIndex = ~0U };
576
577  ParamCommandComment(SourceLocation LocBegin,
578                      SourceLocation LocEnd,
579                      StringRef Name) :
580      BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, Name),
581      ParamIndex(InvalidParamIndex) {
582    ParamCommandCommentBits.Direction = In;
583    ParamCommandCommentBits.IsDirectionExplicit = false;
584  }
585
586  static bool classof(const Comment *C) {
587    return C->getCommentKind() == ParamCommandCommentKind;
588  }
589
590  static bool classof(const ParamCommandComment *) { return true; }
591
592  enum PassDirection {
593    In,
594    Out,
595    InOut
596  };
597
598  static const char *getDirectionAsString(PassDirection D);
599
600  PassDirection getDirection() const LLVM_READONLY {
601    return static_cast<PassDirection>(ParamCommandCommentBits.Direction);
602  }
603
604  bool isDirectionExplicit() const LLVM_READONLY {
605    return ParamCommandCommentBits.IsDirectionExplicit;
606  }
607
608  void setDirection(PassDirection Direction, bool Explicit) {
609    ParamCommandCommentBits.Direction = Direction;
610    ParamCommandCommentBits.IsDirectionExplicit = Explicit;
611  }
612
613  bool hasParamName() const {
614    return getArgCount() > 0;
615  }
616
617  StringRef getParamName() const {
618    return Args[0].Text;
619  }
620
621  SourceRange getParamNameRange() const {
622    return Args[0].Range;
623  }
624
625  bool isParamIndexValid() const LLVM_READONLY {
626    return ParamIndex != InvalidParamIndex;
627  }
628
629  unsigned getParamIndex() const LLVM_READONLY {
630    return ParamIndex;
631  }
632
633  void setParamIndex(unsigned Index) {
634    ParamIndex = Index;
635    assert(isParamIndexValid());
636  }
637};
638
639/// A line of text contained in a verbatim block.
640class VerbatimBlockLineComment : public Comment {
641  StringRef Text;
642
643public:
644  VerbatimBlockLineComment(SourceLocation LocBegin,
645                           StringRef Text) :
646      Comment(VerbatimBlockLineCommentKind,
647              LocBegin,
648              LocBegin.getLocWithOffset(Text.size())),
649      Text(Text)
650  { }
651
652  static bool classof(const Comment *C) {
653    return C->getCommentKind() == VerbatimBlockLineCommentKind;
654  }
655
656  static bool classof(const VerbatimBlockLineComment *) { return true; }
657
658  child_iterator child_begin() const { return NULL; }
659
660  child_iterator child_end() const { return NULL; }
661
662  StringRef getText() const LLVM_READONLY {
663    return Text;
664  }
665};
666
667/// Verbatim block (e. g., preformatted code).  Verbatim block has an opening
668/// and a closing command and contains multiple lines of text
669/// (VerbatimBlockLineComment nodes).
670class VerbatimBlockComment : public BlockCommandComment {
671protected:
672  StringRef CloseName;
673  SourceLocation CloseNameLocBegin;
674  llvm::ArrayRef<VerbatimBlockLineComment *> Lines;
675
676public:
677  VerbatimBlockComment(SourceLocation LocBegin,
678                       SourceLocation LocEnd,
679                       StringRef Name) :
680      BlockCommandComment(VerbatimBlockCommentKind,
681                          LocBegin, LocEnd, Name)
682  { }
683
684  static bool classof(const Comment *C) {
685    return C->getCommentKind() == VerbatimBlockCommentKind;
686  }
687
688  static bool classof(const VerbatimBlockComment *) { return true; }
689
690  child_iterator child_begin() const {
691    return reinterpret_cast<child_iterator>(Lines.begin());
692  }
693
694  child_iterator child_end() const {
695    return reinterpret_cast<child_iterator>(Lines.end());
696  }
697
698  void setCloseName(StringRef Name, SourceLocation LocBegin) {
699    CloseName = Name;
700    CloseNameLocBegin = LocBegin;
701  }
702
703  void setLines(llvm::ArrayRef<VerbatimBlockLineComment *> L) {
704    Lines = L;
705  }
706
707  StringRef getCloseName() const {
708    return CloseName;
709  }
710
711  unsigned getLineCount() const {
712    return Lines.size();
713  }
714
715  StringRef getText(unsigned LineIdx) const {
716    return Lines[LineIdx]->getText();
717  }
718};
719
720/// Verbatim line.  Verbatim line has an opening command and a single line of
721/// text (up to the newline after the opening command).
722class VerbatimLineComment : public BlockCommandComment {
723protected:
724  StringRef Text;
725  SourceLocation TextBegin;
726
727public:
728  VerbatimLineComment(SourceLocation LocBegin,
729                      SourceLocation LocEnd,
730                      StringRef Name,
731                      SourceLocation TextBegin,
732                      StringRef Text) :
733      BlockCommandComment(VerbatimLineCommentKind,
734                          LocBegin, LocEnd,
735                          Name),
736      Text(Text),
737      TextBegin(TextBegin)
738  { }
739
740  static bool classof(const Comment *C) {
741    return C->getCommentKind() == VerbatimLineCommentKind;
742  }
743
744  static bool classof(const VerbatimLineComment *) { return true; }
745
746  child_iterator child_begin() const { return NULL; }
747
748  child_iterator child_end() const { return NULL; }
749
750  StringRef getText() const {
751    return Text;
752  }
753
754  SourceRange getTextRange() const {
755    return SourceRange(TextBegin, getLocEnd());
756  }
757};
758
759/// A full comment attached to a declaration, contains block content.
760class FullComment : public Comment {
761  llvm::ArrayRef<BlockContentComment *> Blocks;
762
763public:
764  FullComment(llvm::ArrayRef<BlockContentComment *> Blocks) :
765      Comment(FullCommentKind, SourceLocation(), SourceLocation()),
766      Blocks(Blocks) {
767    if (Blocks.empty())
768      return;
769
770    setSourceRange(SourceRange(Blocks.front()->getLocStart(),
771                               Blocks.back()->getLocEnd()));
772    setLocation(Blocks.front()->getLocStart());
773  }
774
775  static bool classof(const Comment *C) {
776    return C->getCommentKind() == FullCommentKind;
777  }
778
779  static bool classof(const FullComment *) { return true; }
780
781  child_iterator child_begin() const {
782    return reinterpret_cast<child_iterator>(Blocks.begin());
783  }
784
785  child_iterator child_end() const {
786    return reinterpret_cast<child_iterator>(Blocks.end());
787  }
788};
789
790} // end namespace comments
791} // end namespace clang
792
793#endif
794
795