CommentParser.cpp revision debd16f75fdfa3fb0a498f89450ea574dfb3af4e
1//===- unittests/AST/CommentParser.cpp ------ Comment parser tests --------===//
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#include "clang/Basic/SourceManager.h"
11#include "clang/Basic/FileManager.h"
12#include "clang/Basic/Diagnostic.h"
13#include "clang/AST/Comment.h"
14#include "clang/AST/CommentLexer.h"
15#include "clang/AST/CommentParser.h"
16#include "clang/AST/CommentSema.h"
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/Support/Allocator.h"
19#include <vector>
20
21#include "gtest/gtest.h"
22
23using namespace llvm;
24using namespace clang;
25
26namespace clang {
27namespace comments {
28
29namespace {
30
31const bool DEBUG = true;
32
33class CommentParserTest : public ::testing::Test {
34protected:
35  CommentParserTest()
36    : FileMgr(FileMgrOpts),
37      DiagID(new DiagnosticIDs()),
38      Diags(DiagID, new IgnoringDiagConsumer()),
39      SourceMgr(Diags, FileMgr) {
40  }
41
42  FileSystemOptions FileMgrOpts;
43  FileManager FileMgr;
44  IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
45  DiagnosticsEngine Diags;
46  SourceManager SourceMgr;
47  llvm::BumpPtrAllocator Allocator;
48
49  FullComment *parseString(const char *Source);
50};
51
52FullComment *CommentParserTest::parseString(const char *Source) {
53  MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(Source);
54  FileID File = SourceMgr.createFileIDForMemBuffer(Buf);
55  SourceLocation Begin = SourceMgr.getLocForStartOfFile(File);
56
57  comments::Lexer L(Begin, CommentOptions(),
58                    Source, Source + strlen(Source));
59
60  comments::Sema S(Allocator, SourceMgr, Diags);
61  comments::Parser P(L, S, Allocator, SourceMgr, Diags);
62  comments::FullComment *FC = P.parseFullComment();
63
64  if (DEBUG) {
65    llvm::errs() << "=== Source:\n" << Source << "\n=== AST:\n";
66    FC->dump(SourceMgr);
67  }
68
69  Token Tok;
70  L.lex(Tok);
71  if (Tok.is(tok::eof))
72    return FC;
73  else
74    return NULL;
75}
76
77::testing::AssertionResult HasChildCount(const Comment *C, size_t Count) {
78  if (!C)
79    return ::testing::AssertionFailure() << "Comment is NULL";
80
81  if (Count != C->child_count())
82    return ::testing::AssertionFailure()
83        << "Count = " << Count
84        << ", child_count = " << C->child_count();
85
86  return ::testing::AssertionSuccess();
87}
88
89template <typename T>
90::testing::AssertionResult GetChildAt(const Comment *C,
91                                      size_t Idx,
92                                      T *&Child) {
93  if (!C)
94    return ::testing::AssertionFailure() << "Comment is NULL";
95
96  if (Idx >= C->child_count())
97    return ::testing::AssertionFailure()
98        << "Idx out of range.  Idx = " << Idx
99        << ", child_count = " << C->child_count();
100
101  Comment::child_iterator I = C->child_begin() + Idx;
102  Comment *CommentChild = *I;
103  if (!CommentChild)
104    return ::testing::AssertionFailure() << "Child is NULL";
105
106  Child = dyn_cast<T>(CommentChild);
107  if (!Child)
108    return ::testing::AssertionFailure()
109        << "Child is not of requested type, but a "
110        << CommentChild->getCommentKindName();
111
112  return ::testing::AssertionSuccess();
113}
114
115::testing::AssertionResult HasTextAt(const Comment *C,
116                                     size_t Idx,
117                                     StringRef Text) {
118  TextComment *TC;
119  ::testing::AssertionResult AR = GetChildAt(C, Idx, TC);
120  if (!AR)
121    return AR;
122
123  StringRef ActualText = TC->getText();
124  if (ActualText != Text)
125    return ::testing::AssertionFailure()
126        << "TextComment has text \"" << ActualText.str() << "\", "
127           "expected \"" << Text.str() << "\"";
128
129  if (TC->hasTrailingNewline())
130    return ::testing::AssertionFailure()
131        << "TextComment has a trailing newline";
132
133  return ::testing::AssertionSuccess();
134}
135
136::testing::AssertionResult HasTextWithNewlineAt(const Comment *C,
137                                                size_t Idx,
138                                                StringRef Text) {
139  TextComment *TC;
140  ::testing::AssertionResult AR = GetChildAt(C, Idx, TC);
141  if (!AR)
142    return AR;
143
144  StringRef ActualText = TC->getText();
145  if (ActualText != Text)
146    return ::testing::AssertionFailure()
147        << "TextComment has text \"" << ActualText.str() << "\", "
148           "expected \"" << Text.str() << "\"";
149
150  if (!TC->hasTrailingNewline())
151    return ::testing::AssertionFailure()
152        << "TextComment has no trailing newline";
153
154  return ::testing::AssertionSuccess();
155}
156
157::testing::AssertionResult HasBlockCommandAt(const Comment *C,
158                                             size_t Idx,
159                                             BlockCommandComment *&BCC,
160                                             StringRef Name,
161                                             ParagraphComment *&Paragraph) {
162  ::testing::AssertionResult AR = GetChildAt(C, Idx, BCC);
163  if (!AR)
164    return AR;
165
166  StringRef ActualName = BCC->getCommandName();
167  if (ActualName != Name)
168    return ::testing::AssertionFailure()
169        << "BlockCommandComment has name \"" << ActualName.str() << "\", "
170           "expected \"" << Name.str() << "\"";
171
172  Paragraph = BCC->getParagraph();
173
174  return ::testing::AssertionSuccess();
175}
176
177::testing::AssertionResult HasParamCommandAt(
178                              const Comment *C,
179                              size_t Idx,
180                              ParamCommandComment *&PCC,
181                              StringRef CommandName,
182                              ParamCommandComment::PassDirection Direction,
183                              bool IsDirectionExplicit,
184                              StringRef ParamName,
185                              ParagraphComment *&Paragraph) {
186  ::testing::AssertionResult AR = GetChildAt(C, Idx, PCC);
187  if (!AR)
188    return AR;
189
190  StringRef ActualCommandName = PCC->getCommandName();
191  if (ActualCommandName != CommandName)
192    return ::testing::AssertionFailure()
193        << "ParamCommandComment has name \"" << ActualCommandName.str() << "\", "
194           "expected \"" << CommandName.str() << "\"";
195
196  if (PCC->getDirection() != Direction)
197    return ::testing::AssertionFailure()
198        << "ParamCommandComment has direction " << PCC->getDirection() << ", "
199           "expected " << Direction;
200
201  if (PCC->isDirectionExplicit() != IsDirectionExplicit)
202    return ::testing::AssertionFailure()
203        << "ParamCommandComment has "
204        << (PCC->isDirectionExplicit() ? "explicit" : "implicit")
205        << " direction, "
206           "expected " << (IsDirectionExplicit ? "explicit" : "implicit");
207
208  StringRef ActualParamName = PCC->getParamName();
209  if (ActualParamName != ParamName)
210    return ::testing::AssertionFailure()
211        << "ParamCommandComment has name \"" << ActualParamName.str() << "\", "
212           "expected \"" << ParamName.str() << "\"";
213
214  Paragraph = PCC->getParagraph();
215
216  return ::testing::AssertionSuccess();
217}
218
219::testing::AssertionResult HasInlineCommandAt(const Comment *C,
220                                              size_t Idx,
221                                              InlineCommandComment *&ICC,
222                                              StringRef Name) {
223  ::testing::AssertionResult AR = GetChildAt(C, Idx, ICC);
224  if (!AR)
225    return AR;
226
227  StringRef ActualName = ICC->getCommandName();
228  if (ActualName != Name)
229    return ::testing::AssertionFailure()
230        << "InlineCommandComment has name \"" << ActualName.str() << "\", "
231           "expected \"" << Name.str() << "\"";
232
233  return ::testing::AssertionSuccess();
234}
235
236struct NoArgs {};
237
238::testing::AssertionResult HasInlineCommandAt(const Comment *C,
239                                              size_t Idx,
240                                              InlineCommandComment *&ICC,
241                                              StringRef Name,
242                                              NoArgs) {
243  ::testing::AssertionResult AR = HasInlineCommandAt(C, Idx, ICC, Name);
244  if (!AR)
245    return AR;
246
247  if (ICC->getNumArgs() != 0)
248    return ::testing::AssertionFailure()
249        << "InlineCommandComment has " << ICC->getNumArgs() << " arg(s), "
250           "expected 0";
251
252  return ::testing::AssertionSuccess();
253}
254
255::testing::AssertionResult HasInlineCommandAt(const Comment *C,
256                                              size_t Idx,
257                                              InlineCommandComment *&ICC,
258                                              StringRef Name,
259                                              StringRef Arg) {
260  ::testing::AssertionResult AR = HasInlineCommandAt(C, Idx, ICC, Name);
261  if (!AR)
262    return AR;
263
264  if (ICC->getNumArgs() != 1)
265    return ::testing::AssertionFailure()
266        << "InlineCommandComment has " << ICC->getNumArgs() << " arg(s), "
267           "expected 1";
268
269  StringRef ActualArg = ICC->getArgText(0);
270  if (ActualArg != Arg)
271    return ::testing::AssertionFailure()
272        << "InlineCommandComment has argument \"" << ActualArg.str() << "\", "
273           "expected \"" << Arg.str() << "\"";
274
275  return ::testing::AssertionSuccess();
276}
277
278::testing::AssertionResult HasHTMLStartTagAt(const Comment *C,
279                                             size_t Idx,
280                                             HTMLStartTagComment *&HST,
281                                             StringRef TagName) {
282  ::testing::AssertionResult AR = GetChildAt(C, Idx, HST);
283  if (!AR)
284    return AR;
285
286  StringRef ActualTagName = HST->getTagName();
287  if (ActualTagName != TagName)
288    return ::testing::AssertionFailure()
289        << "HTMLStartTagComment has name \"" << ActualTagName.str() << "\", "
290           "expected \"" << TagName.str() << "\"";
291
292  return ::testing::AssertionSuccess();
293}
294
295struct SelfClosing {};
296
297::testing::AssertionResult HasHTMLStartTagAt(const Comment *C,
298                                             size_t Idx,
299                                             HTMLStartTagComment *&HST,
300                                             StringRef TagName,
301                                             SelfClosing) {
302  ::testing::AssertionResult AR = HasHTMLStartTagAt(C, Idx, HST, TagName);
303  if (!AR)
304    return AR;
305
306  if (!HST->isSelfClosing())
307    return ::testing::AssertionFailure()
308        << "HTMLStartTagComment is not self-closing";
309
310  return ::testing::AssertionSuccess();
311}
312
313
314struct NoAttrs {};
315
316::testing::AssertionResult HasHTMLStartTagAt(const Comment *C,
317                                             size_t Idx,
318                                             HTMLStartTagComment *&HST,
319                                             StringRef TagName,
320                                             NoAttrs) {
321  ::testing::AssertionResult AR = HasHTMLStartTagAt(C, Idx, HST, TagName);
322  if (!AR)
323    return AR;
324
325  if (HST->isSelfClosing())
326    return ::testing::AssertionFailure()
327        << "HTMLStartTagComment is self-closing";
328
329  if (HST->getNumAttrs() != 0)
330    return ::testing::AssertionFailure()
331        << "HTMLStartTagComment has " << HST->getNumAttrs() << " attr(s), "
332           "expected 0";
333
334  return ::testing::AssertionSuccess();
335}
336
337::testing::AssertionResult HasHTMLStartTagAt(const Comment *C,
338                                             size_t Idx,
339                                             HTMLStartTagComment *&HST,
340                                             StringRef TagName,
341                                             StringRef AttrName,
342                                             StringRef AttrValue) {
343  ::testing::AssertionResult AR = HasHTMLStartTagAt(C, Idx, HST, TagName);
344  if (!AR)
345    return AR;
346
347  if (HST->isSelfClosing())
348    return ::testing::AssertionFailure()
349        << "HTMLStartTagComment is self-closing";
350
351  if (HST->getNumAttrs() != 1)
352    return ::testing::AssertionFailure()
353        << "HTMLStartTagComment has " << HST->getNumAttrs() << " attr(s), "
354           "expected 1";
355
356  StringRef ActualName = HST->getAttr(0).Name;
357  if (ActualName != AttrName)
358    return ::testing::AssertionFailure()
359        << "HTMLStartTagComment has attr \"" << ActualName.str() << "\", "
360           "expected \"" << AttrName.str() << "\"";
361
362  StringRef ActualValue = HST->getAttr(0).Value;
363  if (ActualValue != AttrValue)
364    return ::testing::AssertionFailure()
365        << "HTMLStartTagComment has attr value \"" << ActualValue.str() << "\", "
366           "expected \"" << AttrValue.str() << "\"";
367
368  return ::testing::AssertionSuccess();
369}
370
371::testing::AssertionResult HasHTMLEndTagAt(const Comment *C,
372                                           size_t Idx,
373                                           HTMLEndTagComment *&HET,
374                                           StringRef TagName) {
375  ::testing::AssertionResult AR = GetChildAt(C, Idx, HET);
376  if (!AR)
377    return AR;
378
379  StringRef ActualTagName = HET->getTagName();
380  if (ActualTagName != TagName)
381    return ::testing::AssertionFailure()
382        << "HTMLEndTagComment has name \"" << ActualTagName.str() << "\", "
383           "expected \"" << TagName.str() << "\"";
384
385  return ::testing::AssertionSuccess();
386}
387
388::testing::AssertionResult HasParagraphCommentAt(const Comment *C,
389                                                 size_t Idx,
390                                                 StringRef Text) {
391  ParagraphComment *PC;
392
393  {
394    ::testing::AssertionResult AR = GetChildAt(C, Idx, PC);
395    if (!AR)
396      return AR;
397  }
398
399  {
400    ::testing::AssertionResult AR = HasChildCount(PC, 1);
401    if (!AR)
402      return AR;
403  }
404
405  {
406    ::testing::AssertionResult AR = HasTextAt(PC, 0, Text);
407    if (!AR)
408      return AR;
409  }
410
411  return ::testing::AssertionSuccess();
412}
413
414::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
415                                              size_t Idx,
416                                              VerbatimBlockComment *&VBC,
417                                              StringRef Name,
418                                              StringRef CloseName) {
419  ::testing::AssertionResult AR = GetChildAt(C, Idx, VBC);
420  if (!AR)
421    return AR;
422
423  StringRef ActualName = VBC->getCommandName();
424  if (ActualName != Name)
425    return ::testing::AssertionFailure()
426        << "VerbatimBlockComment has name \"" << ActualName.str() << "\", "
427           "expected \"" << Name.str() << "\"";
428
429  StringRef ActualCloseName = VBC->getCloseName();
430  if (ActualCloseName != CloseName)
431    return ::testing::AssertionFailure()
432        << "VerbatimBlockComment has closing command name \""
433        << ActualCloseName.str() << "\", "
434           "expected \"" << CloseName.str() << "\"";
435
436  return ::testing::AssertionSuccess();
437}
438
439struct NoLines {};
440struct Lines {};
441
442::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
443                                              size_t Idx,
444                                              VerbatimBlockComment *&VBC,
445                                              StringRef Name,
446                                              StringRef CloseName,
447                                              NoLines) {
448  ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Idx, VBC, Name,
449                                                     CloseName);
450  if (!AR)
451    return AR;
452
453  if (VBC->getNumLines() != 0)
454    return ::testing::AssertionFailure()
455        << "VerbatimBlockComment has " << VBC->getNumLines() << " lines(s), "
456           "expected 0";
457
458  return ::testing::AssertionSuccess();
459}
460
461::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
462                                              size_t Idx,
463                                              VerbatimBlockComment *&VBC,
464                                              StringRef Name,
465                                              StringRef CloseName,
466                                              Lines,
467                                              StringRef Line0) {
468  ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Idx, VBC, Name,
469                                                     CloseName);
470  if (!AR)
471    return AR;
472
473  if (VBC->getNumLines() != 1)
474    return ::testing::AssertionFailure()
475        << "VerbatimBlockComment has " << VBC->getNumLines() << " lines(s), "
476           "expected 1";
477
478  StringRef ActualLine0 = VBC->getText(0);
479  if (ActualLine0 != Line0)
480    return ::testing::AssertionFailure()
481        << "VerbatimBlockComment has lines[0] \"" << ActualLine0.str() << "\", "
482           "expected \"" << Line0.str() << "\"";
483
484  return ::testing::AssertionSuccess();
485}
486
487::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
488                                              size_t Idx,
489                                              VerbatimBlockComment *&VBC,
490                                              StringRef Name,
491                                              StringRef CloseName,
492                                              Lines,
493                                              StringRef Line0,
494                                              StringRef Line1) {
495  ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Idx, VBC, Name,
496                                                     CloseName);
497  if (!AR)
498    return AR;
499
500  if (VBC->getNumLines() != 2)
501    return ::testing::AssertionFailure()
502        << "VerbatimBlockComment has " << VBC->getNumLines() << " lines(s), "
503           "expected 2";
504
505  StringRef ActualLine0 = VBC->getText(0);
506  if (ActualLine0 != Line0)
507    return ::testing::AssertionFailure()
508        << "VerbatimBlockComment has lines[0] \"" << ActualLine0.str() << "\", "
509           "expected \"" << Line0.str() << "\"";
510
511  StringRef ActualLine1 = VBC->getText(1);
512  if (ActualLine1 != Line1)
513    return ::testing::AssertionFailure()
514        << "VerbatimBlockComment has lines[1] \"" << ActualLine1.str() << "\", "
515           "expected \"" << Line1.str() << "\"";
516
517  return ::testing::AssertionSuccess();
518}
519
520::testing::AssertionResult HasVerbatimLineAt(const Comment *C,
521                                             size_t Idx,
522                                             VerbatimLineComment *&VLC,
523                                             StringRef Name,
524                                             StringRef Text) {
525  ::testing::AssertionResult AR = GetChildAt(C, Idx, VLC);
526  if (!AR)
527    return AR;
528
529  StringRef ActualName = VLC->getCommandName();
530  if (ActualName != Name)
531    return ::testing::AssertionFailure()
532        << "VerbatimLineComment has name \"" << ActualName.str() << "\", "
533           "expected \"" << Name.str() << "\"";
534
535  StringRef ActualText = VLC->getText();
536  if (ActualText != Text)
537    return ::testing::AssertionFailure()
538        << "VerbatimLineComment has text \"" << ActualText.str() << "\", "
539           "expected \"" << Text.str() << "\"";
540
541  return ::testing::AssertionSuccess();
542}
543
544
545TEST_F(CommentParserTest, Basic1) {
546  const char *Source = "//";
547
548  FullComment *FC = parseString(Source);
549  ASSERT_TRUE(HasChildCount(FC, 0));
550}
551
552TEST_F(CommentParserTest, Basic2) {
553  const char *Source = "// Meow";
554
555  FullComment *FC = parseString(Source);
556  ASSERT_TRUE(HasChildCount(FC, 1));
557
558  ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " Meow"));
559}
560
561TEST_F(CommentParserTest, Basic3) {
562  const char *Source =
563    "// Aaa\n"
564    "// Bbb";
565
566  FullComment *FC = parseString(Source);
567  ASSERT_TRUE(HasChildCount(FC, 1));
568
569  {
570    ParagraphComment *PC;
571    ASSERT_TRUE(GetChildAt(FC, 0, PC));
572
573    ASSERT_TRUE(HasChildCount(PC, 2));
574      ASSERT_TRUE(HasTextWithNewlineAt(PC, 0, " Aaa"));
575      ASSERT_TRUE(HasTextAt(PC, 1, " Bbb"));
576  }
577}
578
579TEST_F(CommentParserTest, Paragraph1) {
580  const char *Sources[] = {
581    "// Aaa\n"
582    "//\n"
583    "// Bbb",
584
585    "// Aaa\n"
586    "//\n"
587    "//\n"
588    "// Bbb",
589  };
590
591
592  for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
593    FullComment *FC = parseString(Sources[i]);
594    ASSERT_TRUE(HasChildCount(FC, 2));
595
596    ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " Aaa"));
597    ASSERT_TRUE(HasParagraphCommentAt(FC, 1, " Bbb"));
598  }
599}
600
601TEST_F(CommentParserTest, Paragraph2) {
602  const char *Source =
603    "// \\brief Aaa\n"
604    "//\n"
605    "// Bbb";
606
607  FullComment *FC = parseString(Source);
608  ASSERT_TRUE(HasChildCount(FC, 3));
609
610  ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
611  {
612    BlockCommandComment *BCC;
613    ParagraphComment *PC;
614    ASSERT_TRUE(HasBlockCommandAt(FC, 1, BCC, "brief", PC));
615
616    ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " Aaa"));
617  }
618  ASSERT_TRUE(HasParagraphCommentAt(FC, 2, " Bbb"));
619}
620
621TEST_F(CommentParserTest, Paragraph3) {
622  const char *Source = "// \\brief \\author";
623
624  FullComment *FC = parseString(Source);
625  ASSERT_TRUE(HasChildCount(FC, 3));
626
627  ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
628  {
629    BlockCommandComment *BCC;
630    ParagraphComment *PC;
631    ASSERT_TRUE(HasBlockCommandAt(FC, 1, BCC, "brief", PC));
632
633    ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " "));
634  }
635  {
636    BlockCommandComment *BCC;
637    ParagraphComment *PC;
638    ASSERT_TRUE(HasBlockCommandAt(FC, 2, BCC, "author", PC));
639
640    ASSERT_TRUE(GetChildAt(BCC, 0, PC));
641      ASSERT_TRUE(HasChildCount(PC, 0));
642  }
643}
644
645TEST_F(CommentParserTest, Paragraph4) {
646  const char *Source =
647    "// \\brief Aaa\n"
648    "// Bbb \\author\n"
649    "// Ccc";
650
651  FullComment *FC = parseString(Source);
652  ASSERT_TRUE(HasChildCount(FC, 3));
653
654  ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
655  {
656    BlockCommandComment *BCC;
657    ParagraphComment *PC;
658    ASSERT_TRUE(HasBlockCommandAt(FC, 1, BCC, "brief", PC));
659
660    ASSERT_TRUE(GetChildAt(BCC, 0, PC));
661      ASSERT_TRUE(HasChildCount(PC, 2));
662      ASSERT_TRUE(HasTextWithNewlineAt(PC, 0, " Aaa"));
663      ASSERT_TRUE(HasTextAt(PC, 1, " Bbb "));
664  }
665  {
666    BlockCommandComment *BCC;
667    ParagraphComment *PC;
668    ASSERT_TRUE(HasBlockCommandAt(FC, 2, BCC, "author", PC));
669
670    ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " Ccc"));
671  }
672}
673
674TEST_F(CommentParserTest, ParamCommand1) {
675  const char *Source =
676    "// \\param aaa\n"
677    "// \\param [in] aaa\n"
678    "// \\param [out] aaa\n"
679    "// \\param [in,out] aaa\n"
680    "// \\param [in, out] aaa\n";
681
682  FullComment *FC = parseString(Source);
683  ASSERT_TRUE(HasChildCount(FC, 6));
684
685  ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
686  {
687    ParamCommandComment *PCC;
688    ParagraphComment *PC;
689    ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param",
690                                  ParamCommandComment::In,
691                                  /* IsDirectionExplicit = */ false,
692                                  "aaa", PC));
693    ASSERT_TRUE(HasChildCount(PCC, 1));
694    ASSERT_TRUE(HasChildCount(PC, 1));
695      ASSERT_TRUE(HasTextAt(PC, 0, " "));
696  }
697  {
698    ParamCommandComment *PCC;
699    ParagraphComment *PC;
700    ASSERT_TRUE(HasParamCommandAt(FC, 2, PCC, "param",
701                                  ParamCommandComment::In,
702                                  /* IsDirectionExplicit = */ true,
703                                  "aaa", PC));
704    ASSERT_TRUE(HasChildCount(PCC, 1));
705    ASSERT_TRUE(HasChildCount(PC, 1));
706      ASSERT_TRUE(HasTextAt(PC, 0, " "));
707  }
708  {
709    ParamCommandComment *PCC;
710    ParagraphComment *PC;
711    ASSERT_TRUE(HasParamCommandAt(FC, 3, PCC, "param",
712                                  ParamCommandComment::Out,
713                                  /* IsDirectionExplicit = */ true,
714                                  "aaa", PC));
715    ASSERT_TRUE(HasChildCount(PCC, 1));
716    ASSERT_TRUE(HasChildCount(PC, 1));
717      ASSERT_TRUE(HasTextAt(PC, 0, " "));
718  }
719  {
720    ParamCommandComment *PCC;
721    ParagraphComment *PC;
722    ASSERT_TRUE(HasParamCommandAt(FC, 4, PCC, "param",
723                                  ParamCommandComment::InOut,
724                                  /* IsDirectionExplicit = */ true,
725                                  "aaa", PC));
726    ASSERT_TRUE(HasChildCount(PCC, 1));
727    ASSERT_TRUE(HasChildCount(PC, 1));
728      ASSERT_TRUE(HasTextAt(PC, 0, " "));
729  }
730  {
731    ParamCommandComment *PCC;
732    ParagraphComment *PC;
733    ASSERT_TRUE(HasParamCommandAt(FC, 5, PCC, "param",
734                                  ParamCommandComment::InOut,
735                                  /* IsDirectionExplicit = */ true,
736                                  "aaa", PC));
737    ASSERT_TRUE(HasChildCount(PCC, 1));
738    ASSERT_TRUE(HasChildCount(PC, 0));
739  }
740}
741
742TEST_F(CommentParserTest, InlineCommand1) {
743  const char *Source = "// \\c";
744
745  FullComment *FC = parseString(Source);
746  ASSERT_TRUE(HasChildCount(FC, 1));
747
748  {
749    ParagraphComment *PC;
750    InlineCommandComment *ICC;
751    ASSERT_TRUE(GetChildAt(FC, 0, PC));
752
753    ASSERT_TRUE(HasChildCount(PC, 2));
754      ASSERT_TRUE(HasTextAt(PC, 0, " "));
755      ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", NoArgs()));
756  }
757}
758
759TEST_F(CommentParserTest, InlineCommand2) {
760  const char *Source = "// \\c ";
761
762  FullComment *FC = parseString(Source);
763  ASSERT_TRUE(HasChildCount(FC, 1));
764
765  {
766    ParagraphComment *PC;
767    InlineCommandComment *ICC;
768    ASSERT_TRUE(GetChildAt(FC, 0, PC));
769
770    ASSERT_TRUE(HasChildCount(PC, 3));
771      ASSERT_TRUE(HasTextAt(PC, 0, " "));
772      ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", NoArgs()));
773      ASSERT_TRUE(HasTextAt(PC, 2, " "));
774  }
775}
776
777TEST_F(CommentParserTest, InlineCommand3) {
778  const char *Source = "// \\c aaa\n";
779
780  FullComment *FC = parseString(Source);
781  ASSERT_TRUE(HasChildCount(FC, 1));
782
783  {
784    ParagraphComment *PC;
785    InlineCommandComment *ICC;
786    ASSERT_TRUE(GetChildAt(FC, 0, PC));
787
788    ASSERT_TRUE(HasChildCount(PC, 2));
789      ASSERT_TRUE(HasTextAt(PC, 0, " "));
790      ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", "aaa"));
791  }
792}
793
794TEST_F(CommentParserTest, InlineCommand4) {
795  const char *Source = "// \\c aaa bbb";
796
797  FullComment *FC = parseString(Source);
798  ASSERT_TRUE(HasChildCount(FC, 1));
799
800  {
801    ParagraphComment *PC;
802    InlineCommandComment *ICC;
803    ASSERT_TRUE(GetChildAt(FC, 0, PC));
804
805    ASSERT_TRUE(HasChildCount(PC, 3));
806      ASSERT_TRUE(HasTextAt(PC, 0, " "));
807      ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", "aaa"));
808      ASSERT_TRUE(HasTextAt(PC, 2, " bbb"));
809  }
810}
811
812TEST_F(CommentParserTest, InlineCommand5) {
813  const char *Source = "// \\unknown aaa\n";
814
815  FullComment *FC = parseString(Source);
816  ASSERT_TRUE(HasChildCount(FC, 1));
817
818  {
819    ParagraphComment *PC;
820    InlineCommandComment *ICC;
821    ASSERT_TRUE(GetChildAt(FC, 0, PC));
822
823    ASSERT_TRUE(HasChildCount(PC, 3));
824      ASSERT_TRUE(HasTextAt(PC, 0, " "));
825      ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "unknown", NoArgs()));
826      ASSERT_TRUE(HasTextAt(PC, 2, " aaa"));
827  }
828}
829
830TEST_F(CommentParserTest, HTML1) {
831  const char *Sources[] = {
832    "// <a",
833    "// <a>",
834    "// <a >"
835  };
836
837  for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
838    FullComment *FC = parseString(Sources[i]);
839    ASSERT_TRUE(HasChildCount(FC, 1));
840
841    {
842      ParagraphComment *PC;
843      HTMLStartTagComment *HST;
844      ASSERT_TRUE(GetChildAt(FC, 0, PC));
845
846      ASSERT_TRUE(HasChildCount(PC, 2));
847        ASSERT_TRUE(HasTextAt(PC, 0, " "));
848        ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "a", NoAttrs()));
849    }
850  }
851}
852
853TEST_F(CommentParserTest, HTML2) {
854  const char *Sources[] = {
855    "// <br/>",
856    "// <br />"
857  };
858
859  for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
860    FullComment *FC = parseString(Sources[i]);
861    ASSERT_TRUE(HasChildCount(FC, 1));
862
863    {
864      ParagraphComment *PC;
865      HTMLStartTagComment *HST;
866      ASSERT_TRUE(GetChildAt(FC, 0, PC));
867
868      ASSERT_TRUE(HasChildCount(PC, 2));
869        ASSERT_TRUE(HasTextAt(PC, 0, " "));
870        ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "br", SelfClosing()));
871    }
872  }
873}
874
875TEST_F(CommentParserTest, HTML3) {
876  const char *Sources[] = {
877    "// <a href",
878    "// <a href ",
879    "// <a href>",
880    "// <a href >",
881  };
882
883  for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
884    FullComment *FC = parseString(Sources[i]);
885    ASSERT_TRUE(HasChildCount(FC, 1));
886
887    {
888      ParagraphComment *PC;
889      HTMLStartTagComment *HST;
890      ASSERT_TRUE(GetChildAt(FC, 0, PC));
891
892      ASSERT_TRUE(HasChildCount(PC, 2));
893        ASSERT_TRUE(HasTextAt(PC, 0, " "));
894        ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "a", "href", ""));
895    }
896  }
897}
898
899TEST_F(CommentParserTest, HTML4) {
900  const char *Sources[] = {
901    "// <a href=\"bbb\"",
902    "// <a href=\"bbb\">",
903  };
904
905  for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
906    FullComment *FC = parseString(Sources[i]);
907    ASSERT_TRUE(HasChildCount(FC, 1));
908
909    {
910      ParagraphComment *PC;
911      HTMLStartTagComment *HST;
912      ASSERT_TRUE(GetChildAt(FC, 0, PC));
913
914      ASSERT_TRUE(HasChildCount(PC, 2));
915        ASSERT_TRUE(HasTextAt(PC, 0, " "));
916        ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "a", "href", "bbb"));
917    }
918  }
919}
920
921TEST_F(CommentParserTest, HTML5) {
922  const char *Sources[] = {
923    "// </a",
924    "// </a>",
925    "// </a >"
926  };
927
928  for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
929    FullComment *FC = parseString(Sources[i]);
930    ASSERT_TRUE(HasChildCount(FC, 1));
931
932    {
933      ParagraphComment *PC;
934      HTMLEndTagComment *HET;
935      ASSERT_TRUE(GetChildAt(FC, 0, PC));
936
937      ASSERT_TRUE(HasChildCount(PC, 2));
938        ASSERT_TRUE(HasTextAt(PC, 0, " "));
939        ASSERT_TRUE(HasHTMLEndTagAt(PC, 1, HET, "a"));
940    }
941  }
942}
943
944TEST_F(CommentParserTest, HTML6) {
945  const char *Source =
946    "// <pre>\n"
947    "// Aaa\n"
948    "// Bbb\n"
949    "// </pre>\n";
950
951  FullComment *FC = parseString(Source);
952  ASSERT_TRUE(HasChildCount(FC, 1));
953
954  {
955    ParagraphComment *PC;
956    HTMLStartTagComment *HST;
957    HTMLEndTagComment *HET;
958    ASSERT_TRUE(GetChildAt(FC, 0, PC));
959
960    ASSERT_TRUE(HasChildCount(PC, 6));
961      ASSERT_TRUE(HasTextAt(PC, 0, " "));
962      ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "pre", NoAttrs()));
963      ASSERT_TRUE(HasTextWithNewlineAt(PC, 2, " Aaa"));
964      ASSERT_TRUE(HasTextWithNewlineAt(PC, 3, " Bbb"));
965      ASSERT_TRUE(HasTextAt(PC, 4, " "));
966      ASSERT_TRUE(HasHTMLEndTagAt(PC, 5, HET, "pre"));
967  }
968}
969
970TEST_F(CommentParserTest, VerbatimBlock1) {
971  const char *Source = "// \\verbatim\\endverbatim\n";
972
973  FullComment *FC = parseString(Source);
974  ASSERT_TRUE(HasChildCount(FC, 2));
975
976  ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
977  {
978    VerbatimBlockComment *VCC;
979    ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VCC, "verbatim", "endverbatim",
980                                   NoLines()));
981  }
982}
983
984TEST_F(CommentParserTest, VerbatimBlock2) {
985  const char *Source = "// \\verbatim Aaa \\endverbatim\n";
986
987  FullComment *FC = parseString(Source);
988  ASSERT_TRUE(HasChildCount(FC, 2));
989
990  ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
991  {
992    VerbatimBlockComment *VBC;
993    ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "endverbatim",
994                                   Lines(), " Aaa "));
995  }
996}
997
998TEST_F(CommentParserTest, VerbatimBlock3) {
999  const char *Source = "// \\verbatim Aaa\n";
1000
1001  FullComment *FC = parseString(Source);
1002  ASSERT_TRUE(HasChildCount(FC, 2));
1003
1004  ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1005  {
1006    VerbatimBlockComment *VBC;
1007    ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "",
1008                                   Lines(), " Aaa"));
1009  }
1010}
1011
1012TEST_F(CommentParserTest, VerbatimBlock4) {
1013  const char *Source =
1014    "//\\verbatim\n"
1015    "//\\endverbatim\n";
1016
1017  FullComment *FC = parseString(Source);
1018  ASSERT_TRUE(HasChildCount(FC, 1));
1019
1020  {
1021    VerbatimBlockComment *VBC;
1022    ASSERT_TRUE(HasVerbatimBlockAt(FC, 0, VBC, "verbatim", "endverbatim",
1023                                   NoLines()));
1024  }
1025}
1026
1027TEST_F(CommentParserTest, VerbatimBlock5) {
1028  const char *Sources[] = {
1029    "//\\verbatim\n"
1030    "// Aaa\n"
1031    "//\\endverbatim\n",
1032
1033    "/*\\verbatim\n"
1034    " * Aaa\n"
1035    " *\\endverbatim*/"
1036  };
1037
1038  for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
1039    FullComment *FC = parseString(Sources[i]);
1040    ASSERT_TRUE(HasChildCount(FC, 1));
1041
1042    {
1043      VerbatimBlockComment *VBC;
1044      ASSERT_TRUE(HasVerbatimBlockAt(FC, 0, VBC, "verbatim", "endverbatim",
1045                                     Lines(), " Aaa"));
1046    }
1047  }
1048}
1049
1050TEST_F(CommentParserTest, VerbatimBlock6) {
1051  const char *Sources[] = {
1052    "// \\verbatim\n"
1053    "// Aaa\n"
1054    "// \\endverbatim\n",
1055
1056    "/* \\verbatim\n"
1057    " * Aaa\n"
1058    " * \\endverbatim*/"
1059  };
1060
1061  for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
1062    FullComment *FC = parseString(Sources[i]);
1063    ASSERT_TRUE(HasChildCount(FC, 2));
1064
1065    ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1066    {
1067      VerbatimBlockComment *VBC;
1068      ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "endverbatim",
1069                                     Lines(), " Aaa"));
1070    }
1071  }
1072}
1073
1074TEST_F(CommentParserTest, VerbatimBlock7) {
1075  const char *Sources[] = {
1076    "// \\verbatim\n"
1077    "// Aaa\n"
1078    "// Bbb\n"
1079    "// \\endverbatim\n",
1080
1081    "/* \\verbatim\n"
1082    " * Aaa\n"
1083    " * Bbb\n"
1084    " * \\endverbatim*/"
1085  };
1086
1087  for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
1088    FullComment *FC = parseString(Sources[i]);
1089    ASSERT_TRUE(HasChildCount(FC, 2));
1090
1091    ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1092    {
1093      VerbatimBlockComment *VBC;
1094      ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "endverbatim",
1095                                     Lines(), " Aaa", " Bbb"));
1096    }
1097  }
1098}
1099
1100TEST_F(CommentParserTest, VerbatimBlock8) {
1101  const char *Sources[] = {
1102    "// \\verbatim\n"
1103    "// Aaa\n"
1104    "//\n"
1105    "// Bbb\n"
1106    "// \\endverbatim\n",
1107
1108    "/* \\verbatim\n"
1109    " * Aaa\n"
1110    " *\n"
1111    " * Bbb\n"
1112    " * \\endverbatim*/"
1113  };
1114  for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
1115    FullComment *FC = parseString(Sources[i]);
1116    ASSERT_TRUE(HasChildCount(FC, 2));
1117
1118    ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1119    {
1120      VerbatimBlockComment *VBC;
1121      ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "endverbatim"));
1122      ASSERT_EQ(3U, VBC->getNumLines());
1123      ASSERT_EQ(" Aaa", VBC->getText(0));
1124      ASSERT_EQ("",     VBC->getText(1));
1125      ASSERT_EQ(" Bbb", VBC->getText(2));
1126    }
1127  }
1128}
1129
1130TEST_F(CommentParserTest, VerbatimLine1) {
1131  const char *Sources[] = {
1132    "// \\fn",
1133    "// \\fn\n"
1134  };
1135
1136  for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
1137    FullComment *FC = parseString(Sources[i]);
1138    ASSERT_TRUE(HasChildCount(FC, 2));
1139
1140    ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1141    {
1142      VerbatimLineComment *VLC;
1143      ASSERT_TRUE(HasVerbatimLineAt(FC, 1, VLC, "fn", ""));
1144    }
1145  }
1146}
1147
1148TEST_F(CommentParserTest, VerbatimLine2) {
1149  const char *Sources[] = {
1150    "/// \\fn void *foo(const char *zzz = \"\\$\");\n//",
1151    "/** \\fn void *foo(const char *zzz = \"\\$\");*/"
1152  };
1153
1154  for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
1155    FullComment *FC = parseString(Sources[i]);
1156    ASSERT_TRUE(HasChildCount(FC, 2));
1157
1158    ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1159    {
1160      VerbatimLineComment *VLC;
1161      ASSERT_TRUE(HasVerbatimLineAt(FC, 1, VLC, "fn",
1162                  " void *foo(const char *zzz = \"\\$\");"));
1163    }
1164  }
1165}
1166
1167} // unnamed namespace
1168
1169} // end namespace comments
1170} // end namespace clang
1171
1172