Coverage Report

Created: 2022-07-16 07:03

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