diff options
Diffstat (limited to 'clang/unittests/AST')
-rw-r--r-- | clang/unittests/AST/CommentLexer.cpp | 190 | ||||
-rw-r--r-- | clang/unittests/AST/CommentParser.cpp | 1126 |
2 files changed, 1290 insertions, 26 deletions
diff --git a/clang/unittests/AST/CommentLexer.cpp b/clang/unittests/AST/CommentLexer.cpp index 5b4712df259..0a52364987e 100644 --- a/clang/unittests/AST/CommentLexer.cpp +++ b/clang/unittests/AST/CommentLexer.cpp @@ -359,6 +359,23 @@ TEST_F(CommentLexerTest, DoxygenCommand6) { ASSERT_EQ(tok::newline, Toks[7].getKind()); } +TEST_F(CommentLexerTest, DoxygenCommand7) { + const char *Source = "// \\c\n"; + std::vector<Token> Toks; + + lexString(Source, Toks); + + ASSERT_EQ(3U, Toks.size()); + + ASSERT_EQ(tok::text, Toks[0].getKind()); + ASSERT_EQ(StringRef(" "), Toks[0].getText()); + + ASSERT_EQ(tok::command, Toks[1].getKind()); + ASSERT_EQ(StringRef("c"), Toks[1].getCommandName()); + + ASSERT_EQ(tok::newline, Toks[2].getKind()); +} + // Empty verbatim block. TEST_F(CommentLexerTest, VerbatimBlock1) { const char *Sources[] = { @@ -389,31 +406,45 @@ TEST_F(CommentLexerTest, VerbatimBlock1) { // Empty verbatim block without an end command. TEST_F(CommentLexerTest, VerbatimBlock2) { - const char *Sources[] = { - "/// \\verbatim\n//", - "/** \\verbatim*/" - }; + const char *Source = "/// \\verbatim"; - for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { - std::vector<Token> Toks; + std::vector<Token> Toks; - lexString(Sources[i], Toks); + lexString(Source, Toks); - ASSERT_EQ(4U, Toks.size()); + ASSERT_EQ(3U, Toks.size()); - ASSERT_EQ(tok::text, Toks[0].getKind()); - ASSERT_EQ(StringRef(" "), Toks[0].getText()); + ASSERT_EQ(tok::text, Toks[0].getKind()); + ASSERT_EQ(StringRef(" "), Toks[0].getText()); - ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); - ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); + ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); + ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); - ASSERT_EQ(tok::newline, Toks[2].getKind()); - ASSERT_EQ(tok::newline, Toks[3].getKind()); - } + ASSERT_EQ(tok::newline, Toks[2].getKind()); } -// Single-line verbatim block. +// Empty verbatim block without an end command. TEST_F(CommentLexerTest, VerbatimBlock3) { + const char *Source = "/** \\verbatim*/"; + + std::vector<Token> Toks; + + lexString(Source, Toks); + + ASSERT_EQ(4U, Toks.size()); + + ASSERT_EQ(tok::text, Toks[0].getKind()); + ASSERT_EQ(StringRef(" "), Toks[0].getText()); + + ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); + ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); + + ASSERT_EQ(tok::newline, Toks[2].getKind()); + ASSERT_EQ(tok::newline, Toks[3].getKind()); +} + +// Single-line verbatim block. +TEST_F(CommentLexerTest, VerbatimBlock4) { const char *Sources[] = { "/// Meow \\verbatim aaa \\endverbatim\n//", "/** Meow \\verbatim aaa \\endverbatim*/" @@ -444,7 +475,7 @@ TEST_F(CommentLexerTest, VerbatimBlock3) { } // Single-line verbatim block without an end command. -TEST_F(CommentLexerTest, VerbatimBlock4) { +TEST_F(CommentLexerTest, VerbatimBlock5) { const char *Sources[] = { "/// Meow \\verbatim aaa \n//", "/** Meow \\verbatim aaa */" @@ -471,8 +502,96 @@ TEST_F(CommentLexerTest, VerbatimBlock4) { } } +TEST_F(CommentLexerTest, VerbatimBlock6) { + const char *Source = + "// \\verbatim\n" + "// Aaa\n" + "//\n" + "// Bbb\n" + "// \\endverbatim\n"; + + std::vector<Token> Toks; + + lexString(Source, Toks); + + ASSERT_EQ(11U, Toks.size()); + + ASSERT_EQ(tok::text, Toks[0].getKind()); + ASSERT_EQ(StringRef(" "), Toks[0].getText()); + + ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); + ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); + + ASSERT_EQ(tok::newline, Toks[2].getKind()); + + ASSERT_EQ(tok::verbatim_block_line, Toks[3].getKind()); + ASSERT_EQ(StringRef(" Aaa"), Toks[3].getVerbatimBlockText()); + + ASSERT_EQ(tok::newline, Toks[4].getKind()); + + ASSERT_EQ(tok::newline, Toks[5].getKind()); + + ASSERT_EQ(tok::verbatim_block_line, Toks[6].getKind()); + ASSERT_EQ(StringRef(" Bbb"), Toks[6].getVerbatimBlockText()); + + ASSERT_EQ(tok::newline, Toks[7].getKind()); + + ASSERT_EQ(tok::verbatim_block_line, Toks[8].getKind()); + ASSERT_EQ(StringRef(" "), Toks[8].getVerbatimBlockText()); + + ASSERT_EQ(tok::verbatim_block_end, Toks[9].getKind()); + ASSERT_EQ(StringRef("endverbatim"), Toks[9].getVerbatimBlockName()); + + ASSERT_EQ(tok::newline, Toks[10].getKind()); +} + +TEST_F(CommentLexerTest, VerbatimBlock7) { + const char *Source = + "/* \\verbatim\n" + " * Aaa\n" + " *\n" + " * Bbb\n" + " * \\endverbatim\n" + " */"; + + std::vector<Token> Toks; + + lexString(Source, Toks); + + ASSERT_EQ(11U, Toks.size()); + + ASSERT_EQ(tok::text, Toks[0].getKind()); + ASSERT_EQ(StringRef(" "), Toks[0].getText()); + + ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); + ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); + + ASSERT_EQ(tok::verbatim_block_line, Toks[2].getKind()); + ASSERT_EQ(StringRef(" Aaa"), Toks[2].getVerbatimBlockText()); + + ASSERT_EQ(tok::verbatim_block_line, Toks[3].getKind()); + ASSERT_EQ(StringRef(""), Toks[3].getVerbatimBlockText()); + + ASSERT_EQ(tok::verbatim_block_line, Toks[4].getKind()); + ASSERT_EQ(StringRef(" Bbb"), Toks[4].getVerbatimBlockText()); + + ASSERT_EQ(tok::verbatim_block_line, Toks[5].getKind()); + ASSERT_EQ(StringRef(" "), Toks[5].getVerbatimBlockText()); + + ASSERT_EQ(tok::verbatim_block_end, Toks[6].getKind()); + ASSERT_EQ(StringRef("endverbatim"), Toks[6].getVerbatimBlockName()); + + ASSERT_EQ(tok::newline, Toks[7].getKind()); + + ASSERT_EQ(tok::text, Toks[8].getKind()); + ASSERT_EQ(StringRef(" "), Toks[8].getText()); + + ASSERT_EQ(tok::newline, Toks[9].getKind()); + ASSERT_EQ(tok::newline, Toks[10].getKind()); +} + // Complex test for verbatim blocks. -TEST_F(CommentLexerTest, VerbatimBlock5) { +TEST_F(CommentLexerTest, VerbatimBlock8) { const char *Source = "/* Meow \\verbatim aaa\\$\\@\n" "bbb \\endverbati\r" @@ -492,13 +611,13 @@ TEST_F(CommentLexerTest, VerbatimBlock5) { ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); ASSERT_EQ(tok::verbatim_block_line, Toks[2].getKind()); - ASSERT_EQ(StringRef(" aaa\\$\\@\n"), Toks[2].getVerbatimBlockText()); + ASSERT_EQ(StringRef(" aaa\\$\\@"), Toks[2].getVerbatimBlockText()); ASSERT_EQ(tok::verbatim_block_line, Toks[3].getKind()); - ASSERT_EQ(StringRef("bbb \\endverbati\r"), Toks[3].getVerbatimBlockText()); + ASSERT_EQ(StringRef("bbb \\endverbati"), Toks[3].getVerbatimBlockText()); ASSERT_EQ(tok::verbatim_block_line, Toks[4].getKind()); - ASSERT_EQ(StringRef("ccc\r\n"), Toks[4].getVerbatimBlockText()); + ASSERT_EQ(StringRef("ccc"), Toks[4].getVerbatimBlockText()); ASSERT_EQ(tok::verbatim_block_line, Toks[5].getKind()); ASSERT_EQ(StringRef("ddd "), Toks[5].getVerbatimBlockText()); @@ -513,7 +632,7 @@ TEST_F(CommentLexerTest, VerbatimBlock5) { ASSERT_EQ(StringRef("verbatim"), Toks[8].getVerbatimBlockName()); ASSERT_EQ(tok::verbatim_block_line, Toks[9].getKind()); - ASSERT_EQ(StringRef(" eee\n"), Toks[9].getVerbatimBlockText()); + ASSERT_EQ(StringRef(" eee"), Toks[9].getVerbatimBlockText()); ASSERT_EQ(tok::verbatim_block_end, Toks[10].getKind()); ASSERT_EQ(StringRef("endverbatim"), Toks[10].getVerbatimBlockName()); @@ -526,7 +645,7 @@ TEST_F(CommentLexerTest, VerbatimBlock5) { } // LaTeX verbatim blocks. -TEST_F(CommentLexerTest, VerbatimBlock6) { +TEST_F(CommentLexerTest, VerbatimBlock9) { const char *Source = "/// \\f$ Aaa \\f$ \\f[ Bbb \\f] \\f{ Ccc \\f}"; std::vector<Token> Toks; @@ -968,8 +1087,25 @@ TEST_F(CommentLexerTest, HTML12) { } TEST_F(CommentLexerTest, HTML13) { + const char *Source = "// </tag"; + + std::vector<Token> Toks; + + lexString(Source, Toks); + + ASSERT_EQ(3U, Toks.size()); + + ASSERT_EQ(tok::text, Toks[0].getKind()); + ASSERT_EQ(StringRef(" "), Toks[0].getText()); + + ASSERT_EQ(tok::html_tag_close, Toks[1].getKind()); + ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagCloseName()); + + ASSERT_EQ(tok::newline, Toks[2].getKind()); +} + +TEST_F(CommentLexerTest, HTML14) { const char *Sources[] = { - "// </tag", "// </tag>", "// </ tag>", "// </ tag >" @@ -980,7 +1116,7 @@ TEST_F(CommentLexerTest, HTML13) { lexString(Sources[i], Toks); - ASSERT_EQ(3U, Toks.size()); + ASSERT_EQ(4U, Toks.size()); ASSERT_EQ(tok::text, Toks[0].getKind()); ASSERT_EQ(StringRef(" "), Toks[0].getText()); @@ -988,7 +1124,9 @@ TEST_F(CommentLexerTest, HTML13) { ASSERT_EQ(tok::html_tag_close, Toks[1].getKind()); ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagCloseName()); - ASSERT_EQ(tok::newline, Toks[2].getKind()); + ASSERT_EQ(tok::html_greater, Toks[2].getKind()); + + ASSERT_EQ(tok::newline, Toks[3].getKind()); } } diff --git a/clang/unittests/AST/CommentParser.cpp b/clang/unittests/AST/CommentParser.cpp new file mode 100644 index 00000000000..d5dd0a9c56b --- /dev/null +++ b/clang/unittests/AST/CommentParser.cpp @@ -0,0 +1,1126 @@ +//===- unittests/AST/CommentParser.cpp ------ Comment parser tests --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/AST/Comment.h" +#include "clang/AST/CommentLexer.h" +#include "clang/AST/CommentParser.h" +#include "clang/AST/CommentSema.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Allocator.h" +#include <vector> + +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace clang { +namespace comments { + +namespace { + +const bool DEBUG = true; + +class CommentParserTest : public ::testing::Test { +protected: + CommentParserTest() + : FileMgr(FileMgrOpts), + DiagID(new DiagnosticIDs()), + Diags(DiagID, new IgnoringDiagConsumer()), + SourceMgr(Diags, FileMgr) { + } + + FileSystemOptions FileMgrOpts; + FileManager FileMgr; + IntrusiveRefCntPtr<DiagnosticIDs> DiagID; + DiagnosticsEngine Diags; + SourceManager SourceMgr; + llvm::BumpPtrAllocator Allocator; + + FullComment *parseString(const char *Source); +}; + +FullComment *CommentParserTest::parseString(const char *Source) { + MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(Source); + FileID File = SourceMgr.createFileIDForMemBuffer(Buf); + SourceLocation Begin = SourceMgr.getLocForStartOfFile(File); + + comments::Lexer L(Begin, CommentOptions(), + Source, Source + strlen(Source)); + + comments::Sema S(Allocator); + comments::Parser P(L, S, Allocator); + comments::FullComment *FC = P.parseFullComment(); + + if (DEBUG) { + llvm::errs() << "=== Source:\n" << Source << "\n=== AST:\n"; + FC->dump(SourceMgr); + } + + Token Tok; + L.lex(Tok); + if (Tok.is(tok::eof)) + return FC; + else + return NULL; +} + +::testing::AssertionResult HasChildCount(const Comment *C, size_t Count) { + if (!C) + return ::testing::AssertionFailure() << "Comment is NULL"; + + if (Count != C->child_count()) + return ::testing::AssertionFailure() + << "Count = " << Count + << ", child_count = " << C->child_count(); + + return ::testing::AssertionSuccess(); +} + +template <typename T> +::testing::AssertionResult GetChildAt(const Comment *C, + size_t Idx, + T *&Child) { + if (!C) + return ::testing::AssertionFailure() << "Comment is NULL"; + + if (Idx >= C->child_count()) + return ::testing::AssertionFailure() + << "Idx out of range. Idx = " << Idx + << ", child_count = " << C->child_count(); + + Comment::child_iterator I = C->child_begin() + Idx; + Comment *CommentChild = *I; + if (!CommentChild) + return ::testing::AssertionFailure() << "Child is NULL"; + + Child = dyn_cast<T>(CommentChild); + if (!Child) + return ::testing::AssertionFailure() + << "Child is not of requested type, but a " + << CommentChild->getCommentKindName(); + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult HasTextAt(const Comment *C, + size_t Idx, + StringRef Text) { + TextComment *TC; + ::testing::AssertionResult AR = GetChildAt(C, Idx, TC); + if (!AR) + return AR; + + StringRef ActualText = TC->getText(); + if (ActualText != Text) + return ::testing::AssertionFailure() + << "TextComment has text \"" << ActualText.str() << "\", " + "expected \"" << Text.str() << "\""; + + if (TC->hasTrailingNewline()) + return ::testing::AssertionFailure() + << "TextComment has a trailing newline"; + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult HasTextWithNewlineAt(const Comment *C, + size_t Idx, + StringRef Text) { + TextComment *TC; + ::testing::AssertionResult AR = GetChildAt(C, Idx, TC); + if (!AR) + return AR; + + StringRef ActualText = TC->getText(); + if (ActualText != Text) + return ::testing::AssertionFailure() + << "TextComment has text \"" << ActualText.str() << "\", " + "expected \"" << Text.str() << "\""; + + if (!TC->hasTrailingNewline()) + return ::testing::AssertionFailure() + << "TextComment has no trailing newline"; + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult HasBlockCommandAt(const Comment *C, + size_t Idx, + BlockCommandComment *&BCC, + StringRef Name, + ParagraphComment *&Paragraph) { + ::testing::AssertionResult AR = GetChildAt(C, Idx, BCC); + if (!AR) + return AR; + + StringRef ActualName = BCC->getCommandName(); + if (ActualName != Name) + return ::testing::AssertionFailure() + << "BlockCommandComment has name \"" << ActualName.str() << "\", " + "expected \"" << Name.str() << "\""; + + Paragraph = BCC->getParagraph(); + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult HasParamCommandAt( + const Comment *C, + size_t Idx, + ParamCommandComment *&PCC, + StringRef CommandName, + ParamCommandComment::PassDirection Direction, + bool IsDirectionExplicit, + StringRef ParamName, + ParagraphComment *&Paragraph) { + ::testing::AssertionResult AR = GetChildAt(C, Idx, PCC); + if (!AR) + return AR; + + StringRef ActualCommandName = PCC->getCommandName(); + if (ActualCommandName != CommandName) + return ::testing::AssertionFailure() + << "ParamCommandComment has name \"" << ActualCommandName.str() << "\", " + "expected \"" << CommandName.str() << "\""; + + if (PCC->getDirection() != Direction) + return ::testing::AssertionFailure() + << "ParamCommandComment has direction " << PCC->getDirection() << ", " + "expected " << Direction; + + if (PCC->isDirectionExplicit() != IsDirectionExplicit) + return ::testing::AssertionFailure() + << "ParamCommandComment has " + << (PCC->isDirectionExplicit() ? "explicit" : "implicit") + << " direction, " + "expected " << (IsDirectionExplicit ? "explicit" : "implicit"); + + StringRef ActualParamName = PCC->getParamName(); + if (ActualParamName != ParamName) + return ::testing::AssertionFailure() + << "ParamCommandComment has name \"" << ActualParamName.str() << "\", " + "expected \"" << ParamName.str() << "\""; + + Paragraph = PCC->getParagraph(); + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult HasInlineCommandAt(const Comment *C, + size_t Idx, + InlineCommandComment *&ICC, + StringRef Name) { + ::testing::AssertionResult AR = GetChildAt(C, Idx, ICC); + if (!AR) + return AR; + + StringRef ActualName = ICC->getCommandName(); + if (ActualName != Name) + return ::testing::AssertionFailure() + << "InlineCommandComment has name \"" << ActualName.str() << "\", " + "expected \"" << Name.str() << "\""; + + return ::testing::AssertionSuccess(); +} + +struct NoArgs {}; + +::testing::AssertionResult HasInlineCommandAt(const Comment *C, + size_t Idx, + InlineCommandComment *&ICC, + StringRef Name, + NoArgs) { + ::testing::AssertionResult AR = HasInlineCommandAt(C, Idx, ICC, Name); + if (!AR) + return AR; + + if (ICC->getArgCount() != 0) + return ::testing::AssertionFailure() + << "InlineCommandComment has " << ICC->getArgCount() << " arg(s), " + "expected 0"; + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult HasInlineCommandAt(const Comment *C, + size_t Idx, + InlineCommandComment *&ICC, + StringRef Name, + StringRef Arg) { + ::testing::AssertionResult AR = HasInlineCommandAt(C, Idx, ICC, Name); + if (!AR) + return AR; + + if (ICC->getArgCount() != 1) + return ::testing::AssertionFailure() + << "InlineCommandComment has " << ICC->getArgCount() << " arg(s), " + "expected 1"; + + StringRef ActualArg = ICC->getArgText(0); + if (ActualArg != Arg) + return ::testing::AssertionFailure() + << "InlineCommandComment has argument \"" << ActualArg.str() << "\", " + "expected \"" << Arg.str() << "\""; + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult HasHTMLOpenTagAt(const Comment *C, + size_t Idx, + HTMLOpenTagComment *&HOT, + StringRef TagName) { + ::testing::AssertionResult AR = GetChildAt(C, Idx, HOT); + if (!AR) + return AR; + + StringRef ActualTagName = HOT->getTagName(); + if (ActualTagName != TagName) + return ::testing::AssertionFailure() + << "HTMLOpenTagComment has name \"" << ActualTagName.str() << "\", " + "expected \"" << TagName.str() << "\""; + + return ::testing::AssertionSuccess(); +} + +struct NoAttrs {}; + +::testing::AssertionResult HasHTMLOpenTagAt(const Comment *C, + size_t Idx, + HTMLOpenTagComment *&HOT, + StringRef TagName, + NoAttrs) { + ::testing::AssertionResult AR = HasHTMLOpenTagAt(C, Idx, HOT, TagName); + if (!AR) + return AR; + + if (HOT->getAttrCount() != 0) + return ::testing::AssertionFailure() + << "HTMLOpenTagComment has " << HOT->getAttrCount() << " attr(s), " + "expected 0"; + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult HasHTMLOpenTagAt(const Comment *C, + size_t Idx, + HTMLOpenTagComment *&HOT, + StringRef TagName, + StringRef AttrName, + StringRef AttrValue) { + ::testing::AssertionResult AR = HasHTMLOpenTagAt(C, Idx, HOT, TagName); + if (!AR) + return AR; + + if (HOT->getAttrCount() != 1) + return ::testing::AssertionFailure() + << "HTMLOpenTagComment has " << HOT->getAttrCount() << " attr(s), " + "expected 1"; + + StringRef ActualName = HOT->getAttr(0).Name; + if (ActualName != AttrName) + return ::testing::AssertionFailure() + << "HTMLOpenTagComment has attr \"" << ActualName.str() << "\", " + "expected \"" << AttrName.str() << "\""; + + StringRef ActualValue = HOT->getAttr(0).Value; + if (ActualValue != AttrValue) + return ::testing::AssertionFailure() + << "HTMLOpenTagComment has attr value \"" << ActualValue.str() << "\", " + "expected \"" << AttrValue.str() << "\""; + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult HasHTMLCloseTagAt(const Comment *C, + size_t Idx, + HTMLCloseTagComment *&HCT, + StringRef TagName) { + ::testing::AssertionResult AR = GetChildAt(C, Idx, HCT); + if (!AR) + return AR; + + StringRef ActualTagName = HCT->getTagName(); + if (ActualTagName != TagName) + return ::testing::AssertionFailure() + << "HTMLCloseTagComment has name \"" << ActualTagName.str() << "\", " + "expected \"" << TagName.str() << "\""; + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult HasVerbatimBlockAt(const Comment *C, + size_t Idx, + VerbatimBlockComment *&VBC, + StringRef Name) { + ::testing::AssertionResult AR = GetChildAt(C, Idx, VBC); + if (!AR) + return AR; + + StringRef ActualName = VBC->getCommandName(); + if (ActualName != Name) + return ::testing::AssertionFailure() + << "VerbatimBlockComment has name \"" << ActualName.str() << "\", " + "expected \"" << Name.str() << "\""; + + return ::testing::AssertionSuccess(); +} + +struct NoLines {}; + +::testing::AssertionResult HasVerbatimBlockAt(const Comment *C, + size_t Idx, + VerbatimBlockComment *&VBC, + StringRef Name, + NoLines) { + ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Idx, VBC, Name); + if (!AR) + return AR; + + if (VBC->getLineCount() != 0) + return ::testing::AssertionFailure() + << "VerbatimBlockComment has " << VBC->getLineCount() << " lines(s), " + "expected 0"; + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult HasVerbatimBlockAt(const Comment *C, + size_t Idx, + VerbatimBlockComment *&VBC, + StringRef Name, + StringRef Line0) { + ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Idx, VBC, Name); + if (!AR) + return AR; + + if (VBC->getLineCount() != 1) + return ::testing::AssertionFailure() + << "VerbatimBlockComment has " << VBC->getLineCount() << " lines(s), " + "expected 1"; + + StringRef ActualLine0 = VBC->getText(0); + if (ActualLine0 != Line0) + return ::testing::AssertionFailure() + << "VerbatimBlockComment has lines[0] \"" << ActualLine0.str() << "\", " + "expected \"" << Line0.str() << "\""; + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult HasVerbatimBlockAt(const Comment *C, + size_t Idx, + VerbatimBlockComment *&VBC, + StringRef Name, + StringRef Line0, + StringRef Line1) { + ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Idx, VBC, Name); + if (!AR) + return AR; + + if (VBC->getLineCount() != 2) + return ::testing::AssertionFailure() + << "VerbatimBlockComment has " << VBC->getLineCount() << " lines(s), " + "expected 2"; + + StringRef ActualLine0 = VBC->getText(0); + if (ActualLine0 != Line0) + return ::testing::AssertionFailure() + << "VerbatimBlockComment has lines[0] \"" << ActualLine0.str() << "\", " + "expected \"" << Line0.str() << "\""; + + StringRef ActualLine1 = VBC->getText(1); + if (ActualLine1 != Line1) + return ::testing::AssertionFailure() + << "VerbatimBlockComment has lines[1] \"" << ActualLine1.str() << "\", " + "expected \"" << Line1.str() << "\""; + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult HasVerbatimLineAt(const Comment *C, + size_t Idx, + VerbatimLineComment *&VLC, + StringRef Name, + StringRef Text) { + ::testing::AssertionResult AR = GetChildAt(C, Idx, VLC); + if (!AR) + return AR; + + StringRef ActualName = VLC->getCommandName(); + if (ActualName != Name) + return ::testing::AssertionFailure() + << "VerbatimLineComment has name \"" << ActualName.str() << "\", " + "expected \"" << Name.str() << "\""; + + StringRef ActualText = VLC->getText(); + if (ActualText != Text) + return ::testing::AssertionFailure() + << "VerbatimLineComment has text \"" << ActualText.str() << "\", " + "expected \"" << Text.str() << "\""; + + return ::testing::AssertionSuccess(); +} + + +TEST_F(CommentParserTest, Basic1) { + const char *Source = "//"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 0)); +} + +TEST_F(CommentParserTest, Basic2) { + const char *Source = "// Meow"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " Meow")); + } +} + +TEST_F(CommentParserTest, Basic3) { + const char *Source = + "// Aaa\n" + "// Bbb"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 2)); + ASSERT_TRUE(HasTextWithNewlineAt(PC, 0, " Aaa")); + ASSERT_TRUE(HasTextAt(PC, 1, " Bbb")); + } +} + +TEST_F(CommentParserTest, Paragraph1) { + const char *Sources[] = { + "// Aaa\n" + "//\n" + "// Bbb", + + "// Aaa\n" + "//\n" + "//\n" + "// Bbb", + }; + + + for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { + FullComment *FC = parseString(Sources[i]); + ASSERT_TRUE(HasChildCount(FC, 2)); + + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " Aaa")); + } + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 1, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " Bbb")); + } + } +} + +TEST_F(CommentParserTest, Paragraph2) { + const char *Source = + "// \\brief Aaa\n" + "//\n" + "// Bbb"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 3)); + + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + BlockCommandComment *BCC; + ParagraphComment *PC; + ASSERT_TRUE(HasBlockCommandAt(FC, 1, BCC, "brief", PC)); + + ASSERT_TRUE(GetChildAt(BCC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " Aaa")); + } + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 2, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " Bbb")); + } +} + +TEST_F(CommentParserTest, Paragraph3) { + const char *Source = "// \\brief \\author"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 3)); + + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + BlockCommandComment *BCC; + ParagraphComment *PC; + ASSERT_TRUE(HasBlockCommandAt(FC, 1, BCC, "brief", PC)); + + ASSERT_TRUE(GetChildAt(BCC, 0, PC)); + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + BlockCommandComment *BCC; + ParagraphComment *PC; + ASSERT_TRUE(HasBlockCommandAt(FC, 2, BCC, "author", PC)); + + ASSERT_TRUE(GetChildAt(BCC, 0, PC)); + ASSERT_TRUE(HasChildCount(PC, 0)); + } +} + +TEST_F(CommentParserTest, Paragraph4) { + const char *Source = + "// \\brief Aaa\n" + "// Bbb \\author\n" + "// Ccc"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 3)); + + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + BlockCommandComment *BCC; + ParagraphComment *PC; + ASSERT_TRUE(HasBlockCommandAt(FC, 1, BCC, "brief", PC)); + + ASSERT_TRUE(GetChildAt(BCC, 0, PC)); + ASSERT_TRUE(HasChildCount(PC, 2)); + ASSERT_TRUE(HasTextWithNewlineAt(PC, 0, " Aaa")); + ASSERT_TRUE(HasTextAt(PC, 1, " Bbb ")); + } + { + BlockCommandComment *BCC; + ParagraphComment *PC; + ASSERT_TRUE(HasBlockCommandAt(FC, 2, BCC, "author", PC)); + + ASSERT_TRUE(GetChildAt(BCC, 0, PC)); + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " Ccc")); + } +} + +TEST_F(CommentParserTest, ParamCommand1) { + const char *Source = + "// \\param aaa\n" + "// \\param [in] aaa\n" + "// \\param [out] aaa\n" + "// \\param [in,out] aaa\n" + "// \\param [in, out] aaa\n"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 6)); + + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + ParamCommandComment *PCC; + ParagraphComment *PC; + ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param", + ParamCommandComment::In, + /* IsDirectionExplicit = */ false, + "aaa", PC)); + ASSERT_TRUE(HasChildCount(PCC, 1)); + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + ParamCommandComment *PCC; + ParagraphComment *PC; + ASSERT_TRUE(HasParamCommandAt(FC, 2, PCC, "param", + ParamCommandComment::In, + /* IsDirectionExplicit = */ true, + "aaa", PC)); + ASSERT_TRUE(HasChildCount(PCC, 1)); + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + ParamCommandComment *PCC; + ParagraphComment *PC; + ASSERT_TRUE(HasParamCommandAt(FC, 3, PCC, "param", + ParamCommandComment::Out, + /* IsDirectionExplicit = */ true, + "aaa", PC)); + ASSERT_TRUE(HasChildCount(PCC, 1)); + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + ParamCommandComment *PCC; + ParagraphComment *PC; + ASSERT_TRUE(HasParamCommandAt(FC, 4, PCC, "param", + ParamCommandComment::InOut, + /* IsDirectionExplicit = */ true, + "aaa", PC)); + ASSERT_TRUE(HasChildCount(PCC, 1)); + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + ParamCommandComment *PCC; + ParagraphComment *PC; + ASSERT_TRUE(HasParamCommandAt(FC, 5, PCC, "param", + ParamCommandComment::InOut, + /* IsDirectionExplicit = */ true, + "aaa", PC)); + ASSERT_TRUE(HasChildCount(PCC, 1)); + ASSERT_TRUE(HasChildCount(PC, 0)); + } +} + +TEST_F(CommentParserTest, InlineCommand1) { + const char *Source = "// \\c"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + ParagraphComment *PC; + InlineCommandComment *ICC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 2)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", NoArgs())); + } +} + +TEST_F(CommentParserTest, InlineCommand2) { + const char *Source = "// \\c "; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + ParagraphComment *PC; + InlineCommandComment *ICC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 3)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", NoArgs())); + ASSERT_TRUE(HasTextAt(PC, 2, " ")); + } +} + +TEST_F(CommentParserTest, InlineCommand3) { + const char *Source = "// \\c aaa\n"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + ParagraphComment *PC; + InlineCommandComment *ICC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 2)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", "aaa")); + } +} + +TEST_F(CommentParserTest, InlineCommand4) { + const char *Source = "// \\c aaa bbb"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + ParagraphComment *PC; + InlineCommandComment *ICC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 3)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", "aaa")); + ASSERT_TRUE(HasTextAt(PC, 2, " bbb")); + } +} + +TEST_F(CommentParserTest, InlineCommand5) { + const char *Source = "// \\unknown aaa\n"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + ParagraphComment *PC; + InlineCommandComment *ICC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 3)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "unknown", NoArgs())); + ASSERT_TRUE(HasTextAt(PC, 2, " aaa")); + } +} + +TEST_F(CommentParserTest, HTML1) { + const char *Sources[] = { + "// <a", + "// <a>", + "// <a >" + }; + + for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { + FullComment *FC = parseString(Sources[i]); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + ParagraphComment *PC; + HTMLOpenTagComment *HOT; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 2)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + ASSERT_TRUE(HasHTMLOpenTagAt(PC, 1, HOT, "a", NoAttrs())); + } + } +} + +TEST_F(CommentParserTest, HTML2) { + const char *Sources[] = { + "// <a href", + "// <a href ", + "// <a href>", + "// <a href >", + }; + + for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { + FullComment *FC = parseString(Sources[i]); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + ParagraphComment *PC; + HTMLOpenTagComment *HOT; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 2)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + ASSERT_TRUE(HasHTMLOpenTagAt(PC, 1, HOT, "a", "href", "")); + } + } +} + +TEST_F(CommentParserTest, HTML3) { + const char *Sources[] = { + "// <a href=\"bbb\"", + "// <a href=\"bbb\">", + }; + + for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { + FullComment *FC = parseString(Sources[i]); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + ParagraphComment *PC; + HTMLOpenTagComment *HOT; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 2)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + ASSERT_TRUE(HasHTMLOpenTagAt(PC, 1, HOT, "a", "href", "bbb")); + } + } +} + +TEST_F(CommentParserTest, HTML4) { + const char *Sources[] = { + "// </a", + "// </a>", + "// </a >" + }; + + for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { + FullComment *FC = parseString(Sources[i]); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + ParagraphComment *PC; + HTMLCloseTagComment *HCT; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 2)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + ASSERT_TRUE(HasHTMLCloseTagAt(PC, 1, HCT, "a")); + } + } +} + +TEST_F(CommentParserTest, HTML5) { + const char *Source = + "// <pre>\n" + "// Aaa\n" + "// Bbb\n" + "// </pre>\n"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + ParagraphComment *PC; + HTMLOpenTagComment *HOT; + HTMLCloseTagComment *HCT; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 6)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + ASSERT_TRUE(HasHTMLOpenTagAt(PC, 1, HOT, "pre", NoAttrs())); + ASSERT_TRUE(HasTextWithNewlineAt(PC, 2, " Aaa")); + ASSERT_TRUE(HasTextWithNewlineAt(PC, 3, " Bbb")); + ASSERT_TRUE(HasTextAt(PC, 4, " ")); + ASSERT_TRUE(HasHTMLCloseTagAt(PC, 5, HCT, "pre")); + } +} + +TEST_F(CommentParserTest, VerbatimBlock1) { + const char *Source = "// \\verbatim\\endverbatim\n"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 2)); + + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + VerbatimBlockComment *VCC; + ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VCC, "verbatim", NoLines())); + } +} + +TEST_F(CommentParserTest, VerbatimBlock2) { + const char *Source = "// \\verbatim Aaa \\endverbatim\n"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 2)); + + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + VerbatimBlockComment *VBC; + ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", " Aaa ")); + } +} + +TEST_F(CommentParserTest, VerbatimBlock3) { + const char *Source = + "//\\verbatim\n" + "//\\endverbatim\n"; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + VerbatimBlockComment *VBC; + ASSERT_TRUE(HasVerbatimBlockAt(FC, 0, VBC, "verbatim", NoLines())); + } +} + +TEST_F(CommentParserTest, VerbatimBlock4) { + const char *Sources[] = { + "//\\verbatim\n" + "// Aaa\n" + "//\\endverbatim\n", + + "/*\\verbatim\n" + " * Aaa\n" + " *\\endverbatim*/" + }; + + for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { + FullComment *FC = parseString(Sources[i]); + ASSERT_TRUE(HasChildCount(FC, 1)); + + { + VerbatimBlockComment *VBC; + ASSERT_TRUE(HasVerbatimBlockAt(FC, 0, VBC, "verbatim", " Aaa")); + } + } +} + +TEST_F(CommentParserTest, VerbatimBlock5) { + const char *Sources[] = { + "// \\verbatim\n" + "// Aaa\n" + "// \\endverbatim\n", + + "/* \\verbatim\n" + " * Aaa\n" + " * \\endverbatim*/" + }; + + for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { + FullComment *FC = parseString(Sources[i]); + ASSERT_TRUE(HasChildCount(FC, 2)); + + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + VerbatimBlockComment *VBC; + ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", " Aaa", " ")); + } + } +} + +TEST_F(CommentParserTest, VerbatimBlock6) { + const char *Sources[] = { + "// \\verbatim\n" + "// Aaa\n" + "//\n" + "// Bbb\n" + "// \\endverbatim\n", + + "/* \\verbatim\n" + " * Aaa\n" + " *\n" + " * Bbb\n" + " * \\endverbatim*/" + }; + for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { + FullComment *FC = parseString(Sources[i]); + ASSERT_TRUE(HasChildCount(FC, 2)); + + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + VerbatimBlockComment *VBC; + ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim")); + ASSERT_EQ(4U, VBC->getLineCount()); + ASSERT_EQ(" Aaa", VBC->getText(0)); + ASSERT_EQ("", VBC->getText(1)); + ASSERT_EQ(" Bbb", VBC->getText(2)); + ASSERT_EQ(" ", VBC->getText(3)); + } + } +} + +TEST_F(CommentParserTest, VerbatimLine1) { + const char *Sources[] = { + "// \\fn", + "// \\fn\n" + }; + + for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { + FullComment *FC = parseString(Sources[i]); + ASSERT_TRUE(HasChildCount(FC, 2)); + + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + VerbatimLineComment *VLC; + ASSERT_TRUE(HasVerbatimLineAt(FC, 1, VLC, "fn", "")); + } + } +} + +TEST_F(CommentParserTest, VerbatimLine2) { + const char *Sources[] = { + "/// \\fn void *foo(const char *zzz = \"\\$\");\n//", + "/** \\fn void *foo(const char *zzz = \"\\$\");*/" + }; + + for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { + FullComment *FC = parseString(Sources[i]); + ASSERT_TRUE(HasChildCount(FC, 2)); + + { + ParagraphComment *PC; + ASSERT_TRUE(GetChildAt(FC, 0, PC)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ")); + } + { + VerbatimLineComment *VLC; + ASSERT_TRUE(HasVerbatimLineAt(FC, 1, VLC, "fn", + " void *foo(const char *zzz = \"\\$\");")); + } + } +} + +} // unnamed namespace + +} // end namespace comments +} // end namespace clang + |