brintos

brintos / llvm-project-archived public Read only

0
0
Text · 52.5 KiB · 3bd2bdb Raw
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