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