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