• 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 { InvalidParamIndex = ~0U };
703 
ParamCommandComment(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID,CommandMarkerKind CommandMarker)704   ParamCommandComment(SourceLocation LocBegin,
705                       SourceLocation LocEnd,
706                       unsigned CommandID,
707                       CommandMarkerKind CommandMarker) :
708       BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd,
709                           CommandID, CommandMarker),
710       ParamIndex(InvalidParamIndex) {
711     ParamCommandCommentBits.Direction = In;
712     ParamCommandCommentBits.IsDirectionExplicit = false;
713   }
714 
classof(const Comment * C)715   static bool classof(const Comment *C) {
716     return C->getCommentKind() == ParamCommandCommentKind;
717   }
718 
719   enum PassDirection {
720     In,
721     Out,
722     InOut
723   };
724 
725   static const char *getDirectionAsString(PassDirection D);
726 
getDirection()727   PassDirection getDirection() const LLVM_READONLY {
728     return static_cast<PassDirection>(ParamCommandCommentBits.Direction);
729   }
730 
isDirectionExplicit()731   bool isDirectionExplicit() const LLVM_READONLY {
732     return ParamCommandCommentBits.IsDirectionExplicit;
733   }
734 
setDirection(PassDirection Direction,bool Explicit)735   void setDirection(PassDirection Direction, bool Explicit) {
736     ParamCommandCommentBits.Direction = Direction;
737     ParamCommandCommentBits.IsDirectionExplicit = Explicit;
738   }
739 
hasParamName()740   bool hasParamName() const {
741     return getNumArgs() > 0;
742   }
743 
744   StringRef getParamName(const FullComment *FC) const;
745 
getParamNameAsWritten()746   StringRef getParamNameAsWritten() const {
747     return Args[0].Text;
748   }
749 
getParamNameRange()750   SourceRange getParamNameRange() const {
751     return Args[0].Range;
752   }
753 
isParamIndexValid()754   bool isParamIndexValid() const LLVM_READONLY {
755     return ParamIndex != InvalidParamIndex;
756   }
757 
getParamIndex()758   unsigned getParamIndex() const LLVM_READONLY {
759     assert(isParamIndexValid());
760     return ParamIndex;
761   }
762 
setParamIndex(unsigned Index)763   void setParamIndex(unsigned Index) {
764     ParamIndex = Index;
765     assert(isParamIndexValid());
766   }
767 };
768 
769 /// Doxygen \\tparam command, describes a template parameter.
770 class TParamCommandComment : public BlockCommandComment {
771 private:
772   /// If this template parameter name was resolved (found in template parameter
773   /// list), then this stores a list of position indexes in all template
774   /// parameter lists.
775   ///
776   /// For example:
777   /// \verbatim
778   ///     template<typename C, template<typename T> class TT>
779   ///     void test(TT<int> aaa);
780   /// \endverbatim
781   /// For C:  Position = { 0 }
782   /// For TT: Position = { 1 }
783   /// For T:  Position = { 1, 0 }
784   ArrayRef<unsigned> Position;
785 
786 public:
TParamCommandComment(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID,CommandMarkerKind CommandMarker)787   TParamCommandComment(SourceLocation LocBegin,
788                        SourceLocation LocEnd,
789                        unsigned CommandID,
790                        CommandMarkerKind CommandMarker) :
791       BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID,
792                           CommandMarker)
793   { }
794 
classof(const Comment * C)795   static bool classof(const Comment *C) {
796     return C->getCommentKind() == TParamCommandCommentKind;
797   }
798 
hasParamName()799   bool hasParamName() const {
800     return getNumArgs() > 0;
801   }
802 
803   StringRef getParamName(const FullComment *FC) const;
804 
getParamNameAsWritten()805   StringRef getParamNameAsWritten() const {
806     return Args[0].Text;
807   }
808 
getParamNameRange()809   SourceRange getParamNameRange() const {
810     return Args[0].Range;
811   }
812 
isPositionValid()813   bool isPositionValid() const LLVM_READONLY {
814     return !Position.empty();
815   }
816 
getDepth()817   unsigned getDepth() const {
818     assert(isPositionValid());
819     return Position.size();
820   }
821 
getIndex(unsigned Depth)822   unsigned getIndex(unsigned Depth) const {
823     assert(isPositionValid());
824     return Position[Depth];
825   }
826 
setPosition(ArrayRef<unsigned> NewPosition)827   void setPosition(ArrayRef<unsigned> NewPosition) {
828     Position = NewPosition;
829     assert(isPositionValid());
830   }
831 };
832 
833 /// A line of text contained in a verbatim block.
834 class VerbatimBlockLineComment : public Comment {
835   StringRef Text;
836 
837 public:
VerbatimBlockLineComment(SourceLocation LocBegin,StringRef Text)838   VerbatimBlockLineComment(SourceLocation LocBegin,
839                            StringRef Text) :
840       Comment(VerbatimBlockLineCommentKind,
841               LocBegin,
842               LocBegin.getLocWithOffset(Text.size())),
843       Text(Text)
844   { }
845 
classof(const Comment * C)846   static bool classof(const Comment *C) {
847     return C->getCommentKind() == VerbatimBlockLineCommentKind;
848   }
849 
child_begin()850   child_iterator child_begin() const { return NULL; }
851 
child_end()852   child_iterator child_end() const { return NULL; }
853 
getText()854   StringRef getText() const LLVM_READONLY {
855     return Text;
856   }
857 };
858 
859 /// A verbatim block command (e. g., preformatted code).  Verbatim block has an
860 /// opening and a closing command and contains multiple lines of text
861 /// (VerbatimBlockLineComment nodes).
862 class VerbatimBlockComment : public BlockCommandComment {
863 protected:
864   StringRef CloseName;
865   SourceLocation CloseNameLocBegin;
866   ArrayRef<VerbatimBlockLineComment *> Lines;
867 
868 public:
VerbatimBlockComment(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID)869   VerbatimBlockComment(SourceLocation LocBegin,
870                        SourceLocation LocEnd,
871                        unsigned CommandID) :
872       BlockCommandComment(VerbatimBlockCommentKind,
873                           LocBegin, LocEnd, CommandID,
874                           CMK_At) // FIXME: improve source fidelity.
875   { }
876 
classof(const Comment * C)877   static bool classof(const Comment *C) {
878     return C->getCommentKind() == VerbatimBlockCommentKind;
879   }
880 
child_begin()881   child_iterator child_begin() const {
882     return reinterpret_cast<child_iterator>(Lines.begin());
883   }
884 
child_end()885   child_iterator child_end() const {
886     return reinterpret_cast<child_iterator>(Lines.end());
887   }
888 
setCloseName(StringRef Name,SourceLocation LocBegin)889   void setCloseName(StringRef Name, SourceLocation LocBegin) {
890     CloseName = Name;
891     CloseNameLocBegin = LocBegin;
892   }
893 
setLines(ArrayRef<VerbatimBlockLineComment * > L)894   void setLines(ArrayRef<VerbatimBlockLineComment *> L) {
895     Lines = L;
896   }
897 
getCloseName()898   StringRef getCloseName() const {
899     return CloseName;
900   }
901 
getNumLines()902   unsigned getNumLines() const {
903     return Lines.size();
904   }
905 
getText(unsigned LineIdx)906   StringRef getText(unsigned LineIdx) const {
907     return Lines[LineIdx]->getText();
908   }
909 };
910 
911 /// A verbatim line command.  Verbatim line has an opening command, a single
912 /// line of text (up to the newline after the opening command) and has no
913 /// closing command.
914 class VerbatimLineComment : public BlockCommandComment {
915 protected:
916   StringRef Text;
917   SourceLocation TextBegin;
918 
919 public:
VerbatimLineComment(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID,SourceLocation TextBegin,StringRef Text)920   VerbatimLineComment(SourceLocation LocBegin,
921                       SourceLocation LocEnd,
922                       unsigned CommandID,
923                       SourceLocation TextBegin,
924                       StringRef Text) :
925       BlockCommandComment(VerbatimLineCommentKind,
926                           LocBegin, LocEnd,
927                           CommandID,
928                           CMK_At), // FIXME: improve source fidelity.
929       Text(Text),
930       TextBegin(TextBegin)
931   { }
932 
classof(const Comment * C)933   static bool classof(const Comment *C) {
934     return C->getCommentKind() == VerbatimLineCommentKind;
935   }
936 
child_begin()937   child_iterator child_begin() const { return NULL; }
938 
child_end()939   child_iterator child_end() const { return NULL; }
940 
getText()941   StringRef getText() const {
942     return Text;
943   }
944 
getTextRange()945   SourceRange getTextRange() const {
946     return SourceRange(TextBegin, getLocEnd());
947   }
948 };
949 
950 /// Information about the declaration, useful to clients of FullComment.
951 struct DeclInfo {
952   /// Declaration the comment is actually attached to (in the source).
953   /// Should not be NULL.
954   const Decl *CommentDecl;
955 
956   /// CurrentDecl is the declaration with which the FullComment is associated.
957   ///
958   /// It can be different from \c CommentDecl.  It happens when we we decide
959   /// that the comment originally attached to \c CommentDecl is fine for
960   /// \c CurrentDecl too (for example, for a redeclaration or an overrider of
961   /// \c CommentDecl).
962   ///
963   /// The information in the DeclInfo corresponds to CurrentDecl.
964   const Decl *CurrentDecl;
965 
966   /// Parameters that can be referenced by \\param if \c CommentDecl is something
967   /// that we consider a "function".
968   ArrayRef<const ParmVarDecl *> ParamVars;
969 
970   /// Function result type if \c CommentDecl is something that we consider
971   /// a "function".
972   QualType ResultType;
973 
974   /// Template parameters that can be referenced by \\tparam if \c CommentDecl is
975   /// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is
976   /// true).
977   const TemplateParameterList *TemplateParameters;
978 
979   /// A simplified description of \c CommentDecl kind that should be good enough
980   /// for documentation rendering purposes.
981   enum DeclKind {
982     /// Everything else not explicitly mentioned below.
983     OtherKind,
984 
985     /// Something that we consider a "function":
986     /// \li function,
987     /// \li function template,
988     /// \li function template specialization,
989     /// \li member function,
990     /// \li member function template,
991     /// \li member function template specialization,
992     /// \li ObjC method,
993     /// \li a typedef for a function pointer, member function pointer,
994     ///     ObjC block.
995     FunctionKind,
996 
997     /// Something that we consider a "class":
998     /// \li class/struct,
999     /// \li class template,
1000     /// \li class template (partial) specialization.
1001     ClassKind,
1002 
1003     /// Something that we consider a "variable":
1004     /// \li namespace scope variables;
1005     /// \li static and non-static class data members;
1006     /// \li enumerators.
1007     VariableKind,
1008 
1009     /// A C++ namespace.
1010     NamespaceKind,
1011 
1012     /// A C++ typedef-name (a 'typedef' decl specifier or alias-declaration),
1013     /// see \c TypedefNameDecl.
1014     TypedefKind,
1015 
1016     /// An enumeration or scoped enumeration.
1017     EnumKind
1018   };
1019 
1020   /// What kind of template specialization \c CommentDecl is.
1021   enum TemplateDeclKind {
1022     NotTemplate,
1023     Template,
1024     TemplateSpecialization,
1025     TemplatePartialSpecialization
1026   };
1027 
1028   /// If false, only \c CommentDecl is valid.
1029   unsigned IsFilled : 1;
1030 
1031   /// Simplified kind of \c CommentDecl, see \c DeclKind enum.
1032   unsigned Kind : 3;
1033 
1034   /// Is \c CommentDecl a template declaration.
1035   unsigned TemplateKind : 2;
1036 
1037   /// Is \c CommentDecl an ObjCMethodDecl.
1038   unsigned IsObjCMethod : 1;
1039 
1040   /// Is \c CommentDecl a non-static member function of C++ class or
1041   /// instance method of ObjC class.
1042   /// Can be true only if \c IsFunctionDecl is true.
1043   unsigned IsInstanceMethod : 1;
1044 
1045   /// Is \c CommentDecl a static member function of C++ class or
1046   /// class method of ObjC class.
1047   /// Can be true only if \c IsFunctionDecl is true.
1048   unsigned IsClassMethod : 1;
1049 
1050   void fill();
1051 
getKindDeclInfo1052   DeclKind getKind() const LLVM_READONLY {
1053     return static_cast<DeclKind>(Kind);
1054   }
1055 
getTemplateKindDeclInfo1056   TemplateDeclKind getTemplateKind() const LLVM_READONLY {
1057     return static_cast<TemplateDeclKind>(TemplateKind);
1058   }
1059 };
1060 
1061 /// A full comment attached to a declaration, contains block content.
1062 class FullComment : public Comment {
1063   ArrayRef<BlockContentComment *> Blocks;
1064   DeclInfo *ThisDeclInfo;
1065 
1066 public:
FullComment(ArrayRef<BlockContentComment * > Blocks,DeclInfo * D)1067   FullComment(ArrayRef<BlockContentComment *> Blocks, DeclInfo *D) :
1068       Comment(FullCommentKind, SourceLocation(), SourceLocation()),
1069       Blocks(Blocks), ThisDeclInfo(D) {
1070     if (Blocks.empty())
1071       return;
1072 
1073     setSourceRange(SourceRange(Blocks.front()->getLocStart(),
1074                                Blocks.back()->getLocEnd()));
1075     setLocation(Blocks.front()->getLocStart());
1076   }
1077 
classof(const Comment * C)1078   static bool classof(const Comment *C) {
1079     return C->getCommentKind() == FullCommentKind;
1080   }
1081 
child_begin()1082   child_iterator child_begin() const {
1083     return reinterpret_cast<child_iterator>(Blocks.begin());
1084   }
1085 
child_end()1086   child_iterator child_end() const {
1087     return reinterpret_cast<child_iterator>(Blocks.end());
1088   }
1089 
getDecl()1090   const Decl *getDecl() const LLVM_READONLY {
1091     return ThisDeclInfo->CommentDecl;
1092   }
1093 
getDeclInfo()1094   const DeclInfo *getDeclInfo() const LLVM_READONLY {
1095     if (!ThisDeclInfo->IsFilled)
1096       ThisDeclInfo->fill();
1097     return ThisDeclInfo;
1098   }
1099 
getThisDeclInfo()1100   DeclInfo *getThisDeclInfo() const LLVM_READONLY {
1101     return ThisDeclInfo;
1102   }
1103 
getBlocks()1104   ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
1105 
1106 };
1107 } // end namespace comments
1108 } // end namespace clang
1109 
1110 #endif
1111 
1112