Coverage Report

Created: 2018-07-20 23:04

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