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