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