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