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