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 |
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 | = 0, |
42 | |
43 | /// Command started with an 'at' character: |
44 | /// \code |
45 | /// @foo |
46 | /// \endcode |
47 | = 1 |
48 | }; |
49 | |
50 | /// Any part of the comment. |
51 | /// Abstract class. |
52 | class { |
53 | protected: |
54 | /// Preferred location to show caret. |
55 | SourceLocation ; |
56 | |
57 | /// Source range of this AST node. |
58 | SourceRange ; |
59 | |
60 | class { |
61 | friend class Comment; |
62 | |
63 | /// Type of this AST node. |
64 | unsigned : 8; |
65 | }; |
66 | enum { = 8 }; |
67 | |
68 | class { |
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 : 1; |
76 | }; |
77 | enum { = NumCommentBits + 1 }; |
78 | |
79 | class { |
80 | friend class TextComment; |
81 | |
82 | unsigned : NumInlineContentCommentBits; |
83 | |
84 | /// True if \c IsWhitespace field contains a valid value. |
85 | mutable unsigned : 1; |
86 | |
87 | /// True if this comment AST node contains only whitespace. |
88 | mutable unsigned : 1; |
89 | }; |
90 | enum { = 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 { |
105 | friend class HTMLTagComment; |
106 | |
107 | unsigned : NumInlineContentCommentBits; |
108 | |
109 | /// True if we found that this tag is malformed in some way. |
110 | unsigned : 1; |
111 | }; |
112 | enum { = NumInlineContentCommentBits + 1 }; |
113 | |
114 | class { |
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 : 1; |
122 | }; |
123 | enum { = NumHTMLTagCommentBits + 1 }; |
124 | |
125 | class { |
126 | friend class ParagraphComment; |
127 | |
128 | unsigned : NumCommentBits; |
129 | |
130 | /// True if \c IsWhitespace field contains a valid value. |
131 | mutable unsigned : 1; |
132 | |
133 | /// True if this comment AST node contains only whitespace. |
134 | mutable unsigned : 1; |
135 | }; |
136 | enum { = 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 ; |
167 | InlineContentCommentBitfields ; |
168 | TextCommentBitfields ; |
169 | InlineCommandCommentBitfields InlineCommandCommentBits; |
170 | HTMLTagCommentBitfields ; |
171 | HTMLStartTagCommentBitfields ; |
172 | ParagraphCommentBitfields ; |
173 | BlockCommandCommentBitfields BlockCommandCommentBits; |
174 | ParamCommandCommentBitfields ParamCommandCommentBits; |
175 | }; |
176 | |
177 | void (SourceRange SR) { |
178 | Range = SR; |
179 | } |
180 | |
181 | void (SourceLocation L) { |
182 | Loc = L; |
183 | } |
184 | |
185 | public: |
186 | enum { |
187 | = 0, |
188 | #define (CLASS, PARENT) CLASS##Kind, |
189 | #define (BASE, FIRST, LAST) \ |
190 | First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind, |
191 | #define (BASE, FIRST, LAST) \ |
192 | First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind |
193 | #define (COMMENT) |
194 | #include "clang/AST/CommentNodes.inc" |
195 | }; |
196 | |
197 | (CommentKind K, |
198 | SourceLocation LocBegin, |
199 | SourceLocation LocEnd) : |
200 | Loc(LocBegin), Range(SourceRange(LocBegin, LocEnd)) { |
201 | CommentBits.Kind = K; |
202 | } |
203 | |
204 | CommentKind () const { |
205 | return static_cast<CommentKind>(CommentBits.Kind); |
206 | } |
207 | |
208 | const char *() const; |
209 | |
210 | void () const; |
211 | void () const; |
212 | void (raw_ostream &OS, const ASTContext &Context) const; |
213 | |
214 | SourceRange () const LLVM_READONLY { return Range; } |
215 | |
216 | SourceLocation () const LLVM_READONLY { return Range.getBegin(); } |
217 | |
218 | SourceLocation () const LLVM_READONLY { return Range.getEnd(); } |
219 | |
220 | SourceLocation () const LLVM_READONLY { return Loc; } |
221 | |
222 | typedef Comment * const *; |
223 | |
224 | child_iterator () const; |
225 | child_iterator () const; |
226 | |
227 | // TODO: const child iterator |
228 | |
229 | unsigned () const { |
230 | return child_end() - child_begin(); |
231 | } |
232 | }; |
233 | |
234 | /// Inline content (contained within a block). |
235 | /// Abstract class. |
236 | class : public Comment { |
237 | protected: |
238 | (CommentKind K, |
239 | SourceLocation LocBegin, |
240 | SourceLocation LocEnd) : |
241 | Comment(K, LocBegin, LocEnd) { |
242 | InlineContentCommentBits.HasTrailingNewline = 0; |
243 | } |
244 | |
245 | public: |
246 | static bool (const Comment *C) { |
247 | return C->getCommentKind() >= FirstInlineContentCommentConstant && |
248 | C->getCommentKind() <= LastInlineContentCommentConstant; |
249 | } |
250 | |
251 | void () { |
252 | InlineContentCommentBits.HasTrailingNewline = 1; |
253 | } |
254 | |
255 | bool () const { |
256 | return InlineContentCommentBits.HasTrailingNewline; |
257 | } |
258 | }; |
259 | |
260 | /// Plain text. |
261 | class : public InlineContentComment { |
262 | StringRef ; |
263 | |
264 | public: |
265 | (SourceLocation LocBegin, |
266 | SourceLocation LocEnd, |
267 | StringRef Text) : |
268 | InlineContentComment(TextCommentKind, LocBegin, LocEnd), |
269 | Text(Text) { |
270 | TextCommentBits.IsWhitespaceValid = false; |
271 | } |
272 | |
273 | static bool (const Comment *C) { |
274 | return C->getCommentKind() == TextCommentKind; |
275 | } |
276 | |
277 | child_iterator () const { return nullptr; } |
278 | |
279 | child_iterator () const { return nullptr; } |
280 | |
281 | StringRef () const LLVM_READONLY { return Text; } |
282 | |
283 | bool () 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 () 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 | |
303 | 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: |
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 | |
332 | static bool classof(const Comment *C) { |
333 | return C->getCommentKind() == InlineCommandCommentKind; |
334 | } |
335 | |
336 | child_iterator child_begin() const { return nullptr; } |
337 | |
338 | child_iterator child_end() const { return nullptr; } |
339 | |
340 | unsigned getCommandID() const { |
341 | return InlineCommandCommentBits.CommandID; |
342 | } |
343 | |
344 | StringRef getCommandName(const CommandTraits &Traits) const { |
345 | return Traits.getCommandInfo(getCommandID())->Name; |
346 | } |
347 | |
348 | SourceRange getCommandNameRange() const { |
349 | return SourceRange(getBeginLoc().getLocWithOffset(-1), getEndLoc()); |
350 | } |
351 | |
352 | RenderKind getRenderKind() const { |
353 | return static_cast<RenderKind>(InlineCommandCommentBits.RenderKind); |
354 | } |
355 | |
356 | unsigned getNumArgs() const { |
357 | return Args.size(); |
358 | } |
359 | |
360 | StringRef getArgText(unsigned Idx) const { |
361 | return Args[Idx].Text; |
362 | } |
363 | |
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 : public InlineContentComment { |
372 | protected: |
373 | StringRef ; |
374 | SourceRange ; |
375 | |
376 | (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: |
390 | static bool (const Comment *C) { |
391 | return C->getCommentKind() >= FirstHTMLTagCommentConstant && |
392 | C->getCommentKind() <= LastHTMLTagCommentConstant; |
393 | } |
394 | |
395 | StringRef () const LLVM_READONLY { return TagName; } |
396 | |
397 | SourceRange () const LLVM_READONLY { |
398 | SourceLocation L = getLocation(); |
399 | return SourceRange(L.getLocWithOffset(1), |
400 | L.getLocWithOffset(1 + TagName.size())); |
401 | } |
402 | |
403 | bool () const { |
404 | return HTMLTagCommentBits.IsMalformed; |
405 | } |
406 | |
407 | void () { |
408 | HTMLTagCommentBits.IsMalformed = 1; |
409 | } |
410 | }; |
411 | |
412 | /// An opening HTML tag with attributes. |
413 | class : public HTMLTagComment { |
414 | public: |
415 | class { |
416 | public: |
417 | SourceLocation ; |
418 | StringRef ; |
419 | |
420 | SourceLocation ; |
421 | |
422 | SourceRange ; |
423 | StringRef ; |
424 | |
425 | () { } |
426 | |
427 | (SourceLocation NameLocBegin, StringRef Name) : |
428 | NameLocBegin(NameLocBegin), Name(Name), |
429 | EqualsLoc(SourceLocation()), |
430 | ValueRange(SourceRange()), Value(StringRef()) |
431 | { } |
432 | |
433 | (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 | |
441 | SourceLocation () const { |
442 | return NameLocBegin.getLocWithOffset(Name.size()); |
443 | } |
444 | |
445 | SourceRange () const { |
446 | return SourceRange(NameLocBegin, getNameLocEnd()); |
447 | } |
448 | }; |
449 | |
450 | private: |
451 | ArrayRef<Attribute> ; |
452 | |
453 | public: |
454 | (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 | |
464 | static bool (const Comment *C) { |
465 | return C->getCommentKind() == HTMLStartTagCommentKind; |
466 | } |
467 | |
468 | child_iterator () const { return nullptr; } |
469 | |
470 | child_iterator () const { return nullptr; } |
471 | |
472 | unsigned () const { |
473 | return Attributes.size(); |
474 | } |
475 | |
476 | const Attribute &(unsigned Idx) const { |
477 | return Attributes[Idx]; |
478 | } |
479 | |
480 | void (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 | |
493 | void (SourceLocation GreaterLoc) { |
494 | Range.setEnd(GreaterLoc); |
495 | } |
496 | |
497 | bool () const { |
498 | return HTMLStartTagCommentBits.IsSelfClosing; |
499 | } |
500 | |
501 | void () { |
502 | HTMLStartTagCommentBits.IsSelfClosing = true; |
503 | } |
504 | }; |
505 | |
506 | /// A closing HTML tag. |
507 | class : public HTMLTagComment { |
508 | public: |
509 | (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 | |
519 | static bool (const Comment *C) { |
520 | return C->getCommentKind() == HTMLEndTagCommentKind; |
521 | } |
522 | |
523 | child_iterator () const { return nullptr; } |
524 | |
525 | child_iterator () const { return nullptr; } |
526 | }; |
527 | |
528 | /// Block content (contains inline content). |
529 | /// Abstract class. |
530 | class : public Comment { |
531 | protected: |
532 | (CommentKind K, |
533 | SourceLocation LocBegin, |
534 | SourceLocation LocEnd) : |
535 | Comment(K, LocBegin, LocEnd) |
536 | { } |
537 | |
538 | public: |
539 | static bool (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 : public BlockContentComment { |
547 | ArrayRef<InlineContentComment *> ; |
548 | |
549 | public: |
550 | (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 | |
568 | static bool (const Comment *C) { |
569 | return C->getCommentKind() == ParagraphCommentKind; |
570 | } |
571 | |
572 | child_iterator () const { |
573 | return reinterpret_cast<child_iterator>(Content.begin()); |
574 | } |
575 | |
576 | child_iterator () const { |
577 | return reinterpret_cast<child_iterator>(Content.end()); |
578 | } |
579 | |
580 | bool () 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 () 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 | |
602 | Argument() { } |
603 | 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 | |
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: |
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 | |
637 | static bool classof(const Comment *C) { |
638 | return C->getCommentKind() >= FirstBlockCommandCommentConstant && |
639 | C->getCommentKind() <= LastBlockCommandCommentConstant; |
640 | } |
641 | |
642 | child_iterator child_begin() const { |
643 | return reinterpret_cast<child_iterator>(&Paragraph); |
644 | } |
645 | |
646 | child_iterator child_end() const { |
647 | return reinterpret_cast<child_iterator>(&Paragraph + 1); |
648 | } |
649 | |
650 | unsigned getCommandID() const { |
651 | return BlockCommandCommentBits.CommandID; |
652 | } |
653 | |
654 | StringRef getCommandName(const CommandTraits &Traits) const { |
655 | return Traits.getCommandInfo(getCommandID())->Name; |
656 | } |
657 | |
658 | SourceLocation getCommandNameBeginLoc() const { |
659 | return getBeginLoc().getLocWithOffset(1); |
660 | } |
661 | |
662 | SourceRange getCommandNameRange(const CommandTraits &Traits) const { |
663 | StringRef Name = getCommandName(Traits); |
664 | return SourceRange(getCommandNameBeginLoc(), |
665 | getBeginLoc().getLocWithOffset(1 + Name.size())); |
666 | } |
667 | |
668 | unsigned getNumArgs() const { |
669 | return Args.size(); |
670 | } |
671 | |
672 | StringRef getArgText(unsigned Idx) const { |
673 | return Args[Idx].Text; |
674 | } |
675 | |
676 | SourceRange getArgRange(unsigned Idx) const { |
677 | return Args[Idx].Range; |
678 | } |
679 | |
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 | |
689 | ParagraphComment *getParagraph() const LLVM_READONLY { |
690 | return Paragraph; |
691 | } |
692 | |
693 | bool hasNonWhitespaceParagraph() const { |
694 | return Paragraph && !Paragraph->isWhitespace(); |
695 | } |
696 | |
697 | void setParagraph(ParagraphComment *PC) { |
698 | Paragraph = PC; |
699 | SourceLocation NewLocEnd = PC->getEndLoc(); |
700 | if (NewLocEnd.isValid()) |
701 | setSourceRange(SourceRange(getBeginLoc(), NewLocEnd)); |
702 | } |
703 | |
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 | |
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 | |
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 | |
745 | PassDirection getDirection() const LLVM_READONLY { |
746 | return static_cast<PassDirection>(ParamCommandCommentBits.Direction); |
747 | } |
748 | |
749 | bool isDirectionExplicit() const LLVM_READONLY { |
750 | return ParamCommandCommentBits.IsDirectionExplicit; |
751 | } |
752 | |
753 | void setDirection(PassDirection Direction, bool Explicit) { |
754 | ParamCommandCommentBits.Direction = Direction; |
755 | ParamCommandCommentBits.IsDirectionExplicit = Explicit; |
756 | } |
757 | |
758 | bool hasParamName() const { |
759 | return getNumArgs() > 0; |
760 | } |
761 | |
762 | StringRef getParamName(const FullComment *FC) const; |
763 | |
764 | StringRef getParamNameAsWritten() const { |
765 | return Args[0].Text; |
766 | } |
767 | |
768 | SourceRange getParamNameRange() const { |
769 | return Args[0].Range; |
770 | } |
771 | |
772 | bool isParamIndexValid() const LLVM_READONLY { |
773 | return ParamIndex != InvalidParamIndex; |
774 | } |
775 | |
776 | bool isVarArgParam() const LLVM_READONLY { |
777 | return ParamIndex == VarArgParamIndex; |
778 | } |
779 | |
780 | void setIsVarArgParam() { |
781 | ParamIndex = VarArgParamIndex; |
782 | assert(isParamIndexValid()); |
783 | } |
784 | |
785 | unsigned getParamIndex() const LLVM_READONLY { |
786 | assert(isParamIndexValid()); |
787 | assert(!isVarArgParam()); |
788 | return ParamIndex; |
789 | } |
790 | |
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: |
816 | TParamCommandComment(SourceLocation LocBegin, |
817 | SourceLocation LocEnd, |
818 | unsigned CommandID, |
819 | CommandMarkerKind CommandMarker) : |
820 | BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID, |
821 | CommandMarker) |
822 | { } |
823 | |
824 | static bool classof(const Comment *C) { |
825 | return C->getCommentKind() == TParamCommandCommentKind; |
826 | } |
827 | |
828 | bool hasParamName() const { |
829 | return getNumArgs() > 0; |
830 | } |
831 | |
832 | StringRef getParamName(const FullComment *FC) const; |
833 | |
834 | StringRef getParamNameAsWritten() const { |
835 | return Args[0].Text; |
836 | } |
837 | |
838 | SourceRange getParamNameRange() const { |
839 | return Args[0].Range; |
840 | } |
841 | |
842 | bool isPositionValid() const LLVM_READONLY { |
843 | return !Position.empty(); |
844 | } |
845 | |
846 | unsigned getDepth() const { |
847 | assert(isPositionValid()); |
848 | return Position.size(); |
849 | } |
850 | |
851 | unsigned getIndex(unsigned Depth) const { |
852 | assert(isPositionValid()); |
853 | return Position[Depth]; |
854 | } |
855 | |
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 : public Comment { |
864 | StringRef ; |
865 | |
866 | public: |
867 | (SourceLocation LocBegin, |
868 | StringRef Text) : |
869 | Comment(VerbatimBlockLineCommentKind, |
870 | LocBegin, |
871 | LocBegin.getLocWithOffset(Text.size())), |
872 | Text(Text) |
873 | { } |
874 | |
875 | static bool (const Comment *C) { |
876 | return C->getCommentKind() == VerbatimBlockLineCommentKind; |
877 | } |
878 | |
879 | child_iterator () const { return nullptr; } |
880 | |
881 | child_iterator () const { return nullptr; } |
882 | |
883 | StringRef () 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 : public BlockCommandComment { |
892 | protected: |
893 | StringRef ; |
894 | SourceLocation ; |
895 | ArrayRef<VerbatimBlockLineComment *> ; |
896 | |
897 | public: |
898 | (SourceLocation LocBegin, |
899 | SourceLocation LocEnd, |
900 | unsigned CommandID) : |
901 | BlockCommandComment(VerbatimBlockCommentKind, |
902 | LocBegin, LocEnd, CommandID, |
903 | CMK_At) // FIXME: improve source fidelity. |
904 | { } |
905 | |
906 | static bool (const Comment *C) { |
907 | return C->getCommentKind() == VerbatimBlockCommentKind; |
908 | } |
909 | |
910 | child_iterator () const { |
911 | return reinterpret_cast<child_iterator>(Lines.begin()); |
912 | } |
913 | |
914 | child_iterator () const { |
915 | return reinterpret_cast<child_iterator>(Lines.end()); |
916 | } |
917 | |
918 | void (StringRef Name, SourceLocation LocBegin) { |
919 | CloseName = Name; |
920 | CloseNameLocBegin = LocBegin; |
921 | } |
922 | |
923 | void (ArrayRef<VerbatimBlockLineComment *> L) { |
924 | Lines = L; |
925 | } |
926 | |
927 | StringRef () const { |
928 | return CloseName; |
929 | } |
930 | |
931 | unsigned () const { |
932 | return Lines.size(); |
933 | } |
934 | |
935 | StringRef (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 : public BlockCommandComment { |
944 | protected: |
945 | StringRef ; |
946 | SourceLocation ; |
947 | |
948 | public: |
949 | (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 | |
962 | static bool (const Comment *C) { |
963 | return C->getCommentKind() == VerbatimLineCommentKind; |
964 | } |
965 | |
966 | child_iterator () const { return nullptr; } |
967 | |
968 | child_iterator () const { return nullptr; } |
969 | |
970 | StringRef () const { |
971 | return Text; |
972 | } |
973 | |
974 | SourceRange () const { |
975 | return SourceRange(TextBegin, getEndLoc()); |
976 | } |
977 | }; |
978 | |
979 | /// Information about the declaration, useful to clients of FullComment. |
980 | struct { |
981 | /// Declaration the comment is actually attached to (in the source). |
982 | /// Should not be NULL. |
983 | const Decl *; |
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 *; |
994 | |
995 | /// Parameters that can be referenced by \\param if \c CommentDecl is something |
996 | /// that we consider a "function". |
997 | ArrayRef<const ParmVarDecl *> ; |
998 | |
999 | /// Function return type if \c CommentDecl is something that we consider |
1000 | /// a "function". |
1001 | QualType ; |
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 *; |
1007 | |
1008 | /// A simplified description of \c CommentDecl kind that should be good enough |
1009 | /// for documentation rendering purposes. |
1010 | enum { |
1011 | /// Everything else not explicitly mentioned below. |
1012 | , |
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 | , |
1025 | |
1026 | /// Something that we consider a "class": |
1027 | /// \li class/struct, |
1028 | /// \li class template, |
1029 | /// \li class template (partial) specialization. |
1030 | , |
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 | , |
1037 | |
1038 | /// A C++ namespace. |
1039 | , |
1040 | |
1041 | /// A C++ typedef-name (a 'typedef' decl specifier or alias-declaration), |
1042 | /// see \c TypedefNameDecl. |
1043 | , |
1044 | |
1045 | /// An enumeration or scoped enumeration. |
1046 | |
1047 | }; |
1048 | |
1049 | /// What kind of template specialization \c CommentDecl is. |
1050 | enum { |
1051 | , |
1052 | , |
1053 | , |
1054 | |
1055 | }; |
1056 | |
1057 | /// If false, only \c CommentDecl is valid. |
1058 | unsigned : 1; |
1059 | |
1060 | /// Simplified kind of \c CommentDecl, see \c DeclKind enum. |
1061 | unsigned : 3; |
1062 | |
1063 | /// Is \c CommentDecl a template declaration. |
1064 | unsigned : 2; |
1065 | |
1066 | /// Is \c CommentDecl an ObjCMethodDecl. |
1067 | unsigned : 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 : 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 : 1; |
1078 | |
1079 | void (); |
1080 | |
1081 | DeclKind () const LLVM_READONLY { |
1082 | return static_cast<DeclKind>(Kind); |
1083 | } |
1084 | |
1085 | TemplateDeclKind () 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 : public Comment { |
1092 | ArrayRef<BlockContentComment *> ; |
1093 | DeclInfo *; |
1094 | |
1095 | public: |
1096 | (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 | |
1107 | static bool (const Comment *C) { |
1108 | return C->getCommentKind() == FullCommentKind; |
1109 | } |
1110 | |
1111 | child_iterator () const { |
1112 | return reinterpret_cast<child_iterator>(Blocks.begin()); |
1113 | } |
1114 | |
1115 | child_iterator () const { |
1116 | return reinterpret_cast<child_iterator>(Blocks.end()); |
1117 | } |
1118 | |
1119 | const Decl *() const LLVM_READONLY { |
1120 | return ThisDeclInfo->CommentDecl; |
1121 | } |
1122 | |
1123 | const DeclInfo *() const LLVM_READONLY { |
1124 | if (!ThisDeclInfo->IsFilled) |
1125 | ThisDeclInfo->fill(); |
1126 | return ThisDeclInfo; |
1127 | } |
1128 | |
1129 | ArrayRef<BlockContentComment *> () const { return Blocks; } |
1130 | |
1131 | }; |
1132 | } // end namespace comments |
1133 | } // end namespace clang |
1134 | |
1135 | #endif |
1136 | |
1137 | |