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