/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/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 : 2; |
98 | | unsigned CommandID : CommandInfo::NumCommandIDBits; |
99 | | }; |
100 | | enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 2 + |
101 | | CommandInfo::NumCommandIDBits }; |
102 | | |
103 | | class HTMLTagCommentBitfields { |
104 | | friend class HTMLTagComment; |
105 | | |
106 | | unsigned : NumInlineContentCommentBits; |
107 | | |
108 | | /// True if we found that this tag is malformed in some way. |
109 | | unsigned IsMalformed : 1; |
110 | | }; |
111 | | enum { NumHTMLTagCommentBits = NumInlineContentCommentBits + 1 }; |
112 | | |
113 | | class HTMLStartTagCommentBitfields { |
114 | | friend class HTMLStartTagComment; |
115 | | |
116 | | unsigned : NumHTMLTagCommentBits; |
117 | | |
118 | | /// True if this tag is self-closing (e. g., <br />). This is based on tag |
119 | | /// spelling in comment (plain <br> would not set this flag). |
120 | | unsigned IsSelfClosing : 1; |
121 | | }; |
122 | | enum { NumHTMLStartTagCommentBits = NumHTMLTagCommentBits + 1 }; |
123 | | |
124 | | class ParagraphCommentBitfields { |
125 | | friend class ParagraphComment; |
126 | | |
127 | | unsigned : NumCommentBits; |
128 | | |
129 | | /// True if \c IsWhitespace field contains a valid value. |
130 | | mutable unsigned IsWhitespaceValid : 1; |
131 | | |
132 | | /// True if this comment AST node contains only whitespace. |
133 | | mutable unsigned IsWhitespace : 1; |
134 | | }; |
135 | | enum { NumParagraphCommentBits = NumCommentBits + 2 }; |
136 | | |
137 | | class BlockCommandCommentBitfields { |
138 | | friend class BlockCommandComment; |
139 | | |
140 | | unsigned : NumCommentBits; |
141 | | |
142 | | unsigned CommandID : CommandInfo::NumCommandIDBits; |
143 | | |
144 | | /// Describes the syntax that was used in a documentation command. |
145 | | /// Contains values from CommandMarkerKind enum. |
146 | | unsigned CommandMarker : 1; |
147 | | }; |
148 | | enum { NumBlockCommandCommentBits = NumCommentBits + |
149 | | CommandInfo::NumCommandIDBits + 1 }; |
150 | | |
151 | | class ParamCommandCommentBitfields { |
152 | | friend class ParamCommandComment; |
153 | | |
154 | | unsigned : NumBlockCommandCommentBits; |
155 | | |
156 | | /// Parameter passing direction, see ParamCommandComment::PassDirection. |
157 | | unsigned Direction : 2; |
158 | | |
159 | | /// True if direction was specified explicitly in the comment. |
160 | | unsigned IsDirectionExplicit : 1; |
161 | | }; |
162 | | enum { NumParamCommandCommentBits = NumBlockCommandCommentBits + 3 }; |
163 | | |
164 | | union { |
165 | | CommentBitfields CommentBits; |
166 | | InlineContentCommentBitfields InlineContentCommentBits; |
167 | | TextCommentBitfields TextCommentBits; |
168 | | InlineCommandCommentBitfields InlineCommandCommentBits; |
169 | | HTMLTagCommentBitfields HTMLTagCommentBits; |
170 | | HTMLStartTagCommentBitfields HTMLStartTagCommentBits; |
171 | | ParagraphCommentBitfields ParagraphCommentBits; |
172 | | BlockCommandCommentBitfields BlockCommandCommentBits; |
173 | | ParamCommandCommentBitfields ParamCommandCommentBits; |
174 | | }; |
175 | | |
176 | 5.37k | void setSourceRange(SourceRange SR) { |
177 | 5.37k | Range = SR; |
178 | 5.37k | } |
179 | | |
180 | 5.30k | void setLocation(SourceLocation L) { |
181 | 5.30k | Loc = L; |
182 | 5.30k | } |
183 | | |
184 | | public: |
185 | | enum CommentKind { |
186 | | NoCommentKind = 0, |
187 | | #define COMMENT(CLASS, PARENT) CLASS##Kind, |
188 | | #define COMMENT_RANGE(BASE, FIRST, LAST) \ |
189 | | First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind, |
190 | | #define LAST_COMMENT_RANGE(BASE, FIRST, LAST) \ |
191 | | First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind |
192 | | #define ABSTRACT_COMMENT(COMMENT) |
193 | | #include "clang/AST/CommentNodes.inc" |
194 | | }; |
195 | | |
196 | | Comment(CommentKind K, |
197 | | SourceLocation LocBegin, |
198 | | SourceLocation LocEnd) : |
199 | 8.79k | Loc(LocBegin), Range(SourceRange(LocBegin, LocEnd)) { |
200 | 8.79k | CommentBits.Kind = K; |
201 | 8.79k | } |
202 | | |
203 | 74.4k | CommentKind getCommentKind() const { |
204 | 74.4k | return static_cast<CommentKind>(CommentBits.Kind); |
205 | 74.4k | } |
206 | | |
207 | | const char *getCommentKindName() const; |
208 | | |
209 | | void dump() const; |
210 | | void dumpColor() const; |
211 | | void dump(const ASTContext &Context) const; |
212 | | void dump(raw_ostream &OS, const CommandTraits *Traits, |
213 | | const SourceManager *SM) const; |
214 | | |
215 | 953 | SourceRange getSourceRange() const LLVM_READONLY { return Range; } |
216 | | |
217 | 10.9k | SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } |
218 | | |
219 | 5.05k | SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } |
220 | | |
221 | 351 | SourceLocation getLocation() const LLVM_READONLY { return Loc; } |
222 | | |
223 | | typedef Comment * const *child_iterator; |
224 | | |
225 | | child_iterator child_begin() const; |
226 | | child_iterator child_end() const; |
227 | | |
228 | | // TODO: const child iterator |
229 | | |
230 | | unsigned child_count() const { |
231 | | return child_end() - child_begin(); |
232 | | } |
233 | | }; |
234 | | |
235 | | /// Inline content (contained within a block). |
236 | | /// Abstract class. |
237 | | class InlineContentComment : public Comment { |
238 | | protected: |
239 | | InlineContentComment(CommentKind K, |
240 | | SourceLocation LocBegin, |
241 | | SourceLocation LocEnd) : |
242 | 3.39k | Comment(K, LocBegin, LocEnd) { |
243 | 3.39k | InlineContentCommentBits.HasTrailingNewline = 0; |
244 | 3.39k | } |
245 | | |
246 | | public: |
247 | | static bool classof(const Comment *C) { |
248 | | return C->getCommentKind() >= FirstInlineContentCommentConstant && |
249 | | C->getCommentKind() <= LastInlineContentCommentConstant; |
250 | | } |
251 | | |
252 | 556 | void addTrailingNewline() { |
253 | 556 | InlineContentCommentBits.HasTrailingNewline = 1; |
254 | 556 | } |
255 | | |
256 | | bool hasTrailingNewline() const { |
257 | | return InlineContentCommentBits.HasTrailingNewline; |
258 | | } |
259 | | }; |
260 | | |
261 | | /// Plain text. |
262 | | class TextComment : public InlineContentComment { |
263 | | StringRef Text; |
264 | | |
265 | | public: |
266 | | TextComment(SourceLocation LocBegin, |
267 | | SourceLocation LocEnd, |
268 | | StringRef Text) : |
269 | | InlineContentComment(TextCommentKind, LocBegin, LocEnd), |
270 | 3.07k | Text(Text) { |
271 | 3.07k | TextCommentBits.IsWhitespaceValid = false; |
272 | 3.07k | } |
273 | | |
274 | 8.47k | static bool classof(const Comment *C) { |
275 | 8.47k | return C->getCommentKind() == TextCommentKind; |
276 | 8.47k | } |
277 | | |
278 | 2.41k | child_iterator child_begin() const { return nullptr; } |
279 | | |
280 | 2.41k | child_iterator child_end() const { return nullptr; } |
281 | | |
282 | 5.86k | StringRef getText() const LLVM_READONLY { return Text; } |
283 | | |
284 | 4.21k | bool isWhitespace() const { |
285 | 4.21k | if (TextCommentBits.IsWhitespaceValid) |
286 | 1.80k | return TextCommentBits.IsWhitespace; |
287 | 2.41k | |
288 | 2.41k | TextCommentBits.IsWhitespace = isWhitespaceNoCache(); |
289 | 2.41k | TextCommentBits.IsWhitespaceValid = true; |
290 | 2.41k | return TextCommentBits.IsWhitespace; |
291 | 2.41k | } |
292 | | |
293 | | private: |
294 | | bool isWhitespaceNoCache() const; |
295 | | }; |
296 | | |
297 | | /// A command with word-like arguments that is considered inline content. |
298 | | class InlineCommandComment : public InlineContentComment { |
299 | | public: |
300 | | struct Argument { |
301 | | SourceRange Range; |
302 | | StringRef Text; |
303 | | |
304 | 28 | Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { } |
305 | | }; |
306 | | |
307 | | /// The most appropriate rendering mode for this command, chosen on command |
308 | | /// semantics in Doxygen. |
309 | | enum RenderKind { |
310 | | RenderNormal, |
311 | | RenderBold, |
312 | | RenderMonospaced, |
313 | | RenderEmphasized |
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 | 183 | Args(Args) { |
328 | 183 | InlineCommandCommentBits.RenderKind = RK; |
329 | 183 | InlineCommandCommentBits.CommandID = CommandID; |
330 | 183 | } |
331 | | |
332 | | static bool classof(const Comment *C) { |
333 | | return C->getCommentKind() == InlineCommandCommentKind; |
334 | | } |
335 | | |
336 | 173 | child_iterator child_begin() const { return nullptr; } |
337 | | |
338 | 173 | child_iterator child_end() const { return nullptr; } |
339 | | |
340 | 178 | unsigned getCommandID() const { |
341 | 178 | return InlineCommandCommentBits.CommandID; |
342 | 178 | } |
343 | | |
344 | | StringRef getCommandName(const CommandTraits &Traits) const { |
345 | | return Traits.getCommandInfo(getCommandID())->Name; |
346 | | } |
347 | | |
348 | 0 | SourceRange getCommandNameRange() const { |
349 | 0 | return SourceRange(getBeginLoc().getLocWithOffset(-1), getEndLoc()); |
350 | 0 | } |
351 | | |
352 | 215 | RenderKind getRenderKind() const { |
353 | 215 | return static_cast<RenderKind>(InlineCommandCommentBits.RenderKind); |
354 | 215 | } |
355 | | |
356 | 531 | unsigned getNumArgs() const { |
357 | 531 | return Args.size(); |
358 | 531 | } |
359 | | |
360 | 69 | StringRef getArgText(unsigned Idx) const { |
361 | 69 | return Args[Idx].Text; |
362 | 69 | } |
363 | | |
364 | 0 | SourceRange getArgRange(unsigned Idx) const { |
365 | 0 | return Args[Idx].Range; |
366 | 0 | } |
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 | | |
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 | 145 | TagNameRange(TagNameBegin, TagNameEnd) { |
385 | 145 | setLocation(TagNameBegin); |
386 | 145 | HTMLTagCommentBits.IsMalformed = 0; |
387 | 145 | } |
388 | | |
389 | | public: |
390 | | static bool classof(const Comment *C) { |
391 | | return C->getCommentKind() >= FirstHTMLTagCommentConstant && |
392 | | C->getCommentKind() <= LastHTMLTagCommentConstant; |
393 | | } |
394 | | |
395 | 524 | StringRef getTagName() const LLVM_READONLY { return TagName; } |
396 | | |
397 | 0 | SourceRange getTagNameSourceRange() const LLVM_READONLY { |
398 | 0 | SourceLocation L = getLocation(); |
399 | 0 | return SourceRange(L.getLocWithOffset(1), |
400 | 0 | L.getLocWithOffset(1 + TagName.size())); |
401 | 0 | } |
402 | | |
403 | 114 | bool isMalformed() const { |
404 | 114 | return HTMLTagCommentBits.IsMalformed; |
405 | 114 | } |
406 | | |
407 | 58 | void setIsMalformed() { |
408 | 58 | HTMLTagCommentBits.IsMalformed = 1; |
409 | 58 | } |
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 | | |
425 | 0 | Attribute() { } |
426 | | |
427 | | Attribute(SourceLocation NameLocBegin, StringRef Name) : |
428 | | NameLocBegin(NameLocBegin), Name(Name), |
429 | | EqualsLoc(SourceLocation()), |
430 | | ValueRange(SourceRange()), Value(StringRef()) |
431 | 20 | { } |
432 | | |
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 | 18 | { } |
440 | | |
441 | 14 | SourceLocation getNameLocEnd() const { |
442 | 14 | return NameLocBegin.getLocWithOffset(Name.size()); |
443 | 14 | } |
444 | | |
445 | 0 | SourceRange getNameRange() const { |
446 | 0 | return SourceRange(NameLocBegin, getNameLocEnd()); |
447 | 0 | } |
448 | | }; |
449 | | |
450 | | private: |
451 | | ArrayRef<Attribute> Attributes; |
452 | | |
453 | | public: |
454 | | HTMLStartTagComment(SourceLocation LocBegin, |
455 | | StringRef TagName) : |
456 | | HTMLTagComment(HTMLStartTagCommentKind, |
457 | | LocBegin, LocBegin.getLocWithOffset(1 + TagName.size()), |
458 | | TagName, |
459 | | LocBegin.getLocWithOffset(1), |
460 | 94 | LocBegin.getLocWithOffset(1 + TagName.size())) { |
461 | 94 | HTMLStartTagCommentBits.IsSelfClosing = false; |
462 | 94 | } |
463 | | |
464 | | static bool classof(const Comment *C) { |
465 | | return C->getCommentKind() == HTMLStartTagCommentKind; |
466 | | } |
467 | | |
468 | 65 | child_iterator child_begin() const { return nullptr; } |
469 | | |
470 | 65 | child_iterator child_end() const { return nullptr; } |
471 | | |
472 | 253 | unsigned getNumAttrs() const { |
473 | 253 | return Attributes.size(); |
474 | 253 | } |
475 | | |
476 | 102 | const Attribute &getAttr(unsigned Idx) const { |
477 | 102 | return Attributes[Idx]; |
478 | 102 | } |
479 | | |
480 | 94 | void setAttrs(ArrayRef<Attribute> Attrs) { |
481 | 94 | Attributes = Attrs; |
482 | 94 | if (!Attrs.empty()) { |
483 | 32 | const Attribute &Attr = Attrs.back(); |
484 | 32 | SourceLocation L = Attr.ValueRange.getEnd(); |
485 | 32 | if (L.isValid()) |
486 | 18 | Range.setEnd(L); |
487 | 14 | else { |
488 | 14 | Range.setEnd(Attr.getNameLocEnd()); |
489 | 14 | } |
490 | 32 | } |
491 | 94 | } |
492 | | |
493 | 94 | void setGreaterLoc(SourceLocation GreaterLoc) { |
494 | 94 | Range.setEnd(GreaterLoc); |
495 | 94 | } |
496 | | |
497 | 171 | bool isSelfClosing() const { |
498 | 171 | return HTMLStartTagCommentBits.IsSelfClosing; |
499 | 171 | } |
500 | | |
501 | 9 | void setSelfClosing() { |
502 | 9 | HTMLStartTagCommentBits.IsSelfClosing = true; |
503 | 9 | } |
504 | | }; |
505 | | |
506 | | /// A closing HTML tag. |
507 | | class HTMLEndTagComment : public HTMLTagComment { |
508 | | public: |
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 | 51 | { } |
518 | | |
519 | | static bool classof(const Comment *C) { |
520 | | return C->getCommentKind() == HTMLEndTagCommentKind; |
521 | | } |
522 | | |
523 | 38 | child_iterator child_begin() const { return nullptr; } |
524 | | |
525 | 38 | 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: |
532 | | BlockContentComment(CommentKind K, |
533 | | SourceLocation LocBegin, |
534 | | SourceLocation LocEnd) : |
535 | | Comment(K, LocBegin, LocEnd) |
536 | 3.96k | { } |
537 | | |
538 | | public: |
539 | 0 | static bool classof(const Comment *C) { |
540 | 0 | return C->getCommentKind() >= FirstBlockContentCommentConstant && |
541 | 0 | C->getCommentKind() <= LastBlockContentCommentConstant; |
542 | 0 | } |
543 | | }; |
544 | | |
545 | | /// A single paragraph that contains inline content. |
546 | | class ParagraphComment : public BlockContentComment { |
547 | | ArrayRef<InlineContentComment *> Content; |
548 | | |
549 | | public: |
550 | | ParagraphComment(ArrayRef<InlineContentComment *> Content) : |
551 | | BlockContentComment(ParagraphCommentKind, |
552 | | SourceLocation(), |
553 | | SourceLocation()), |
554 | 2.64k | Content(Content) { |
555 | 2.64k | if (Content.empty()) { |
556 | 178 | ParagraphCommentBits.IsWhitespace = true; |
557 | 178 | ParagraphCommentBits.IsWhitespaceValid = true; |
558 | 178 | return; |
559 | 178 | } |
560 | 2.46k | |
561 | 2.46k | ParagraphCommentBits.IsWhitespaceValid = false; |
562 | 2.46k | |
563 | 2.46k | setSourceRange(SourceRange(Content.front()->getBeginLoc(), |
564 | 2.46k | Content.back()->getEndLoc())); |
565 | 2.46k | setLocation(Content.front()->getBeginLoc()); |
566 | 2.46k | } |
567 | | |
568 | | static bool classof(const Comment *C) { |
569 | | return C->getCommentKind() == ParagraphCommentKind; |
570 | | } |
571 | | |
572 | 11.8k | child_iterator child_begin() const { |
573 | 11.8k | return reinterpret_cast<child_iterator>(Content.begin()); |
574 | 11.8k | } |
575 | | |
576 | 9.21k | child_iterator child_end() const { |
577 | 9.21k | return reinterpret_cast<child_iterator>(Content.end()); |
578 | 9.21k | } |
579 | | |
580 | 7.15k | bool isWhitespace() const { |
581 | 7.15k | if (ParagraphCommentBits.IsWhitespaceValid) |
582 | 5.18k | return ParagraphCommentBits.IsWhitespace; |
583 | 1.97k | |
584 | 1.97k | ParagraphCommentBits.IsWhitespace = isWhitespaceNoCache(); |
585 | 1.97k | ParagraphCommentBits.IsWhitespaceValid = true; |
586 | 1.97k | return ParagraphCommentBits.IsWhitespace; |
587 | 1.97k | } |
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 | | |
602 | 0 | Argument() { } |
603 | 498 | 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 | 615 | Paragraph(nullptr) { |
620 | 615 | setLocation(getCommandNameBeginLoc()); |
621 | 615 | BlockCommandCommentBits.CommandID = CommandID; |
622 | 615 | BlockCommandCommentBits.CommandMarker = CommandMarker; |
623 | 615 | } |
624 | | |
625 | | public: |
626 | | BlockCommandComment(SourceLocation LocBegin, |
627 | | SourceLocation LocEnd, |
628 | | unsigned CommandID, |
629 | | CommandMarkerKind CommandMarker) : |
630 | | BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd), |
631 | 708 | Paragraph(nullptr) { |
632 | 708 | setLocation(getCommandNameBeginLoc()); |
633 | 708 | BlockCommandCommentBits.CommandID = CommandID; |
634 | 708 | BlockCommandCommentBits.CommandMarker = CommandMarker; |
635 | 708 | } |
636 | | |
637 | | static bool classof(const Comment *C) { |
638 | | return C->getCommentKind() >= FirstBlockCommandCommentConstant && |
639 | | C->getCommentKind() <= LastBlockCommandCommentConstant; |
640 | | } |
641 | | |
642 | 2.55k | child_iterator child_begin() const { |
643 | 2.55k | return reinterpret_cast<child_iterator>(&Paragraph); |
644 | 2.55k | } |
645 | | |
646 | 1.72k | child_iterator child_end() const { |
647 | 1.72k | return reinterpret_cast<child_iterator>(&Paragraph + 1); |
648 | 1.72k | } |
649 | | |
650 | 7.38k | unsigned getCommandID() const { |
651 | 7.38k | return BlockCommandCommentBits.CommandID; |
652 | 7.38k | } |
653 | | |
654 | 1.09k | StringRef getCommandName(const CommandTraits &Traits) const { |
655 | 1.09k | return Traits.getCommandInfo(getCommandID())->Name; |
656 | 1.09k | } |
657 | | |
658 | 1.53k | SourceLocation getCommandNameBeginLoc() const { |
659 | 1.53k | return getBeginLoc().getLocWithOffset(1); |
660 | 1.53k | } |
661 | | |
662 | 212 | SourceRange getCommandNameRange(const CommandTraits &Traits) const { |
663 | 212 | StringRef Name = getCommandName(Traits); |
664 | 212 | return SourceRange(getCommandNameBeginLoc(), |
665 | 212 | getBeginLoc().getLocWithOffset(1 + Name.size())); |
666 | 212 | } |
667 | | |
668 | 2.04k | unsigned getNumArgs() const { |
669 | 2.04k | return Args.size(); |
670 | 2.04k | } |
671 | | |
672 | 0 | StringRef getArgText(unsigned Idx) const { |
673 | 0 | return Args[Idx].Text; |
674 | 0 | } |
675 | | |
676 | 24 | SourceRange getArgRange(unsigned Idx) const { |
677 | 24 | return Args[Idx].Range; |
678 | 24 | } |
679 | | |
680 | 498 | void setArgs(ArrayRef<Argument> A) { |
681 | 498 | Args = A; |
682 | 498 | if (Args.size() > 0) { |
683 | 498 | SourceLocation NewLocEnd = Args.back().Range.getEnd(); |
684 | 498 | if (NewLocEnd.isValid()) |
685 | 498 | setSourceRange(SourceRange(getBeginLoc(), NewLocEnd)); |
686 | 498 | } |
687 | 498 | } |
688 | | |
689 | 2.77k | ParagraphComment *getParagraph() const LLVM_READONLY { |
690 | 2.77k | return Paragraph; |
691 | 2.77k | } |
692 | | |
693 | | bool hasNonWhitespaceParagraph() const { |
694 | | return Paragraph && !Paragraph->isWhitespace(); |
695 | | } |
696 | | |
697 | 1.22k | void setParagraph(ParagraphComment *PC) { |
698 | 1.22k | Paragraph = PC; |
699 | 1.22k | SourceLocation NewLocEnd = PC->getEndLoc(); |
700 | 1.22k | if (NewLocEnd.isValid()) |
701 | 1.04k | setSourceRange(SourceRange(getBeginLoc(), NewLocEnd)); |
702 | 1.22k | } |
703 | | |
704 | 286 | CommandMarkerKind getCommandMarker() const LLVM_READONLY { |
705 | 286 | return static_cast<CommandMarkerKind>( |
706 | 286 | BlockCommandCommentBits.CommandMarker); |
707 | 286 | } |
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 | 356 | ParamIndex(InvalidParamIndex) { |
729 | 356 | ParamCommandCommentBits.Direction = In; |
730 | 356 | ParamCommandCommentBits.IsDirectionExplicit = false; |
731 | 356 | } |
732 | | |
733 | 2.56k | static bool classof(const Comment *C) { |
734 | 2.56k | return C->getCommentKind() == ParamCommandCommentKind; |
735 | 2.56k | } |
736 | | |
737 | | enum PassDirection { |
738 | | In, |
739 | | Out, |
740 | | InOut |
741 | | }; |
742 | | |
743 | | static const char *getDirectionAsString(PassDirection D); |
744 | | |
745 | 435 | PassDirection getDirection() const LLVM_READONLY { |
746 | 435 | return static_cast<PassDirection>(ParamCommandCommentBits.Direction); |
747 | 435 | } |
748 | | |
749 | 1.17k | bool isDirectionExplicit() const LLVM_READONLY { |
750 | 1.17k | return ParamCommandCommentBits.IsDirectionExplicit; |
751 | 1.17k | } |
752 | | |
753 | 349 | void setDirection(PassDirection Direction, bool Explicit) { |
754 | 349 | ParamCommandCommentBits.Direction = Direction; |
755 | 349 | ParamCommandCommentBits.IsDirectionExplicit = Explicit; |
756 | 349 | } |
757 | | |
758 | 973 | bool hasParamName() const { |
759 | 973 | return getNumArgs() > 0; |
760 | 973 | } |
761 | | |
762 | | StringRef getParamName(const FullComment *FC) const; |
763 | | |
764 | 762 | StringRef getParamNameAsWritten() const { |
765 | 762 | return Args[0].Text; |
766 | 762 | } |
767 | | |
768 | 107 | SourceRange getParamNameRange() const { |
769 | 107 | return Args[0].Range; |
770 | 107 | } |
771 | | |
772 | 1.36k | bool isParamIndexValid() const LLVM_READONLY { |
773 | 1.36k | return ParamIndex != InvalidParamIndex; |
774 | 1.36k | } |
775 | | |
776 | 927 | bool isVarArgParam() const LLVM_READONLY { |
777 | 927 | return ParamIndex == VarArgParamIndex; |
778 | 927 | } |
779 | | |
780 | 22 | void setIsVarArgParam() { |
781 | 22 | ParamIndex = VarArgParamIndex; |
782 | 22 | assert(isParamIndexValid()); |
783 | 22 | } |
784 | | |
785 | 867 | unsigned getParamIndex() const LLVM_READONLY { |
786 | 867 | assert(isParamIndexValid()); |
787 | 867 | assert(!isVarArgParam()); |
788 | 867 | return ParamIndex; |
789 | 867 | } |
790 | | |
791 | 176 | void setParamIndex(unsigned Index) { |
792 | 176 | ParamIndex = Index; |
793 | 176 | assert(isParamIndexValid()); |
794 | 176 | assert(!isVarArgParam()); |
795 | 176 | } |
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 | 156 | { } |
823 | | |
824 | | static bool classof(const Comment *C) { |
825 | | return C->getCommentKind() == TParamCommandCommentKind; |
826 | | } |
827 | | |
828 | 372 | bool hasParamName() const { |
829 | 372 | return getNumArgs() > 0; |
830 | 372 | } |
831 | | |
832 | | StringRef getParamName(const FullComment *FC) const; |
833 | | |
834 | 182 | StringRef getParamNameAsWritten() const { |
835 | 182 | return Args[0].Text; |
836 | 182 | } |
837 | | |
838 | 2 | SourceRange getParamNameRange() const { |
839 | 2 | return Args[0].Range; |
840 | 2 | } |
841 | | |
842 | 999 | bool isPositionValid() const LLVM_READONLY { |
843 | 999 | return !Position.empty(); |
844 | 999 | } |
845 | | |
846 | 830 | unsigned getDepth() const { |
847 | 830 | assert(isPositionValid()); |
848 | 830 | return Position.size(); |
849 | 830 | } |
850 | | |
851 | 601 | unsigned getIndex(unsigned Depth) const { |
852 | 601 | assert(isPositionValid()); |
853 | 601 | return Position[Depth]; |
854 | 601 | } |
855 | | |
856 | 92 | void setPosition(ArrayRef<unsigned> NewPosition) { |
857 | 92 | Position = NewPosition; |
858 | 92 | assert(isPositionValid()); |
859 | 92 | } |
860 | | }; |
861 | | |
862 | | /// A line of text contained in a verbatim block. |
863 | | class VerbatimBlockLineComment : public Comment { |
864 | | StringRef Text; |
865 | | |
866 | | public: |
867 | | VerbatimBlockLineComment(SourceLocation LocBegin, |
868 | | StringRef Text) : |
869 | | Comment(VerbatimBlockLineCommentKind, |
870 | | LocBegin, |
871 | | LocBegin.getLocWithOffset(Text.size())), |
872 | | Text(Text) |
873 | 46 | { } |
874 | | |
875 | | static bool classof(const Comment *C) { |
876 | | return C->getCommentKind() == VerbatimBlockLineCommentKind; |
877 | | } |
878 | | |
879 | 35 | child_iterator child_begin() const { return nullptr; } |
880 | | |
881 | 35 | child_iterator child_end() const { return nullptr; } |
882 | | |
883 | 85 | StringRef getText() const LLVM_READONLY { |
884 | 85 | return Text; |
885 | 85 | } |
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: |
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 | 30 | { } |
905 | | |
906 | | static bool classof(const Comment *C) { |
907 | | return C->getCommentKind() == VerbatimBlockCommentKind; |
908 | | } |
909 | | |
910 | 57 | child_iterator child_begin() const { |
911 | 57 | return reinterpret_cast<child_iterator>(Lines.begin()); |
912 | 57 | } |
913 | | |
914 | 40 | child_iterator child_end() const { |
915 | 40 | return reinterpret_cast<child_iterator>(Lines.end()); |
916 | 40 | } |
917 | | |
918 | 30 | void setCloseName(StringRef Name, SourceLocation LocBegin) { |
919 | 30 | CloseName = Name; |
920 | 30 | CloseNameLocBegin = LocBegin; |
921 | 30 | } |
922 | | |
923 | 30 | void setLines(ArrayRef<VerbatimBlockLineComment *> L) { |
924 | 30 | Lines = L; |
925 | 30 | } |
926 | | |
927 | 26 | StringRef getCloseName() const { |
928 | 26 | return CloseName; |
929 | 26 | } |
930 | | |
931 | | unsigned getNumLines() const { |
932 | | return Lines.size(); |
933 | | } |
934 | | |
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: |
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 | 73 | { } |
961 | | |
962 | | static bool classof(const Comment *C) { |
963 | | return C->getCommentKind() == VerbatimLineCommentKind; |
964 | | } |
965 | | |
966 | 46 | child_iterator child_begin() const { return nullptr; } |
967 | | |
968 | 46 | child_iterator child_end() const { return nullptr; } |
969 | | |
970 | 58 | StringRef getText() const { |
971 | 58 | return Text; |
972 | 58 | } |
973 | | |
974 | 0 | SourceRange getTextRange() const { |
975 | 0 | return SourceRange(TextBegin, getEndLoc()); |
976 | 0 | } |
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 | | |
1081 | 2.71k | DeclKind getKind() const LLVM_READONLY { |
1082 | 2.71k | return static_cast<DeclKind>(Kind); |
1083 | 2.71k | } |
1084 | | |
1085 | 296 | TemplateDeclKind getTemplateKind() const LLVM_READONLY { |
1086 | 296 | return static_cast<TemplateDeclKind>(TemplateKind); |
1087 | 296 | } |
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: |
1096 | | FullComment(ArrayRef<BlockContentComment *> Blocks, DeclInfo *D) : |
1097 | | Comment(FullCommentKind, SourceLocation(), SourceLocation()), |
1098 | 1.38k | Blocks(Blocks), ThisDeclInfo(D) { |
1099 | 1.38k | if (Blocks.empty()) |
1100 | 13 | return; |
1101 | 1.37k | |
1102 | 1.37k | setSourceRange( |
1103 | 1.37k | SourceRange(Blocks.front()->getBeginLoc(), Blocks.back()->getEndLoc())); |
1104 | 1.37k | setLocation(Blocks.front()->getBeginLoc()); |
1105 | 1.37k | } |
1106 | | |
1107 | 1.93k | static bool classof(const Comment *C) { |
1108 | 1.93k | return C->getCommentKind() == FullCommentKind; |
1109 | 1.93k | } |
1110 | | |
1111 | 7.73k | child_iterator child_begin() const { |
1112 | 7.73k | return reinterpret_cast<child_iterator>(Blocks.begin()); |
1113 | 7.73k | } |
1114 | | |
1115 | 5.69k | child_iterator child_end() const { |
1116 | 5.69k | return reinterpret_cast<child_iterator>(Blocks.end()); |
1117 | 5.69k | } |
1118 | | |
1119 | 119 | const Decl *getDecl() const LLVM_READONLY { |
1120 | 119 | return ThisDeclInfo->CommentDecl; |
1121 | 119 | } |
1122 | | |
1123 | 1.43k | const DeclInfo *getDeclInfo() const LLVM_READONLY { |
1124 | 1.43k | if (!ThisDeclInfo->IsFilled) |
1125 | 0 | ThisDeclInfo->fill(); |
1126 | 1.43k | return ThisDeclInfo; |
1127 | 1.43k | } |
1128 | | |
1129 | 119 | ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; } |
1130 | | |
1131 | | }; |
1132 | | } // end namespace comments |
1133 | | } // end namespace clang |
1134 | | |
1135 | | #endif |
1136 | | |