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