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