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