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