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