Clang Project

clang_source_code/unittests/AST/CommentParser.cpp
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
23using namespace llvm;
24using namespace clang;
25
26namespace clang {
27namespace comments {
28
29namespace {
30
31const bool DEBUG = true;
32
33class CommentParserTest : public ::testing::Test {
34protected:
35  CommentParserTest()
36    : FileMgr(FileMgrOpts),
37      DiagID(new DiagnosticIDs()),
38      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
39      SourceMgr(Diags, FileMgr),
40      Traits(Allocator, CommentOptions()) {
41  }
42
43  FileSystemOptions FileMgrOpts;
44  FileManager FileMgr;
45  IntrusiveRefCntPtr<DiagnosticIDsDiagID;
46  DiagnosticsEngine Diags;
47  SourceManager SourceMgr;
48  llvm::BumpPtrAllocator Allocator;
49  CommandTraits Traits;
50
51  FullComment *parseString(const char *Source);
52};
53
54FullComment *CommentParserTest::parseString(const char *Source) {
55  std::unique_ptr<MemoryBufferBuf = 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 (DEBUG) {
66    llvm::errs() << "=== Source:\n" << Source << "\n=== AST:\n";
67    FC->dump(llvm::errs(), &Traits, &SourceMgr);
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
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
90template <typename T>
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
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
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
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
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
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
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
279struct NoArgs {};
280
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
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
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
340struct SelfClosing {};
341
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
359struct NoAttrs {};
360
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
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
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
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
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
485struct NoLines {};
486struct Lines {};
487
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
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
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
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
595TEST_F(CommentParserTest, Basic1) {
596  const char *Source = "//";
597
598  FullComment *FC = parseString(Source);
599  ASSERT_TRUE(HasChildCount(FC, 0));
600}
601
602TEST_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
611TEST_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(FC0PC));
622
623    ASSERT_TRUE(HasChildCount(PC, 2));
624      ASSERT_TRUE(HasTextWithNewlineAt(PC, 0" Aaa"));
625      ASSERT_TRUE(HasTextAt(PC, 1" Bbb"));
626  }
627}
628
629TEST_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
676TEST_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
696TEST_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(BCC0PC));
716      ASSERT_TRUE(HasChildCount(PC, 0));
717  }
718}
719
720TEST_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(BCC0PC));
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
749TEST_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
768TEST_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
793TEST_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
822TEST_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
852TEST_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
882TEST_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
913TEST_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
939TEST_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
966TEST_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
989TEST_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(FC0PC));
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
1006TEST_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(FC0PC));
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
1024TEST_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(FC0PC));
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
1041TEST_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(FC0PC));
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
1059TEST_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(FC0PC));
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
1077TEST_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
1100TEST_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
1122TEST_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
1146TEST_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
1168TEST_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
1191TEST_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(FC0PC));
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
1217TEST_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
1232TEST_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
1247TEST_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
1261TEST_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
1277TEST_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
1301TEST_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
1326TEST_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
1353TEST_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
1384TEST_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
1402TEST_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
1421TEST_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