Coverage Report

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