Coverage Report

Created: 2018-09-25 23:22

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