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