Coverage Report

Created: 2022-01-18 06:27

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