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 MY_DEBUG = true;
32
33class CommentParserTest : public ::testing::Test {
34protected:
35 CommentParserTest()
36 : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
37 Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
38 SourceMgr(Diags, FileMgr), Traits(Allocator, CommentOptions()) {}
39
40 FileSystemOptions FileMgrOpts;
41 FileManager FileMgr;
42 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
43 DiagnosticOptions DiagOpts;
44 DiagnosticsEngine Diags;
45 SourceManager SourceMgr;
46 llvm::BumpPtrAllocator Allocator;
47 CommandTraits Traits;
48
49 FullComment *parseString(const char *Source);
50};
51
52FullComment *CommentParserTest::parseString(const char *Source) {
53 std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(InputData: Source);
54 FileID File = SourceMgr.createFileID(Buffer: std::move(Buf));
55 SourceLocation Begin = SourceMgr.getLocForStartOfFile(FID: File);
56
57 Lexer L(Allocator, Diags, Traits, Begin, Source, Source + strlen(Source));
58
59 Sema S(Allocator, SourceMgr, Diags, Traits, /*PP=*/ nullptr);
60 Parser P(L, S, Allocator, SourceMgr, Diags, Traits);
61 FullComment *FC = P.parseFullComment();
62
63 if (MY_DEBUG) {
64 llvm::errs() << "=== Source:\n" << Source << "\n=== AST:\n";
65 FC->dump();
66 }
67
68 Token Tok;
69 L.lex(T&: Tok);
70 if (Tok.is(K: tok::eof))
71 return FC;
72 else
73 return nullptr;
74}
75
76::testing::AssertionResult HasChildCount(const Comment *C, size_t Count) {
77 if (!C)
78 return ::testing::AssertionFailure() << "Comment is NULL";
79
80 if (Count != C->child_count())
81 return ::testing::AssertionFailure()
82 << "Count = " << Count
83 << ", child_count = " << C->child_count();
84
85 return ::testing::AssertionSuccess();
86}
87
88template <typename T>
89::testing::AssertionResult GetChildAt(const Comment *C,
90 size_t Idx,
91 T *&Child) {
92 if (!C)
93 return ::testing::AssertionFailure() << "Comment is NULL";
94
95 if (Idx >= C->child_count())
96 return ::testing::AssertionFailure()
97 << "Idx out of range. Idx = " << Idx
98 << ", child_count = " << C->child_count();
99
100 Comment::child_iterator I = C->child_begin() + Idx;
101 Comment *CommentChild = *I;
102 if (!CommentChild)
103 return ::testing::AssertionFailure() << "Child is NULL";
104
105 Child = dyn_cast<T>(CommentChild);
106 if (!Child)
107 return ::testing::AssertionFailure()
108 << "Child is not of requested type, but a "
109 << CommentChild->getCommentKindName();
110
111 return ::testing::AssertionSuccess();
112}
113
114::testing::AssertionResult HasTextAt(const Comment *C,
115 size_t Idx,
116 StringRef Text) {
117 TextComment *TC;
118 ::testing::AssertionResult AR = GetChildAt(C, Idx, Child&: TC);
119 if (!AR)
120 return AR;
121
122 StringRef ActualText = TC->getText();
123 if (ActualText != Text)
124 return ::testing::AssertionFailure()
125 << "TextComment has text \"" << ActualText.str() << "\", "
126 "expected \"" << Text.str() << "\"";
127
128 if (TC->hasTrailingNewline())
129 return ::testing::AssertionFailure()
130 << "TextComment has a trailing newline";
131
132 return ::testing::AssertionSuccess();
133}
134
135::testing::AssertionResult HasTextWithNewlineAt(const Comment *C,
136 size_t Idx,
137 StringRef Text) {
138 TextComment *TC;
139 ::testing::AssertionResult AR = GetChildAt(C, Idx, Child&: TC);
140 if (!AR)
141 return AR;
142
143 StringRef ActualText = TC->getText();
144 if (ActualText != Text)
145 return ::testing::AssertionFailure()
146 << "TextComment has text \"" << ActualText.str() << "\", "
147 "expected \"" << Text.str() << "\"";
148
149 if (!TC->hasTrailingNewline())
150 return ::testing::AssertionFailure()
151 << "TextComment has no trailing newline";
152
153 return ::testing::AssertionSuccess();
154}
155
156::testing::AssertionResult HasBlockCommandAt(const Comment *C,
157 const CommandTraits &Traits,
158 size_t Idx,
159 BlockCommandComment *&BCC,
160 StringRef Name,
161 ParagraphComment *&Paragraph) {
162 ::testing::AssertionResult AR = GetChildAt(C, Idx, Child&: BCC);
163 if (!AR)
164 return AR;
165
166 StringRef ActualName = BCC->getCommandName(Traits);
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
178HasParamCommandAt(const Comment *C, const CommandTraits &Traits, size_t Idx,
179 ParamCommandComment *&PCC, StringRef CommandName,
180 ParamCommandPassDirection Direction, bool IsDirectionExplicit,
181 StringRef ParamName, ParagraphComment *&Paragraph) {
182 ::testing::AssertionResult AR = GetChildAt(C, Idx, Child&: PCC);
183 if (!AR)
184 return AR;
185
186 StringRef ActualCommandName = PCC->getCommandName(Traits);
187 if (ActualCommandName != CommandName)
188 return ::testing::AssertionFailure()
189 << "ParamCommandComment has name \"" << ActualCommandName.str() << "\", "
190 "expected \"" << CommandName.str() << "\"";
191
192 if (PCC->getDirection() != Direction)
193 return ::testing::AssertionFailure()
194 << "ParamCommandComment has direction "
195 << llvm::to_underlying(E: PCC->getDirection()) << ", expected "
196 << llvm::to_underlying(E: Direction);
197
198 if (PCC->isDirectionExplicit() != IsDirectionExplicit)
199 return ::testing::AssertionFailure()
200 << "ParamCommandComment has "
201 << (PCC->isDirectionExplicit() ? "explicit" : "implicit")
202 << " direction, "
203 "expected " << (IsDirectionExplicit ? "explicit" : "implicit");
204
205 if (!ParamName.empty() && !PCC->hasParamName())
206 return ::testing::AssertionFailure()
207 << "ParamCommandComment has no parameter name";
208
209 StringRef ActualParamName = PCC->hasParamName() ? PCC->getParamNameAsWritten() : "";
210 if (ActualParamName != ParamName)
211 return ::testing::AssertionFailure()
212 << "ParamCommandComment has parameter name \"" << ActualParamName.str()
213 << "\", "
214 "expected \"" << ParamName.str() << "\"";
215
216 Paragraph = PCC->getParagraph();
217
218 return ::testing::AssertionSuccess();
219}
220
221::testing::AssertionResult HasTParamCommandAt(
222 const Comment *C,
223 const CommandTraits &Traits,
224 size_t Idx,
225 TParamCommandComment *&TPCC,
226 StringRef CommandName,
227 StringRef ParamName,
228 ParagraphComment *&Paragraph) {
229 ::testing::AssertionResult AR = GetChildAt(C, Idx, Child&: TPCC);
230 if (!AR)
231 return AR;
232
233 StringRef ActualCommandName = TPCC->getCommandName(Traits);
234 if (ActualCommandName != CommandName)
235 return ::testing::AssertionFailure()
236 << "TParamCommandComment has name \"" << ActualCommandName.str() << "\", "
237 "expected \"" << CommandName.str() << "\"";
238
239 if (!ParamName.empty() && !TPCC->hasParamName())
240 return ::testing::AssertionFailure()
241 << "TParamCommandComment has no parameter name";
242
243 StringRef ActualParamName = TPCC->hasParamName() ? TPCC->getParamNameAsWritten() : "";
244 if (ActualParamName != ParamName)
245 return ::testing::AssertionFailure()
246 << "TParamCommandComment has parameter name \"" << ActualParamName.str()
247 << "\", "
248 "expected \"" << ParamName.str() << "\"";
249
250 Paragraph = TPCC->getParagraph();
251
252 return ::testing::AssertionSuccess();
253}
254
255::testing::AssertionResult HasInlineCommandAt(const Comment *C,
256 const CommandTraits &Traits,
257 size_t Idx,
258 InlineCommandComment *&ICC,
259 StringRef Name) {
260 ::testing::AssertionResult AR = GetChildAt(C, Idx, Child&: ICC);
261 if (!AR)
262 return AR;
263
264 StringRef ActualName = ICC->getCommandName(Traits);
265 if (ActualName != Name)
266 return ::testing::AssertionFailure()
267 << "InlineCommandComment has name \"" << ActualName.str() << "\", "
268 "expected \"" << Name.str() << "\"";
269
270 return ::testing::AssertionSuccess();
271}
272
273struct NoArgs {};
274
275::testing::AssertionResult HasInlineCommandAt(const Comment *C,
276 const CommandTraits &Traits,
277 size_t Idx,
278 InlineCommandComment *&ICC,
279 StringRef Name,
280 NoArgs) {
281 ::testing::AssertionResult AR = HasInlineCommandAt(C, Traits, Idx, ICC, Name);
282 if (!AR)
283 return AR;
284
285 if (ICC->getNumArgs() != 0)
286 return ::testing::AssertionFailure()
287 << "InlineCommandComment has " << ICC->getNumArgs() << " arg(s), "
288 "expected 0";
289
290 return ::testing::AssertionSuccess();
291}
292
293::testing::AssertionResult HasInlineCommandAt(const Comment *C,
294 const CommandTraits &Traits,
295 size_t Idx,
296 InlineCommandComment *&ICC,
297 StringRef Name,
298 StringRef Arg) {
299 ::testing::AssertionResult AR = HasInlineCommandAt(C, Traits, Idx, ICC, Name);
300 if (!AR)
301 return AR;
302
303 if (ICC->getNumArgs() != 1)
304 return ::testing::AssertionFailure()
305 << "InlineCommandComment has " << ICC->getNumArgs() << " arg(s), "
306 "expected 1";
307
308 StringRef ActualArg = ICC->getArgText(Idx: 0);
309 if (ActualArg != Arg)
310 return ::testing::AssertionFailure()
311 << "InlineCommandComment has argument \"" << ActualArg.str() << "\", "
312 "expected \"" << Arg.str() << "\"";
313
314 return ::testing::AssertionSuccess();
315}
316
317::testing::AssertionResult HasHTMLStartTagAt(const Comment *C,
318 size_t Idx,
319 HTMLStartTagComment *&HST,
320 StringRef TagName) {
321 ::testing::AssertionResult AR = GetChildAt(C, Idx, Child&: HST);
322 if (!AR)
323 return AR;
324
325 StringRef ActualTagName = HST->getTagName();
326 if (ActualTagName != TagName)
327 return ::testing::AssertionFailure()
328 << "HTMLStartTagComment has name \"" << ActualTagName.str() << "\", "
329 "expected \"" << TagName.str() << "\"";
330
331 return ::testing::AssertionSuccess();
332}
333
334struct SelfClosing {};
335
336::testing::AssertionResult HasHTMLStartTagAt(const Comment *C,
337 size_t Idx,
338 HTMLStartTagComment *&HST,
339 StringRef TagName,
340 SelfClosing) {
341 ::testing::AssertionResult AR = HasHTMLStartTagAt(C, Idx, HST, TagName);
342 if (!AR)
343 return AR;
344
345 if (!HST->isSelfClosing())
346 return ::testing::AssertionFailure()
347 << "HTMLStartTagComment is not self-closing";
348
349 return ::testing::AssertionSuccess();
350}
351
352
353struct NoAttrs {};
354
355::testing::AssertionResult HasHTMLStartTagAt(const Comment *C,
356 size_t Idx,
357 HTMLStartTagComment *&HST,
358 StringRef TagName,
359 NoAttrs) {
360 ::testing::AssertionResult AR = HasHTMLStartTagAt(C, Idx, HST, TagName);
361 if (!AR)
362 return AR;
363
364 if (HST->isSelfClosing())
365 return ::testing::AssertionFailure()
366 << "HTMLStartTagComment is self-closing";
367
368 if (HST->getNumAttrs() != 0)
369 return ::testing::AssertionFailure()
370 << "HTMLStartTagComment has " << HST->getNumAttrs() << " attr(s), "
371 "expected 0";
372
373 return ::testing::AssertionSuccess();
374}
375
376::testing::AssertionResult HasHTMLStartTagAt(const Comment *C,
377 size_t Idx,
378 HTMLStartTagComment *&HST,
379 StringRef TagName,
380 StringRef AttrName,
381 StringRef AttrValue) {
382 ::testing::AssertionResult AR = HasHTMLStartTagAt(C, Idx, HST, TagName);
383 if (!AR)
384 return AR;
385
386 if (HST->isSelfClosing())
387 return ::testing::AssertionFailure()
388 << "HTMLStartTagComment is self-closing";
389
390 if (HST->getNumAttrs() != 1)
391 return ::testing::AssertionFailure()
392 << "HTMLStartTagComment has " << HST->getNumAttrs() << " attr(s), "
393 "expected 1";
394
395 StringRef ActualName = HST->getAttr(Idx: 0).Name;
396 if (ActualName != AttrName)
397 return ::testing::AssertionFailure()
398 << "HTMLStartTagComment has attr \"" << ActualName.str() << "\", "
399 "expected \"" << AttrName.str() << "\"";
400
401 StringRef ActualValue = HST->getAttr(Idx: 0).Value;
402 if (ActualValue != AttrValue)
403 return ::testing::AssertionFailure()
404 << "HTMLStartTagComment has attr value \"" << ActualValue.str() << "\", "
405 "expected \"" << AttrValue.str() << "\"";
406
407 return ::testing::AssertionSuccess();
408}
409
410::testing::AssertionResult HasHTMLEndTagAt(const Comment *C,
411 size_t Idx,
412 HTMLEndTagComment *&HET,
413 StringRef TagName) {
414 ::testing::AssertionResult AR = GetChildAt(C, Idx, Child&: HET);
415 if (!AR)
416 return AR;
417
418 StringRef ActualTagName = HET->getTagName();
419 if (ActualTagName != TagName)
420 return ::testing::AssertionFailure()
421 << "HTMLEndTagComment has name \"" << ActualTagName.str() << "\", "
422 "expected \"" << TagName.str() << "\"";
423
424 return ::testing::AssertionSuccess();
425}
426
427::testing::AssertionResult HasParagraphCommentAt(const Comment *C,
428 size_t Idx,
429 StringRef Text) {
430 ParagraphComment *PC;
431
432 {
433 ::testing::AssertionResult AR = GetChildAt(C, Idx, Child&: PC);
434 if (!AR)
435 return AR;
436 }
437
438 {
439 ::testing::AssertionResult AR = HasChildCount(PC, 1);
440 if (!AR)
441 return AR;
442 }
443
444 {
445 ::testing::AssertionResult AR = HasTextAt(PC, 0, Text);
446 if (!AR)
447 return AR;
448 }
449
450 return ::testing::AssertionSuccess();
451}
452
453::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
454 const CommandTraits &Traits,
455 size_t Idx,
456 VerbatimBlockComment *&VBC,
457 StringRef Name,
458 StringRef CloseName) {
459 ::testing::AssertionResult AR = GetChildAt(C, Idx, Child&: VBC);
460 if (!AR)
461 return AR;
462
463 StringRef ActualName = VBC->getCommandName(Traits);
464 if (ActualName != Name)
465 return ::testing::AssertionFailure()
466 << "VerbatimBlockComment has name \"" << ActualName.str() << "\", "
467 "expected \"" << Name.str() << "\"";
468
469 StringRef ActualCloseName = VBC->getCloseName();
470 if (ActualCloseName != CloseName)
471 return ::testing::AssertionFailure()
472 << "VerbatimBlockComment has closing command name \""
473 << ActualCloseName.str() << "\", "
474 "expected \"" << CloseName.str() << "\"";
475
476 return ::testing::AssertionSuccess();
477}
478
479struct NoLines {};
480struct Lines {};
481
482::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
483 const CommandTraits &Traits,
484 size_t Idx,
485 VerbatimBlockComment *&VBC,
486 StringRef Name,
487 StringRef CloseName,
488 NoLines) {
489 ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Traits, Idx, VBC, Name,
490 CloseName);
491 if (!AR)
492 return AR;
493
494 if (VBC->getNumLines() != 0)
495 return ::testing::AssertionFailure()
496 << "VerbatimBlockComment has " << VBC->getNumLines() << " lines(s), "
497 "expected 0";
498
499 return ::testing::AssertionSuccess();
500}
501
502::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
503 const CommandTraits &Traits,
504 size_t Idx,
505 VerbatimBlockComment *&VBC,
506 StringRef Name,
507 StringRef CloseName,
508 Lines,
509 StringRef Line0) {
510 ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Traits, Idx, VBC, Name,
511 CloseName);
512 if (!AR)
513 return AR;
514
515 if (VBC->getNumLines() != 1)
516 return ::testing::AssertionFailure()
517 << "VerbatimBlockComment has " << VBC->getNumLines() << " lines(s), "
518 "expected 1";
519
520 StringRef ActualLine0 = VBC->getText(LineIdx: 0);
521 if (ActualLine0 != Line0)
522 return ::testing::AssertionFailure()
523 << "VerbatimBlockComment has lines[0] \"" << ActualLine0.str() << "\", "
524 "expected \"" << Line0.str() << "\"";
525
526 return ::testing::AssertionSuccess();
527}
528
529::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
530 const CommandTraits &Traits,
531 size_t Idx,
532 VerbatimBlockComment *&VBC,
533 StringRef Name,
534 StringRef CloseName,
535 Lines,
536 StringRef Line0,
537 StringRef Line1) {
538 ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Traits, Idx, VBC, Name,
539 CloseName);
540 if (!AR)
541 return AR;
542
543 if (VBC->getNumLines() != 2)
544 return ::testing::AssertionFailure()
545 << "VerbatimBlockComment has " << VBC->getNumLines() << " lines(s), "
546 "expected 2";
547
548 StringRef ActualLine0 = VBC->getText(LineIdx: 0);
549 if (ActualLine0 != Line0)
550 return ::testing::AssertionFailure()
551 << "VerbatimBlockComment has lines[0] \"" << ActualLine0.str() << "\", "
552 "expected \"" << Line0.str() << "\"";
553
554 StringRef ActualLine1 = VBC->getText(LineIdx: 1);
555 if (ActualLine1 != Line1)
556 return ::testing::AssertionFailure()
557 << "VerbatimBlockComment has lines[1] \"" << ActualLine1.str() << "\", "
558 "expected \"" << Line1.str() << "\"";
559
560 return ::testing::AssertionSuccess();
561}
562
563::testing::AssertionResult HasVerbatimLineAt(const Comment *C,
564 const CommandTraits &Traits,
565 size_t Idx,
566 VerbatimLineComment *&VLC,
567 StringRef Name,
568 StringRef Text) {
569 ::testing::AssertionResult AR = GetChildAt(C, Idx, Child&: VLC);
570 if (!AR)
571 return AR;
572
573 StringRef ActualName = VLC->getCommandName(Traits);
574 if (ActualName != Name)
575 return ::testing::AssertionFailure()
576 << "VerbatimLineComment has name \"" << ActualName.str() << "\", "
577 "expected \"" << Name.str() << "\"";
578
579 StringRef ActualText = VLC->getText();
580 if (ActualText != Text)
581 return ::testing::AssertionFailure()
582 << "VerbatimLineComment has text \"" << ActualText.str() << "\", "
583 "expected \"" << Text.str() << "\"";
584
585 return ::testing::AssertionSuccess();
586}
587
588
589TEST_F(CommentParserTest, Basic1) {
590 const char *Source = "//";
591
592 FullComment *FC = parseString(Source);
593 ASSERT_TRUE(HasChildCount(FC, 0));
594}
595
596TEST_F(CommentParserTest, Basic2) {
597 const char *Source = "// Meow";
598
599 FullComment *FC = parseString(Source);
600 ASSERT_TRUE(HasChildCount(FC, 1));
601
602 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " Meow"));
603}
604
605TEST_F(CommentParserTest, Basic3) {
606 const char *Source =
607 "// Aaa\n"
608 "// Bbb";
609
610 FullComment *FC = parseString(Source);
611 ASSERT_TRUE(HasChildCount(FC, 1));
612
613 {
614 ParagraphComment *PC;
615 ASSERT_TRUE(GetChildAt(FC, 0, PC));
616
617 ASSERT_TRUE(HasChildCount(PC, 2));
618 ASSERT_TRUE(HasTextWithNewlineAt(PC, 0, " Aaa"));
619 ASSERT_TRUE(HasTextAt(PC, 1, " Bbb"));
620 }
621}
622
623TEST_F(CommentParserTest, ParagraphSplitting1) {
624 const char *Sources[] = {
625 ("// Aaa\n"
626 "//\n"
627 "// Bbb"),
628
629 ("// Aaa\n"
630 "// \n"
631 "// Bbb"),
632
633 ("// Aaa\n"
634 "//\t\n"
635 "// Bbb"),
636
637 ("// Aaa\n"
638 "//\n"
639 "//\n"
640 "// Bbb"),
641
642 ("/**\n"
643 " Aaa\n"
644 "\n"
645 " Bbb\n"
646 "*/"),
647
648 ("/**\n"
649 " Aaa\n"
650 " \n"
651 " Bbb\n"
652 "*/"),
653
654 ("/**\n"
655 " Aaa\n"
656 "\t \n"
657 " Bbb\n"
658 "*/"),
659 };
660
661 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
662 FullComment *FC = parseString(Sources[i]);
663 ASSERT_TRUE(HasChildCount(FC, 2));
664
665 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " Aaa"));
666 ASSERT_TRUE(HasParagraphCommentAt(FC, 1, " Bbb"));
667 }
668}
669
670TEST_F(CommentParserTest, Paragraph1) {
671 const char *Source =
672 "// \\brief Aaa\n"
673 "//\n"
674 "// Bbb";
675
676 FullComment *FC = parseString(Source);
677 ASSERT_TRUE(HasChildCount(FC, 3));
678
679 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
680 {
681 BlockCommandComment *BCC;
682 ParagraphComment *PC;
683 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC));
684
685 ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " Aaa"));
686 }
687 ASSERT_TRUE(HasParagraphCommentAt(FC, 2, " Bbb"));
688}
689
690TEST_F(CommentParserTest, Paragraph2) {
691 const char *Source = "// \\brief \\author";
692
693 FullComment *FC = parseString(Source);
694 ASSERT_TRUE(HasChildCount(FC, 3));
695
696 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
697 {
698 BlockCommandComment *BCC;
699 ParagraphComment *PC;
700 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC));
701
702 ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " "));
703 }
704 {
705 BlockCommandComment *BCC;
706 ParagraphComment *PC;
707 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "author", PC));
708
709 ASSERT_TRUE(GetChildAt(BCC, 0, PC));
710 ASSERT_TRUE(HasChildCount(PC, 0));
711 }
712}
713
714TEST_F(CommentParserTest, Paragraph3) {
715 const char *Source =
716 "// \\brief Aaa\n"
717 "// Bbb \\author\n"
718 "// Ccc";
719
720 FullComment *FC = parseString(Source);
721 ASSERT_TRUE(HasChildCount(FC, 3));
722
723 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
724 {
725 BlockCommandComment *BCC;
726 ParagraphComment *PC;
727 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC));
728
729 ASSERT_TRUE(GetChildAt(BCC, 0, PC));
730 ASSERT_TRUE(HasChildCount(PC, 2));
731 ASSERT_TRUE(HasTextWithNewlineAt(PC, 0, " Aaa"));
732 ASSERT_TRUE(HasTextAt(PC, 1, " Bbb "));
733 }
734 {
735 BlockCommandComment *BCC;
736 ParagraphComment *PC;
737 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "author", PC));
738
739 ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " Ccc"));
740 }
741}
742
743TEST_F(CommentParserTest, ParamCommand1) {
744 const char *Source = "// \\param aaa";
745
746 FullComment *FC = parseString(Source);
747 ASSERT_TRUE(HasChildCount(FC, 2));
748
749 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
750 {
751 ParamCommandComment *PCC;
752 ParagraphComment *PC;
753 ASSERT_TRUE(HasParamCommandAt(
754 FC, Traits, 1, PCC, "param", ParamCommandPassDirection::In,
755 /* IsDirectionExplicit = */ false, "aaa", PC));
756 ASSERT_TRUE(HasChildCount(PCC, 1));
757 ASSERT_TRUE(HasChildCount(PC, 0));
758 }
759}
760
761TEST_F(CommentParserTest, ParamCommand2) {
762 const char *Source = "// \\param\\brief";
763
764 FullComment *FC = parseString(Source);
765 ASSERT_TRUE(HasChildCount(FC, 3));
766
767 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
768 {
769 ParamCommandComment *PCC;
770 ParagraphComment *PC;
771 ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
772 ParamCommandPassDirection::In,
773 /* IsDirectionExplicit = */ false, "", PC));
774 ASSERT_TRUE(HasChildCount(PCC, 1));
775 ASSERT_TRUE(HasChildCount(PC, 0));
776 }
777 {
778 BlockCommandComment *BCC;
779 ParagraphComment *PC;
780 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "brief", PC));
781 ASSERT_TRUE(HasChildCount(PC, 0));
782 }
783}
784
785TEST_F(CommentParserTest, ParamCommand3) {
786 const char *Sources[] = {
787 "// \\param aaa Bbb\n",
788 ("// \\param\n"
789 "// aaa Bbb\n"),
790 ("// \\param \n"
791 "// aaa Bbb\n"),
792 ("// \\param aaa\n"
793 "// Bbb\n")
794 };
795
796 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
797 FullComment *FC = parseString(Sources[i]);
798 ASSERT_TRUE(HasChildCount(FC, 2));
799
800 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
801 {
802 ParamCommandComment *PCC;
803 ParagraphComment *PC;
804 ASSERT_TRUE(HasParamCommandAt(
805 FC, Traits, 1, PCC, "param", ParamCommandPassDirection::In,
806 /* IsDirectionExplicit = */ false, "aaa", PC));
807 ASSERT_TRUE(HasChildCount(PCC, 1));
808 ASSERT_TRUE(HasParagraphCommentAt(PCC, 0, " Bbb"));
809 }
810 }
811}
812
813TEST_F(CommentParserTest, ParamCommand4) {
814 const char *Sources[] = {
815 "// \\param [in] aaa Bbb\n",
816 "// \\param[in] aaa Bbb\n",
817 ("// \\param\n"
818 "// [in] aaa Bbb\n"),
819 ("// \\param [in]\n"
820 "// aaa Bbb\n"),
821 ("// \\param [in] aaa\n"
822 "// Bbb\n"),
823 };
824
825 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
826 FullComment *FC = parseString(Sources[i]);
827 ASSERT_TRUE(HasChildCount(FC, 2));
828
829 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
830 {
831 ParamCommandComment *PCC;
832 ParagraphComment *PC;
833 ASSERT_TRUE(HasParamCommandAt(
834 FC, Traits, 1, PCC, "param", ParamCommandPassDirection::In,
835 /* IsDirectionExplicit = */ true, "aaa", PC));
836 ASSERT_TRUE(HasChildCount(PCC, 1));
837 ASSERT_TRUE(HasParagraphCommentAt(PCC, 0, " Bbb"));
838 }
839 }
840}
841
842TEST_F(CommentParserTest, ParamCommand5) {
843 const char *Sources[] = {
844 "// \\param [out] aaa Bbb\n",
845 "// \\param[out] aaa Bbb\n",
846 ("// \\param\n"
847 "// [out] aaa Bbb\n"),
848 ("// \\param [out]\n"
849 "// aaa Bbb\n"),
850 ("// \\param [out] aaa\n"
851 "// Bbb\n"),
852 };
853
854 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
855 FullComment *FC = parseString(Sources[i]);
856 ASSERT_TRUE(HasChildCount(FC, 2));
857
858 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
859 {
860 ParamCommandComment *PCC;
861 ParagraphComment *PC;
862 ASSERT_TRUE(HasParamCommandAt(
863 FC, Traits, 1, PCC, "param", ParamCommandPassDirection::Out,
864 /* IsDirectionExplicit = */ true, "aaa", PC));
865 ASSERT_TRUE(HasChildCount(PCC, 1));
866 ASSERT_TRUE(HasParagraphCommentAt(PCC, 0, " Bbb"));
867 }
868 }
869}
870
871TEST_F(CommentParserTest, ParamCommand6) {
872 const char *Sources[] = {
873 "// \\param [in,out] aaa Bbb\n",
874 "// \\param[in,out] aaa Bbb\n",
875 "// \\param [in, out] aaa Bbb\n",
876 "// \\param [in,\n"
877 "// out] aaa Bbb\n",
878 "// \\param [in,out]\n"
879 "// aaa Bbb\n",
880 "// \\param [in,out] aaa\n"
881 "// Bbb\n"
882 };
883
884 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
885 FullComment *FC = parseString(Sources[i]);
886 ASSERT_TRUE(HasChildCount(FC, 2));
887
888 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
889 {
890 ParamCommandComment *PCC;
891 ParagraphComment *PC;
892 ASSERT_TRUE(HasParamCommandAt(
893 FC, Traits, 1, PCC, "param", ParamCommandPassDirection::InOut,
894 /* IsDirectionExplicit = */ true, "aaa", PC));
895 ASSERT_TRUE(HasChildCount(PCC, 1));
896 ASSERT_TRUE(HasParagraphCommentAt(PCC, 0, " Bbb"));
897 }
898 }
899}
900
901TEST_F(CommentParserTest, ParamCommand7) {
902 const char *Source =
903 "// \\param aaa \\% Bbb \\$ ccc\n";
904
905 FullComment *FC = parseString(Source);
906 ASSERT_TRUE(HasChildCount(FC, 2));
907
908 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
909 {
910 ParamCommandComment *PCC;
911 ParagraphComment *PC;
912 ASSERT_TRUE(HasParamCommandAt(
913 FC, Traits, 1, PCC, "param", ParamCommandPassDirection::In,
914 /* IsDirectionExplicit = */ false, "aaa", PC));
915 ASSERT_TRUE(HasChildCount(PCC, 1));
916
917 ASSERT_TRUE(HasChildCount(PC, 5));
918 ASSERT_TRUE(HasTextAt(PC, 0, " "));
919 ASSERT_TRUE(HasTextAt(PC, 1, "%"));
920 ASSERT_TRUE(HasTextAt(PC, 2, " Bbb "));
921 ASSERT_TRUE(HasTextAt(PC, 3, "$"));
922 ASSERT_TRUE(HasTextAt(PC, 4, " ccc"));
923 }
924}
925
926TEST_F(CommentParserTest, TParamCommand1) {
927 const char *Sources[] = {
928 "// \\tparam aaa Bbb\n",
929 "// \\tparam\n"
930 "// aaa Bbb\n",
931 "// \\tparam \n"
932 "// aaa Bbb\n",
933 "// \\tparam aaa\n"
934 "// Bbb\n"
935 };
936
937 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
938 FullComment *FC = parseString(Sources[i]);
939 ASSERT_TRUE(HasChildCount(FC, 2));
940
941 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
942 {
943 TParamCommandComment *TPCC;
944 ParagraphComment *PC;
945 ASSERT_TRUE(HasTParamCommandAt(FC, Traits, 1, TPCC, "tparam",
946 "aaa", PC));
947 ASSERT_TRUE(HasChildCount(TPCC, 1));
948 ASSERT_TRUE(HasParagraphCommentAt(TPCC, 0, " Bbb"));
949 }
950 }
951}
952
953TEST_F(CommentParserTest, TParamCommand2) {
954 const char *Source = "// \\tparam\\brief";
955
956 FullComment *FC = parseString(Source);
957 ASSERT_TRUE(HasChildCount(FC, 3));
958
959 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
960 {
961 TParamCommandComment *TPCC;
962 ParagraphComment *PC;
963 ASSERT_TRUE(HasTParamCommandAt(FC, Traits, 1, TPCC, "tparam", "", PC));
964 ASSERT_TRUE(HasChildCount(TPCC, 1));
965 ASSERT_TRUE(HasChildCount(PC, 0));
966 }
967 {
968 BlockCommandComment *BCC;
969 ParagraphComment *PC;
970 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "brief", PC));
971 ASSERT_TRUE(HasChildCount(PC, 0));
972 }
973}
974
975
976TEST_F(CommentParserTest, InlineCommand1) {
977 const char *Source = "// \\c";
978
979 FullComment *FC = parseString(Source);
980 ASSERT_TRUE(HasChildCount(FC, 1));
981
982 {
983 ParagraphComment *PC;
984 InlineCommandComment *ICC;
985 ASSERT_TRUE(GetChildAt(FC, 0, PC));
986
987 ASSERT_TRUE(HasChildCount(PC, 2));
988 ASSERT_TRUE(HasTextAt(PC, 0, " "));
989 ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", NoArgs()));
990 }
991}
992
993TEST_F(CommentParserTest, InlineCommand2) {
994 const char *Source = "// \\c ";
995
996 FullComment *FC = parseString(Source);
997 ASSERT_TRUE(HasChildCount(FC, 1));
998
999 {
1000 ParagraphComment *PC;
1001 InlineCommandComment *ICC;
1002 ASSERT_TRUE(GetChildAt(FC, 0, PC));
1003
1004 ASSERT_TRUE(HasChildCount(PC, 3));
1005 ASSERT_TRUE(HasTextAt(PC, 0, " "));
1006 ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", NoArgs()));
1007 ASSERT_TRUE(HasTextAt(PC, 2, " "));
1008 }
1009}
1010
1011TEST_F(CommentParserTest, InlineCommand3) {
1012 const char *Source = "// \\c aaa\n";
1013
1014 FullComment *FC = parseString(Source);
1015 ASSERT_TRUE(HasChildCount(FC, 1));
1016
1017 {
1018 ParagraphComment *PC;
1019 InlineCommandComment *ICC;
1020 ASSERT_TRUE(GetChildAt(FC, 0, PC));
1021
1022 ASSERT_TRUE(HasChildCount(PC, 2));
1023 ASSERT_TRUE(HasTextAt(PC, 0, " "));
1024 ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", "aaa"));
1025 }
1026}
1027
1028TEST_F(CommentParserTest, InlineCommand4) {
1029 const char *Source = "// \\c aaa bbb";
1030
1031 FullComment *FC = parseString(Source);
1032 ASSERT_TRUE(HasChildCount(FC, 1));
1033
1034 {
1035 ParagraphComment *PC;
1036 InlineCommandComment *ICC;
1037 ASSERT_TRUE(GetChildAt(FC, 0, PC));
1038
1039 ASSERT_TRUE(HasChildCount(PC, 3));
1040 ASSERT_TRUE(HasTextAt(PC, 0, " "));
1041 ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", "aaa"));
1042 ASSERT_TRUE(HasTextAt(PC, 2, " bbb"));
1043 }
1044}
1045
1046TEST_F(CommentParserTest, InlineCommand5) {
1047 const char *Source = "// \\unknown aaa\n";
1048
1049 FullComment *FC = parseString(Source);
1050 ASSERT_TRUE(HasChildCount(FC, 1));
1051
1052 {
1053 ParagraphComment *PC;
1054 InlineCommandComment *ICC;
1055 ASSERT_TRUE(GetChildAt(FC, 0, PC));
1056
1057 ASSERT_TRUE(HasChildCount(PC, 3));
1058 ASSERT_TRUE(HasTextAt(PC, 0, " "));
1059 ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "unknown", NoArgs()));
1060 ASSERT_TRUE(HasTextAt(PC, 2, " aaa"));
1061 }
1062}
1063
1064TEST_F(CommentParserTest, HTML1) {
1065 const char *Sources[] = {
1066 "// <a",
1067 "// <a>",
1068 "// <a >",
1069 "// <a\n// >",
1070 };
1071
1072 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1073 FullComment *FC = parseString(Sources[i]);
1074 ASSERT_TRUE(HasChildCount(FC, 1));
1075
1076 {
1077 ParagraphComment *PC;
1078 HTMLStartTagComment *HST;
1079 ASSERT_TRUE(GetChildAt(FC, 0, PC));
1080
1081 ASSERT_TRUE(HasChildCount(PC, 2));
1082 ASSERT_TRUE(HasTextAt(PC, 0, " "));
1083 ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "a", NoAttrs()));
1084 }
1085 }
1086}
1087
1088TEST_F(CommentParserTest, HTML2) {
1089 const char *Sources[] = {
1090 "// <br/>",
1091 "// <br />",
1092 "// <br \n// />",
1093 };
1094
1095 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1096 FullComment *FC = parseString(Sources[i]);
1097 ASSERT_TRUE(HasChildCount(FC, 1));
1098
1099 {
1100 ParagraphComment *PC;
1101 HTMLStartTagComment *HST;
1102 ASSERT_TRUE(GetChildAt(FC, 0, PC));
1103
1104 ASSERT_TRUE(HasChildCount(PC, 2));
1105 ASSERT_TRUE(HasTextAt(PC, 0, " "));
1106 ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "br", SelfClosing()));
1107 }
1108 }
1109}
1110
1111TEST_F(CommentParserTest, HTML3) {
1112 const char *Sources[] = {
1113 "// <a href", "// <a href ", "// <a href>",
1114 "// <a href >", "// <a \n// href >",
1115 };
1116
1117 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1118 FullComment *FC = parseString(Sources[i]);
1119 ASSERT_TRUE(HasChildCount(FC, 1));
1120
1121 {
1122 ParagraphComment *PC;
1123 HTMLStartTagComment *HST;
1124 ASSERT_TRUE(GetChildAt(FC, 0, PC));
1125
1126 ASSERT_TRUE(HasChildCount(PC, 2));
1127 ASSERT_TRUE(HasTextAt(PC, 0, " "));
1128 ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "a", "href", ""));
1129 }
1130 }
1131}
1132
1133TEST_F(CommentParserTest, HTML4) {
1134 const char *Sources[] = {
1135 "// <a href=\"bbb\"",
1136 "// <a href=\"bbb\">",
1137 "// <a \n// href=\"bbb\">",
1138 };
1139
1140 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1141 FullComment *FC = parseString(Sources[i]);
1142 ASSERT_TRUE(HasChildCount(FC, 1));
1143
1144 {
1145 ParagraphComment *PC;
1146 HTMLStartTagComment *HST;
1147 ASSERT_TRUE(GetChildAt(FC, 0, PC));
1148
1149 ASSERT_TRUE(HasChildCount(PC, 2));
1150 ASSERT_TRUE(HasTextAt(PC, 0, " "));
1151 ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "a", "href", "bbb"));
1152 }
1153 }
1154}
1155
1156TEST_F(CommentParserTest, HTML5) {
1157 const char *Sources[] = {
1158 "// </a",
1159 "// </a>",
1160 "// </a >"
1161 };
1162
1163 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1164 FullComment *FC = parseString(Sources[i]);
1165 ASSERT_TRUE(HasChildCount(FC, 1));
1166
1167 {
1168 ParagraphComment *PC;
1169 HTMLEndTagComment *HET;
1170 ASSERT_TRUE(GetChildAt(FC, 0, PC));
1171
1172 ASSERT_TRUE(HasChildCount(PC, 2));
1173 ASSERT_TRUE(HasTextAt(PC, 0, " "));
1174 ASSERT_TRUE(HasHTMLEndTagAt(PC, 1, HET, "a"));
1175 }
1176 }
1177}
1178
1179TEST_F(CommentParserTest, HTML6) {
1180 const char *Source =
1181 "// <pre>\n"
1182 "// Aaa\n"
1183 "// Bbb\n"
1184 "// </pre>\n";
1185
1186 FullComment *FC = parseString(Source);
1187 ASSERT_TRUE(HasChildCount(FC, 1));
1188
1189 {
1190 ParagraphComment *PC;
1191 HTMLStartTagComment *HST;
1192 HTMLEndTagComment *HET;
1193 ASSERT_TRUE(GetChildAt(FC, 0, PC));
1194
1195 ASSERT_TRUE(HasChildCount(PC, 6));
1196 ASSERT_TRUE(HasTextAt(PC, 0, " "));
1197 ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "pre", NoAttrs()));
1198 ASSERT_TRUE(HasTextWithNewlineAt(PC, 2, " Aaa"));
1199 ASSERT_TRUE(HasTextWithNewlineAt(PC, 3, " Bbb"));
1200 ASSERT_TRUE(HasTextAt(PC, 4, " "));
1201 ASSERT_TRUE(HasHTMLEndTagAt(PC, 5, HET, "pre"));
1202 }
1203}
1204
1205TEST_F(CommentParserTest, VerbatimBlock1) {
1206 const char *Source = "// \\verbatim\\endverbatim\n";
1207
1208 FullComment *FC = parseString(Source);
1209 ASSERT_TRUE(HasChildCount(FC, 2));
1210
1211 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1212 {
1213 VerbatimBlockComment *VCC;
1214 ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VCC,
1215 "verbatim", "endverbatim",
1216 NoLines()));
1217 }
1218}
1219
1220TEST_F(CommentParserTest, VerbatimBlock2) {
1221 const char *Source = "// \\verbatim Aaa \\endverbatim\n";
1222
1223 FullComment *FC = parseString(Source);
1224 ASSERT_TRUE(HasChildCount(FC, 2));
1225
1226 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1227 {
1228 VerbatimBlockComment *VBC;
1229 ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
1230 "verbatim", "endverbatim",
1231 Lines(), " Aaa "));
1232 }
1233}
1234
1235TEST_F(CommentParserTest, VerbatimBlock3) {
1236 const char *Source = "// \\verbatim Aaa\n";
1237
1238 FullComment *FC = parseString(Source);
1239 ASSERT_TRUE(HasChildCount(FC, 2));
1240
1241 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1242 {
1243 VerbatimBlockComment *VBC;
1244 ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC, "verbatim", "",
1245 Lines(), " Aaa"));
1246 }
1247}
1248
1249TEST_F(CommentParserTest, VerbatimBlock4) {
1250 const char *Source =
1251 "//\\verbatim\n"
1252 "//\\endverbatim\n";
1253
1254 FullComment *FC = parseString(Source);
1255 ASSERT_TRUE(HasChildCount(FC, 1));
1256
1257 {
1258 VerbatimBlockComment *VBC;
1259 ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 0, VBC,
1260 "verbatim", "endverbatim",
1261 NoLines()));
1262 }
1263}
1264
1265TEST_F(CommentParserTest, VerbatimBlock5) {
1266 const char *Sources[] = {
1267 "//\\verbatim\n"
1268 "// Aaa\n"
1269 "//\\endverbatim\n",
1270
1271 "/*\\verbatim\n"
1272 " * Aaa\n"
1273 " *\\endverbatim*/"
1274 };
1275
1276 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1277 FullComment *FC = parseString(Sources[i]);
1278 ASSERT_TRUE(HasChildCount(FC, 1));
1279
1280 {
1281 VerbatimBlockComment *VBC;
1282 ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 0, VBC,
1283 "verbatim", "endverbatim",
1284 Lines(), " Aaa"));
1285 }
1286 }
1287}
1288
1289TEST_F(CommentParserTest, VerbatimBlock6) {
1290 const char *Sources[] = {
1291 "// \\verbatim\n"
1292 "// Aaa\n"
1293 "// \\endverbatim\n",
1294
1295 "/* \\verbatim\n"
1296 " * Aaa\n"
1297 " * \\endverbatim*/"
1298 };
1299
1300 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1301 FullComment *FC = parseString(Sources[i]);
1302 ASSERT_TRUE(HasChildCount(FC, 2));
1303
1304 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1305 {
1306 VerbatimBlockComment *VBC;
1307 ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
1308 "verbatim", "endverbatim",
1309 Lines(), " Aaa"));
1310 }
1311 }
1312}
1313
1314TEST_F(CommentParserTest, VerbatimBlock7) {
1315 const char *Sources[] = {
1316 "// \\verbatim\n"
1317 "// Aaa\n"
1318 "// Bbb\n"
1319 "// \\endverbatim\n",
1320
1321 "/* \\verbatim\n"
1322 " * Aaa\n"
1323 " * Bbb\n"
1324 " * \\endverbatim*/"
1325 };
1326
1327 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1328 FullComment *FC = parseString(Sources[i]);
1329 ASSERT_TRUE(HasChildCount(FC, 2));
1330
1331 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1332 {
1333 VerbatimBlockComment *VBC;
1334 ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
1335 "verbatim", "endverbatim",
1336 Lines(), " Aaa", " Bbb"));
1337 }
1338 }
1339}
1340
1341TEST_F(CommentParserTest, VerbatimBlock8) {
1342 const char *Sources[] = {
1343 "// \\verbatim\n"
1344 "// Aaa\n"
1345 "//\n"
1346 "// Bbb\n"
1347 "// \\endverbatim\n",
1348
1349 "/* \\verbatim\n"
1350 " * Aaa\n"
1351 " *\n"
1352 " * Bbb\n"
1353 " * \\endverbatim*/"
1354 };
1355 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1356 FullComment *FC = parseString(Sources[i]);
1357 ASSERT_TRUE(HasChildCount(FC, 2));
1358
1359 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1360 {
1361 VerbatimBlockComment *VBC;
1362 ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
1363 "verbatim", "endverbatim"));
1364 ASSERT_EQ(3U, VBC->getNumLines());
1365 ASSERT_EQ(" Aaa", VBC->getText(0));
1366 ASSERT_EQ("", VBC->getText(1));
1367 ASSERT_EQ(" Bbb", VBC->getText(2));
1368 }
1369 }
1370}
1371
1372TEST_F(CommentParserTest, VerbatimLine1) {
1373 const char *Sources[] = {
1374 "// \\fn",
1375 "// \\fn\n"
1376 };
1377
1378 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1379 FullComment *FC = parseString(Sources[i]);
1380 ASSERT_TRUE(HasChildCount(FC, 2));
1381
1382 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1383 {
1384 VerbatimLineComment *VLC;
1385 ASSERT_TRUE(HasVerbatimLineAt(FC, Traits, 1, VLC, "fn", ""));
1386 }
1387 }
1388}
1389
1390TEST_F(CommentParserTest, VerbatimLine2) {
1391 const char *Sources[] = {
1392 "/// \\fn void *foo(const char *zzz = \"\\$\");\n//",
1393 "/** \\fn void *foo(const char *zzz = \"\\$\");*/"
1394 };
1395
1396 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1397 FullComment *FC = parseString(Sources[i]);
1398 ASSERT_TRUE(HasChildCount(FC, 2));
1399
1400 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1401 {
1402 VerbatimLineComment *VLC;
1403 ASSERT_TRUE(HasVerbatimLineAt(FC, Traits, 1, VLC, "fn",
1404 " void *foo(const char *zzz = \"\\$\");"));
1405 }
1406 }
1407}
1408
1409TEST_F(CommentParserTest, Deprecated) {
1410 const char *Sources[] = {
1411 "/** @deprecated*/",
1412 "/// @deprecated\n"
1413 };
1414
1415 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1416 FullComment *FC = parseString(Sources[i]);
1417 ASSERT_TRUE(HasChildCount(FC, 2));
1418
1419 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1420 {
1421 BlockCommandComment *BCC;
1422 ParagraphComment *PC;
1423 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "deprecated", PC));
1424 ASSERT_TRUE(HasChildCount(PC, 0));
1425 }
1426 }
1427}
1428
1429TEST_F(CommentParserTest, ThrowsCommandHasArg1) {
1430 const char *Sources[] = {
1431 "/// @throws int This function throws an integer",
1432 ("/// @throws\n"
1433 "/// int This function throws an integer"),
1434 ("/// @throws \n"
1435 "/// int This function throws an integer"),
1436 ("/// @throws\n"
1437 "/// int\n"
1438 "/// This function throws an integer"),
1439 ("/// @throws \n"
1440 "/// int \n"
1441 "/// This function throws an integer"),
1442 };
1443
1444 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1445 FullComment *FC = parseString(Sources[i]);
1446 ASSERT_TRUE(HasChildCount(FC, 2));
1447
1448 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1449 {
1450 BlockCommandComment *BCC;
1451 ParagraphComment *PC;
1452 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "throws", PC));
1453 ASSERT_TRUE(HasChildCount(PC, 1));
1454 ASSERT_TRUE(BCC->getNumArgs() == 1);
1455 ASSERT_TRUE(BCC->getArgText(0) == "int");
1456 }
1457 }
1458}
1459
1460TEST_F(CommentParserTest, ThrowsCommandHasArg2) {
1461 const char *Sources[] = {
1462 "/// @throws int** This function throws a double pointer to an integer",
1463 };
1464
1465 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1466 FullComment *FC = parseString(Sources[i]);
1467 ASSERT_TRUE(HasChildCount(FC, 2));
1468
1469 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1470 {
1471 BlockCommandComment *BCC;
1472 ParagraphComment *PC;
1473 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "throws", PC));
1474 ASSERT_TRUE(HasChildCount(PC, 1));
1475 ASSERT_TRUE(BCC->getNumArgs() == 1);
1476 ASSERT_TRUE(BCC->getArgText(0) == "int**");
1477 }
1478 }
1479}
1480
1481TEST_F(CommentParserTest, ThrowsCommandHasArg3) {
1482 const char *Sources[] = {
1483 "/// @throws Error<T> error of type Error<T>",
1484 };
1485
1486 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1487 FullComment *FC = parseString(Sources[i]);
1488 ASSERT_TRUE(HasChildCount(FC, 2));
1489
1490 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1491 {
1492 BlockCommandComment *BCC;
1493 ParagraphComment *PC;
1494 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "throws", PC));
1495 ASSERT_TRUE(HasChildCount(PC, 3)); // Extra children because <T> is parsed
1496 // as a series of TextComments
1497 ASSERT_TRUE(BCC->getNumArgs() == 1);
1498 ASSERT_TRUE(BCC->getArgText(0) == "Error<T>");
1499 }
1500 }
1501}
1502
1503TEST_F(CommentParserTest, ThrowsCommandHasArg4) {
1504 const char *Sources[] = {
1505 "/// @throws Error<Container<T>> nested templates",
1506 };
1507
1508 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1509 FullComment *FC = parseString(Sources[i]);
1510 ASSERT_TRUE(HasChildCount(FC, 2));
1511
1512 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1513 {
1514 BlockCommandComment *BCC;
1515 ParagraphComment *PC;
1516 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "throws", PC));
1517 ASSERT_TRUE(HasChildCount(PC, 1));
1518 ASSERT_TRUE(BCC->getNumArgs() == 1);
1519 ASSERT_TRUE(BCC->getArgText(0) == "Error<Container<T>>");
1520 }
1521 }
1522}
1523
1524TEST_F(CommentParserTest, ThrowsCommandHasArg5) {
1525 const char *Sources[] = {
1526 "/// @throws Error<Ts...> variadic templates",
1527 };
1528
1529 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1530 FullComment *FC = parseString(Sources[i]);
1531 ASSERT_TRUE(HasChildCount(FC, 2));
1532
1533 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1534 {
1535 BlockCommandComment *BCC;
1536 ParagraphComment *PC;
1537 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "throws", PC));
1538 ASSERT_TRUE(HasChildCount(PC, 1));
1539 ASSERT_TRUE(BCC->getNumArgs() == 1);
1540 ASSERT_TRUE(BCC->getArgText(0) == "Error<Ts...>");
1541 }
1542 }
1543}
1544
1545TEST_F(CommentParserTest, ThrowsCommandHasArg6) {
1546 const char *Sources[] = {
1547 "/// @throws Foo<(1 > 0)> typo1",
1548 };
1549
1550 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1551 FullComment *FC = parseString(Sources[i]);
1552 ASSERT_TRUE(HasChildCount(FC, 2));
1553
1554 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1555 {
1556 BlockCommandComment *BCC;
1557 ParagraphComment *PC;
1558 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "throws", PC));
1559 ASSERT_TRUE(HasChildCount(PC, 1));
1560 ASSERT_TRUE(BCC->getNumArgs() == 1);
1561 ASSERT_TRUE(BCC->getArgText(0) == "Foo<(1 >");
1562 }
1563 }
1564}
1565
1566// No matter the number of (unmatched) opening brackets, no type is parsed.
1567TEST_F(CommentParserTest, ThrowsCommandHasArg7) {
1568 const char *Sources[] = {
1569 "/// @throws Foo<",
1570 "/// @throws Foo<<<",
1571 "/// @throws Foo<<<<<<<",
1572 "/// @throws Foo<\n",
1573 "/// @throws Foo<<<\n",
1574 "/// @throws Foo<<<<<<<\n",
1575 };
1576
1577 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1578 FullComment *FC = parseString(Sources[i]);
1579 ASSERT_TRUE(HasChildCount(FC, 2));
1580
1581 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1582 {
1583 BlockCommandComment *BCC;
1584 ParagraphComment *PC;
1585 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "throws", PC));
1586 ASSERT_TRUE(HasChildCount(PC, 0));
1587 ASSERT_TRUE(BCC->getNumArgs() == 0);
1588 }
1589 }
1590}
1591
1592// Types with a non-matching closing bracket are parsed as if they are a type
1593TEST_F(CommentParserTest, ThrowsCommandHasArg8) {
1594 const char *Sources[] = {
1595 "/// @throws Foo>",
1596 "/// @throws Foo>\n",
1597 };
1598
1599 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1600 FullComment *FC = parseString(Sources[i]);
1601 ASSERT_TRUE(HasChildCount(FC, 2));
1602
1603 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1604 {
1605 BlockCommandComment *BCC;
1606 ParagraphComment *PC;
1607 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "throws", PC));
1608 ASSERT_TRUE(HasChildCount(PC, 0));
1609 ASSERT_TRUE(BCC->getNumArgs() == 1);
1610 ASSERT_TRUE(BCC->getArgText(0) == "Foo>");
1611 }
1612 }
1613}
1614
1615// Everying up until the end of the paragraph comment will be
1616// eaten up if the template sequence is unterminated (i.e. number of
1617// opening and closing brackets is not equal).
1618TEST_F(CommentParserTest, ThrowsCommandHasArg9) {
1619 const char *Sources[] = {
1620 "/// @throws Foo<Bar<t>\n"
1621 "/// Aaa\n"
1622 "///\n"
1623 "/// Bbb\n"
1624 };
1625
1626 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1627 FullComment *FC = parseString(Sources[i]);
1628 ASSERT_TRUE(HasChildCount(FC, 3));
1629
1630 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1631 {
1632 BlockCommandComment *BCC;
1633 ParagraphComment *PC;
1634 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "throws", PC));
1635 ASSERT_TRUE(HasChildCount(PC, 0));
1636 ASSERT_TRUE(BCC->getNumArgs() == 0);
1637 }
1638 }
1639}
1640
1641TEST_F(CommentParserTest, ParCommandHasArg1) {
1642 const char *Sources[] = {
1643 "/// @par Paragraph header:", "/// @par Paragraph header:\n",
1644 "/// @par Paragraph header:\r\n", "/// @par Paragraph header:\n\r",
1645 "/** @par Paragraph header:*/",
1646 };
1647
1648 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1649 FullComment *FC = parseString(Sources[i]);
1650 ASSERT_TRUE(HasChildCount(FC, 2));
1651
1652 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1653 {
1654 BlockCommandComment *BCC;
1655 ParagraphComment *PC;
1656 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "par", PC));
1657 ASSERT_TRUE(HasChildCount(PC, 0));
1658 ASSERT_TRUE(BCC->getNumArgs() == 1);
1659 ASSERT_TRUE(BCC->getArgText(0) == "Paragraph header:");
1660 }
1661 }
1662}
1663
1664TEST_F(CommentParserTest, ParCommandHasArg2) {
1665 const char *Sources[] = {
1666 "/// @par Paragraph header: ", "/// @par Paragraph header: \n",
1667 "/// @par Paragraph header: \r\n", "/// @par Paragraph header: \n\r",
1668 "/** @par Paragraph header: */",
1669 };
1670
1671 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1672 FullComment *FC = parseString(Sources[i]);
1673 ASSERT_TRUE(HasChildCount(FC, 2));
1674
1675 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1676 {
1677 BlockCommandComment *BCC;
1678 ParagraphComment *PC;
1679 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "par", PC));
1680 ASSERT_TRUE(HasChildCount(PC, 0));
1681 ASSERT_TRUE(BCC->getNumArgs() == 1);
1682 ASSERT_TRUE(BCC->getArgText(0) == "Paragraph header: ");
1683 }
1684 }
1685}
1686
1687TEST_F(CommentParserTest, ParCommandHasArg3) {
1688 const char *Sources[] = {
1689 ("/// @par Paragraph header:\n"
1690 "/// Paragraph body"),
1691 ("/// @par Paragraph header:\r\n"
1692 "/// Paragraph body"),
1693 ("/// @par Paragraph header:\n\r"
1694 "/// Paragraph body"),
1695 };
1696
1697 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1698 FullComment *FC = parseString(Sources[i]);
1699 ASSERT_TRUE(HasChildCount(FC, 2));
1700
1701 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1702 {
1703 BlockCommandComment *BCC;
1704 ParagraphComment *PC;
1705 TextComment *TC;
1706 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "par", PC));
1707 ASSERT_TRUE(HasChildCount(PC, 1));
1708 ASSERT_TRUE(BCC->getNumArgs() == 1);
1709 ASSERT_TRUE(BCC->getArgText(0) == "Paragraph header:");
1710 ASSERT_TRUE(GetChildAt(PC, 0, TC));
1711 ASSERT_TRUE(TC->getText() == " Paragraph body");
1712 }
1713 }
1714}
1715
1716TEST_F(CommentParserTest, ParCommandHasArg4) {
1717 const char *Sources[] = {
1718 ("/// @par Paragraph header:\n"
1719 "/// Paragraph body1\n"
1720 "/// Paragraph body2"),
1721 ("/// @par Paragraph header:\r\n"
1722 "/// Paragraph body1\n"
1723 "/// Paragraph body2"),
1724 ("/// @par Paragraph header:\n\r"
1725 "/// Paragraph body1\n"
1726 "/// Paragraph body2"),
1727 };
1728
1729 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1730 FullComment *FC = parseString(Sources[i]);
1731 ASSERT_TRUE(HasChildCount(FC, 2));
1732
1733 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1734 {
1735 BlockCommandComment *BCC;
1736 ParagraphComment *PC;
1737 TextComment *TC;
1738 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "par", PC));
1739 ASSERT_TRUE(HasChildCount(PC, 2));
1740 ASSERT_TRUE(BCC->getNumArgs() == 1);
1741 ASSERT_TRUE(BCC->getArgText(0) == "Paragraph header:");
1742 ASSERT_TRUE(GetChildAt(PC, 0, TC));
1743 ASSERT_TRUE(TC->getText() == " Paragraph body1");
1744 ASSERT_TRUE(GetChildAt(PC, 1, TC));
1745 ASSERT_TRUE(TC->getText() == " Paragraph body2");
1746 }
1747 }
1748}
1749
1750TEST_F(CommentParserTest, ParCommandHasArg5) {
1751 const char *Sources[] = {
1752 ("/// @par \n"
1753 "/// Paragraphs with no text before newline have no heading"),
1754 ("/// @par \r\n"
1755 "/// Paragraphs with no text before newline have no heading"),
1756 ("/// @par \n\r"
1757 "/// Paragraphs with no text before newline have no heading"),
1758 };
1759
1760 for (size_t i = 0, e = std::size(Sources); i != e; i++) {
1761 FullComment *FC = parseString(Sources[i]);
1762 ASSERT_TRUE(HasChildCount(FC, 2));
1763
1764 ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
1765 {
1766 BlockCommandComment *BCC;
1767 ParagraphComment *PC;
1768 TextComment *TC;
1769 ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "par", PC));
1770 ASSERT_TRUE(HasChildCount(PC, 1));
1771 ASSERT_TRUE(BCC->getNumArgs() == 0);
1772 ASSERT_TRUE(GetChildAt(PC, 0, TC));
1773 ASSERT_TRUE(TC->getText() ==
1774 "Paragraphs with no text before newline have no heading");
1775 }
1776 }
1777}
1778
1779} // unnamed namespace
1780
1781} // end namespace comments
1782} // end namespace clang
1783

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang/unittests/AST/CommentParser.cpp