Coverage Report

Created: 2020-11-24 06:42

/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.14k
  void setSourceRange(SourceRange SR) {
178
7.14k
    Range = SR;
179
7.14k
  }
180
181
7.09k
  void setLocation(SourceLocation L) {
182
7.09k
    Loc = L;
183
7.09k
  }
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
11.7k
      Loc(LocBegin), Range(SourceRange(LocBegin, LocEnd)) {
201
11.7k
    CommentBits.Kind = K;
202
11.7k
  }
203
204
105k
  CommentKind getCommentKind() const {
205
105k
    return static_cast<CommentKind>(CommentBits.Kind);
206
105k
  }
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.24k
  SourceRange getSourceRange() const LLVM_READONLY { return Range; }
215
216
14.6k
  SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); }
217
218
6.76k
  SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); }
219
220
498
  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.1k
  unsigned child_count() const {
230
12.1k
    return child_end() - child_begin();
231
12.1k
  }
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.45k
      Comment(K, LocBegin, LocEnd) {
242
4.45k
    InlineContentCommentBits.HasTrailingNewline = 0;
243
4.45k
  }
244
245
public:
246
5.07k
  static bool classof(const Comment *C) {
247
5.07k
    return C->getCommentKind() >= FirstInlineContentCommentConstant &&
248
5.07k
           C->getCommentKind() <= LastInlineContentCommentConstant;
249
5.07k
  }
250
251
680
  void addTrailingNewline() {
252
680
    InlineContentCommentBits.HasTrailingNewline = 1;
253
680
  }
254
255
2.66k
  bool hasTrailingNewline() const {
256
2.66k
    return InlineContentCommentBits.HasTrailingNewline;
257
2.66k
  }
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.03k
      Text(Text) {
270
4.03k
    TextCommentBits.IsWhitespaceValid = false;
271
4.03k
  }
272
273
16.1k
  static bool classof(const Comment *C) {
274
16.1k
    return C->getCommentKind() == TextCommentKind;
275
16.1k
  }
276
277
2.48k
  child_iterator child_begin() const { return nullptr; }
278
279
2.48k
  child_iterator child_end() const { return nullptr; }
280
281
6.00k
  StringRef getText() const LLVM_READONLY { return Text; }
282
283
4.66k
  bool isWhitespace() const {
284
4.66k
    if (TextCommentBits.IsWhitespaceValid)
285
1.84k
      return TextCommentBits.IsWhitespace;
286
287
2.81k
    TextCommentBits.IsWhitespace = isWhitespaceNoCache();
288
2.81k
    TextCommentBits.IsWhitespaceValid = true;
289
2.81k
    return TextCommentBits.IsWhitespace;
290
2.81k
  }
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
241
      Args(Args) {
328
241
    InlineCommandCommentBits.RenderKind = RK;
329
241
    InlineCommandCommentBits.CommandID = CommandID;
330
241
  }
331
332
1.17k
  static bool classof(const Comment *C) {
333
1.17k
    return C->getCommentKind() == InlineCommandCommentKind;
334
1.17k
  }
335
336
193
  child_iterator child_begin() const { return nullptr; }
337
338
193
  child_iterator child_end() const { return nullptr; }
339
340
198
  unsigned getCommandID() const {
341
198
    return InlineCommandCommentBits.CommandID;
342
198
  }
343
344
188
  StringRef getCommandName(const CommandTraits &Traits) const {
345
188
    return Traits.getCommandInfo(getCommandID())->Name;
346
188
  }
347
348
0
  SourceRange getCommandNameRange() const {
349
0
    return SourceRange(getBeginLoc().getLocWithOffset(-1), getEndLoc());
350
0
  }
351
352
255
  RenderKind getRenderKind() const {
353
255
    return static_cast<RenderKind>(InlineCommandCommentBits.RenderKind);
354
255
  }
355
356
657
  unsigned getNumArgs() const {
357
657
    return Args.size();
358
657
  }
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
        NameLocBegin(NameLocBegin), Name(Name),
429
        EqualsLoc(SourceLocation()),
430
        ValueRange(SourceRange()), Value(StringRef())
431
28
    { }
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
21
    { }
440
441
19
    SourceLocation getNameLocEnd() const {
442
19
      return NameLocBegin.getLocWithOffset(Name.size());
443
19
    }
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
123
                     LocBegin.getLocWithOffset(1 + TagName.size())) {
461
123
    HTMLStartTagCommentBits.IsSelfClosing = false;
462
123
  }
463
464
296
  static bool classof(const Comment *C) {
465
296
    return C->getCommentKind() == HTMLStartTagCommentKind;
466
296
  }
467
468
67
  child_iterator child_begin() const { return nullptr; }
469
470
67
  child_iterator child_end() const { return nullptr; }
471
472
255
  unsigned getNumAttrs() const {
473
255
    return Attributes.size();
474
255
  }
475
476
102
  const Attribute &getAttr(unsigned Idx) const {
477
102
    return Attributes[Idx];
478
102
  }
479
480
123
  void setAttrs(ArrayRef<Attribute> Attrs) {
481
123
    Attributes = Attrs;
482
123
    if (!Attrs.empty()) {
483
40
      const Attribute &Attr = Attrs.back();
484
40
      SourceLocation L = Attr.ValueRange.getEnd();
485
40
      if (L.isValid())
486
21
        Range.setEnd(L);
487
19
      else {
488
19
        Range.setEnd(Attr.getNameLocEnd());
489
19
      }
490
40
    }
491
123
  }
492
493
123
  void setGreaterLoc(SourceLocation GreaterLoc) {
494
123
    Range.setEnd(GreaterLoc);
495
123
  }
496
497
173
  bool isSelfClosing() const {
498
173
    return HTMLStartTagCommentBits.IsSelfClosing;
499
173
  }
500
501
12
  void setSelfClosing() {
502
12
    HTMLStartTagCommentBits.IsSelfClosing = true;
503
12
  }
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
64
  { }
518
519
  static bool classof(const Comment *C) {
520
    return C->getCommentKind() == HTMLEndTagCommentKind;
521
  }
522
523
39
  child_iterator child_begin() const { return nullptr; }
524
525
39
  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
5.43k
  { }
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
3.58k
      Content(Content) {
555
3.58k
    if (Content.empty()) {
556
301
      ParagraphCommentBits.IsWhitespace = true;
557
301
      ParagraphCommentBits.IsWhitespaceValid = true;
558
301
      return;
559
301
    }
560
561
3.28k
    ParagraphCommentBits.IsWhitespaceValid = false;
562
563
3.28k
    setSourceRange(SourceRange(Content.front()->getBeginLoc(),
564
3.28k
                               Content.back()->getEndLoc()));
565
3.28k
    setLocation(Content.front()->getBeginLoc());
566
3.28k
  }
567
568
7.71k
  static bool classof(const Comment *C) {
569
7.71k
    return C->getCommentKind() == ParagraphCommentKind;
570
7.71k
  }
571
572
12.4k
  child_iterator child_begin() const {
573
12.4k
    return reinterpret_cast<child_iterator>(Content.begin());
574
12.4k
  }
575
576
9.80k
  child_iterator child_end() const {
577
9.80k
    return reinterpret_cast<child_iterator>(Content.end());
578
9.80k
  }
579
580
7.76k
  bool isWhitespace() const {
581
7.76k
    if (ParagraphCommentBits.IsWhitespaceValid)
582
5.39k
      return ParagraphCommentBits.IsWhitespace;
583
584
2.37k
    ParagraphCommentBits.IsWhitespace = isWhitespaceNoCache();
585
2.37k
    ParagraphCommentBits.IsWhitespaceValid = true;
586
2.37k
    return ParagraphCommentBits.IsWhitespace;
587
2.37k
  }
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
686
    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
844
      Paragraph(nullptr) {
620
844
    setLocation(getCommandNameBeginLoc());
621
844
    BlockCommandCommentBits.CommandID = CommandID;
622
844
    BlockCommandCommentBits.CommandMarker = CommandMarker;
623
844
  }
624
625
public:
626
  BlockCommandComment(SourceLocation LocBegin,
627
                      SourceLocation LocEnd,
628
                      unsigned CommandID,
629
                      CommandMarkerKind CommandMarker) :
630
      BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd),
631
1.00k
      Paragraph(nullptr) {
632
1.00k
    setLocation(getCommandNameBeginLoc());
633
1.00k
    BlockCommandCommentBits.CommandID = CommandID;
634
1.00k
    BlockCommandCommentBits.CommandMarker = CommandMarker;
635
1.00k
  }
636
637
3.07k
  static bool classof(const Comment *C) {
638
3.07k
    return C->getCommentKind() >= FirstBlockCommandCommentConstant &&
639
3.07k
           C->getCommentKind() <= LastBlockCommandCommentConstant;
640
3.07k
  }
641
642
2.61k
  child_iterator child_begin() const {
643
2.61k
    return reinterpret_cast<child_iterator>(&Paragraph);
644
2.61k
  }
645
646
1.75k
  child_iterator child_end() const {
647
1.75k
    return reinterpret_cast<child_iterator>(&Paragraph + 1);
648
1.75k
  }
649
650
9.44k
  unsigned getCommandID() const {
651
9.44k
    return BlockCommandCommentBits.CommandID;
652
9.44k
  }
653
654
1.33k
  StringRef getCommandName(const CommandTraits &Traits) const {
655
1.33k
    return Traits.getCommandInfo(getCommandID())->Name;
656
1.33k
  }
657
658
2.15k
  SourceLocation getCommandNameBeginLoc() const {
659
2.15k
    return getBeginLoc().getLocWithOffset(1);
660
2.15k
  }
661
662
303
  SourceRange getCommandNameRange(const CommandTraits &Traits) const {
663
303
    StringRef Name = getCommandName(Traits);
664
303
    return SourceRange(getCommandNameBeginLoc(),
665
303
                       getBeginLoc().getLocWithOffset(1 + Name.size()));
666
303
  }
667
668
2.98k
  unsigned getNumArgs() const {
669
2.98k
    return Args.size();
670
2.98k
  }
671
672
0
  StringRef getArgText(unsigned Idx) const {
673
0
    return Args[Idx].Text;
674
0
  }
675
676
36
  SourceRange getArgRange(unsigned Idx) const {
677
36
    return Args[Idx].Range;
678
36
  }
679
680
686
  void setArgs(ArrayRef<Argument> A) {
681
686
    Args = A;
682
686
    if (Args.size() > 0) {
683
686
      SourceLocation NewLocEnd = Args.back().Range.getEnd();
684
686
      if (NewLocEnd.isValid())
685
686
        setSourceRange(SourceRange(getBeginLoc(), NewLocEnd));
686
686
    }
687
686
  }
688
689
3.24k
  ParagraphComment *getParagraph() const LLVM_READONLY {
690
3.24k
    return Paragraph;
691
3.24k
  }
692
693
582
  bool hasNonWhitespaceParagraph() const {
694
582
    return Paragraph && !Paragraph->isWhitespace();
695
582
  }
696
697
1.70k
  void setParagraph(ParagraphComment *PC) {
698
1.70k
    Paragraph = PC;
699
1.70k
    SourceLocation NewLocEnd = PC->getEndLoc();
700
1.70k
    if (NewLocEnd.isValid())
701
1.40k
      setSourceRange(SourceRange(getBeginLoc(), NewLocEnd));
702
1.70k
  }
703
704
497
  CommandMarkerKind getCommandMarker() const LLVM_READONLY {
705
497
    return static_cast<CommandMarkerKind>(
706
497
        BlockCommandCommentBits.CommandMarker);
707
497
  }
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
501
      ParamIndex(InvalidParamIndex) {
729
501
    ParamCommandCommentBits.Direction = In;
730
501
    ParamCommandCommentBits.IsDirectionExplicit = false;
731
501
  }
732
733
4.94k
  static bool classof(const Comment *C) {
734
4.94k
    return C->getCommentKind() == ParamCommandCommentKind;
735
4.94k
  }
736
737
  enum PassDirection {
738
    In,
739
    Out,
740
    InOut
741
  };
742
743
  static const char *getDirectionAsString(PassDirection D);
744
745
442
  PassDirection getDirection() const LLVM_READONLY {
746
442
    return static_cast<PassDirection>(ParamCommandCommentBits.Direction);
747
442
  }
748
749
1.32k
  bool isDirectionExplicit() const LLVM_READONLY {
750
1.32k
    return ParamCommandCommentBits.IsDirectionExplicit;
751
1.32k
  }
752
753
492
  void setDirection(PassDirection Direction, bool Explicit) {
754
492
    ParamCommandCommentBits.Direction = Direction;
755
492
    ParamCommandCommentBits.IsDirectionExplicit = Explicit;
756
492
  }
757
758
1.11k
  bool hasParamName() const {
759
1.11k
    return getNumArgs() > 0;
760
1.11k
  }
761
762
  StringRef getParamName(const FullComment *FC) const;
763
764
930
  StringRef getParamNameAsWritten() const {
765
930
    return Args[0].Text;
766
930
  }
767
768
152
  SourceRange getParamNameRange() const {
769
152
    return Args[0].Range;
770
152
  }
771
772
2.79k
  bool isParamIndexValid() const LLVM_READONLY {
773
2.79k
    return ParamIndex != InvalidParamIndex;
774
2.79k
  }
775
776
2.06k
  bool isVarArgParam() const LLVM_READONLY {
777
2.06k
    return ParamIndex == VarArgParamIndex;
778
2.06k
  }
779
780
35
  void setIsVarArgParam() {
781
35
    ParamIndex = VarArgParamIndex;
782
35
    assert(isParamIndexValid());
783
35
  }
784
785
878
  unsigned getParamIndex() const LLVM_READONLY {
786
878
    assert(isParamIndexValid());
787
878
    assert(!isVarArgParam());
788
878
    return ParamIndex;
789
878
  }
790
791
247
  void setParamIndex(unsigned Index) {
792
247
    ParamIndex = Index;
793
247
    assert(isParamIndexValid());
794
247
    assert(!isVarArgParam());
795
247
  }
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
202
  { }
823
824
1.11k
  static bool classof(const Comment *C) {
825
1.11k
    return C->getCommentKind() == TParamCommandCommentKind;
826
1.11k
  }
827
828
374
  bool hasParamName() const {
829
374
    return getNumArgs() > 0;
830
374
  }
831
832
  StringRef getParamName(const FullComment *FC) const;
833
834
183
  StringRef getParamNameAsWritten() const {
835
183
    return Args[0].Text;
836
183
  }
837
838
3
  SourceRange getParamNameRange() const {
839
3
    return Args[0].Range;
840
3
  }
841
842
2.71k
  bool isPositionValid() const LLVM_READONLY {
843
2.71k
    return !Position.empty();
844
2.71k
  }
845
846
832
  unsigned getDepth() const {
847
832
    assert(isPositionValid());
848
832
    return Position.size();
849
832
  }
850
851
603
  unsigned getIndex(unsigned Depth) const {
852
603
    assert(isPositionValid());
853
603
    return Position[Depth];
854
603
  }
855
856
118
  void setPosition(ArrayRef<unsigned> NewPosition) {
857
118
    Position = NewPosition;
858
118
    assert(isPositionValid());
859
118
  }
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
57
  { }
874
875
34
  static bool classof(const Comment *C) {
876
34
    return C->getCommentKind() == VerbatimBlockLineCommentKind;
877
34
  }
878
879
36
  child_iterator child_begin() const { return nullptr; }
880
881
36
  child_iterator child_end() const { return nullptr; }
882
883
86
  StringRef getText() const LLVM_READONLY {
884
86
    return Text;
885
86
  }
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
37
  { }
905
906
  static bool classof(const Comment *C) {
907
    return C->getCommentKind() == VerbatimBlockCommentKind;
908
  }
909
910
58
  child_iterator child_begin() const {
911
58
    return reinterpret_cast<child_iterator>(Lines.begin());
912
58
  }
913
914
41
  child_iterator child_end() const {
915
41
    return reinterpret_cast<child_iterator>(Lines.end());
916
41
  }
917
918
37
  void setCloseName(StringRef Name, SourceLocation LocBegin) {
919
37
    CloseName = Name;
920
37
    CloseNameLocBegin = LocBegin;
921
37
  }
922
923
37
  void setLines(ArrayRef<VerbatimBlockLineComment *> L) {
924
37
    Lines = L;
925
37
  }
926
927
27
  StringRef getCloseName() const {
928
27
    return CloseName;
929
27
  }
930
931
30
  unsigned getNumLines() const {
932
30
    return Lines.size();
933
30
  }
934
935
50
  StringRef getText(unsigned LineIdx) const {
936
50
    return Lines[LineIdx]->getText();
937
50
  }
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
104
  { }
961
962
176
  static bool classof(const Comment *C) {
963
176
    return C->getCommentKind() == VerbatimLineCommentKind;
964
176
  }
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
3.47k
  DeclKind getKind() const LLVM_READONLY {
1082
3.47k
    return static_cast<DeclKind>(Kind);
1083
3.47k
  }
1084
1085
387
  TemplateDeclKind getTemplateKind() const LLVM_READONLY {
1086
387
    return static_cast<TemplateDeclKind>(TemplateKind);
1087
387
  }
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.78k
      Blocks(Blocks), ThisDeclInfo(D) {
1099
1.78k
    if (Blocks.empty())
1100
16
      return;
1101
1102
1.77k
    setSourceRange(
1103
1.77k
        SourceRange(Blocks.front()->getBeginLoc(), Blocks.back()->getEndLoc()));
1104
1.77k
    setLocation(Blocks.front()->getBeginLoc());
1105
1.77k
  }
1106
1107
4.00k
  static bool classof(const Comment *C) {
1108
4.00k
    return C->getCommentKind() == FullCommentKind;
1109
4.00k
  }
1110
1111
8.21k
  child_iterator child_begin() const {
1112
8.21k
    return reinterpret_cast<child_iterator>(Blocks.begin());
1113
8.21k
  }
1114
1115
6.11k
  child_iterator child_end() const {
1116
6.11k
    return reinterpret_cast<child_iterator>(Blocks.end());
1117
6.11k
  }
1118
1119
106
  const Decl *getDecl() const LLVM_READONLY {
1120
106
    return ThisDeclInfo->CommentDecl;
1121
106
  }
1122
1123
1.45k
  const DeclInfo *getDeclInfo() const LLVM_READONLY {
1124
1.45k
    if (!ThisDeclInfo->IsFilled)
1125
0
      ThisDeclInfo->fill();
1126
1.45k
    return ThisDeclInfo;
1127
1.45k
  }
1128
1129
106
  ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
1130
1131
};
1132
} // end namespace comments
1133
} // end namespace clang
1134
1135
#endif
1136