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