diff options
Diffstat (limited to 'unittests/AST')
-rw-r--r-- | unittests/AST/CMakeLists.txt | 5 | ||||
-rw-r--r-- | unittests/AST/CommentLexer.cpp | 327 | ||||
-rw-r--r-- | unittests/AST/CommentParser.cpp | 125 | ||||
-rw-r--r-- | unittests/AST/DeclPrinterTest.cpp | 1248 | ||||
-rw-r--r-- | unittests/AST/Makefile | 8 | ||||
-rw-r--r-- | unittests/AST/SourceLocationTest.cpp | 289 | ||||
-rw-r--r-- | unittests/AST/StmtPrinterTest.cpp | 172 |
7 files changed, 1999 insertions, 175 deletions
diff --git a/unittests/AST/CMakeLists.txt b/unittests/AST/CMakeLists.txt index 63418a2937a16..1ea293ee83ae7 100644 --- a/unittests/AST/CMakeLists.txt +++ b/unittests/AST/CMakeLists.txt @@ -1,8 +1,11 @@ add_clang_unittest(ASTTests CommentLexer.cpp CommentParser.cpp + DeclPrinterTest.cpp + SourceLocationTest.cpp + StmtPrinterTest.cpp ) target_link_libraries(ASTTests - clangAST + clangAST clangASTMatchers clangTooling ) diff --git a/unittests/AST/CommentLexer.cpp b/unittests/AST/CommentLexer.cpp index cab0fdddbc2fb..2723a611e1064 100644 --- a/unittests/AST/CommentLexer.cpp +++ b/unittests/AST/CommentLexer.cpp @@ -10,6 +10,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/AST/CommentLexer.h" #include "clang/AST/CommentCommandTraits.h" #include "llvm/ADT/STLExtras.h" @@ -29,8 +30,9 @@ protected: CommentLexerTest() : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()), - Diags(DiagID, new IgnoringDiagConsumer()), - SourceMgr(Diags, FileMgr) { + Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), + SourceMgr(Diags, FileMgr), + Traits(Allocator) { } FileSystemOptions FileMgrOpts; @@ -39,8 +41,21 @@ protected: DiagnosticsEngine Diags; SourceManager SourceMgr; llvm::BumpPtrAllocator Allocator; + CommandTraits Traits; void lexString(const char *Source, std::vector<Token> &Toks); + + StringRef getCommandName(const Token &Tok) { + return Traits.getCommandInfo(Tok.getCommandID())->Name; + } + + StringRef getVerbatimBlockName(const Token &Tok) { + return Traits.getCommandInfo(Tok.getVerbatimBlockID())->Name; + } + + StringRef getVerbatimLineName(const Token &Tok) { + return Traits.getCommandInfo(Tok.getVerbatimLineID())->Name; + } }; void CommentLexerTest::lexString(const char *Source, @@ -49,9 +64,7 @@ void CommentLexerTest::lexString(const char *Source, FileID File = SourceMgr.createFileIDForMemBuffer(Buf); SourceLocation Begin = SourceMgr.getLocForStartOfFile(File); - comments::CommandTraits Traits; - comments::Lexer L(Allocator, Traits, Begin, CommentOptions(), - Source, Source + strlen(Source)); + Lexer L(Allocator, Traits, Begin, Source, Source + strlen(Source)); while (1) { Token Tok; @@ -310,7 +323,35 @@ TEST_F(CommentLexerTest, DoxygenCommand4) { } } +// A command marker followed by a non-letter that is not a part of an escape +// sequence. TEST_F(CommentLexerTest, DoxygenCommand5) { + const char *Source = "/// \\^ \\0"; + std::vector<Token> Toks; + + lexString(Source, Toks); + + ASSERT_EQ(6U, Toks.size()); + + ASSERT_EQ(tok::text, Toks[0].getKind()); + ASSERT_EQ(StringRef(" "), Toks[0].getText()); + + ASSERT_EQ(tok::text, Toks[1].getKind()); + ASSERT_EQ(StringRef("\\"), Toks[1].getText()); + + ASSERT_EQ(tok::text, Toks[2].getKind()); + ASSERT_EQ(StringRef("^ "), Toks[2].getText()); + + ASSERT_EQ(tok::text, Toks[3].getKind()); + ASSERT_EQ(StringRef("\\"), Toks[3].getText()); + + ASSERT_EQ(tok::text, Toks[4].getKind()); + ASSERT_EQ(StringRef("0"), Toks[4].getText()); + + ASSERT_EQ(tok::newline, Toks[5].getKind()); +} + +TEST_F(CommentLexerTest, DoxygenCommand6) { const char *Source = "/// \\brief Aaa."; std::vector<Token> Toks; @@ -322,7 +363,7 @@ TEST_F(CommentLexerTest, DoxygenCommand5) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::command, Toks[1].getKind()); - ASSERT_EQ(StringRef("brief"), Toks[1].getCommandName()); + ASSERT_EQ(StringRef("brief"), getCommandName(Toks[1])); ASSERT_EQ(tok::text, Toks[2].getKind()); ASSERT_EQ(StringRef(" Aaa."), Toks[2].getText()); @@ -330,7 +371,39 @@ TEST_F(CommentLexerTest, DoxygenCommand5) { ASSERT_EQ(tok::newline, Toks[3].getKind()); } -TEST_F(CommentLexerTest, DoxygenCommand6) { +TEST_F(CommentLexerTest, DoxygenCommand7) { + const char *Source = "/// \\em\\em \\em\t\\em\n"; + std::vector<Token> Toks; + + lexString(Source, Toks); + + ASSERT_EQ(8U, 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("em"), getCommandName(Toks[1])); + + ASSERT_EQ(tok::command, Toks[2].getKind()); + ASSERT_EQ(StringRef("em"), getCommandName(Toks[2])); + + ASSERT_EQ(tok::text, Toks[3].getKind()); + ASSERT_EQ(StringRef(" "), Toks[3].getText()); + + ASSERT_EQ(tok::command, Toks[4].getKind()); + ASSERT_EQ(StringRef("em"), getCommandName(Toks[4])); + + ASSERT_EQ(tok::text, Toks[5].getKind()); + ASSERT_EQ(StringRef("\t"), Toks[5].getText()); + + ASSERT_EQ(tok::command, Toks[6].getKind()); + ASSERT_EQ(StringRef("em"), getCommandName(Toks[6])); + + ASSERT_EQ(tok::newline, Toks[7].getKind()); +} + +TEST_F(CommentLexerTest, DoxygenCommand8) { const char *Source = "/// \\aaa\\bbb \\ccc\t\\ddd\n"; std::vector<Token> Toks; @@ -341,28 +414,28 @@ TEST_F(CommentLexerTest, DoxygenCommand6) { ASSERT_EQ(tok::text, Toks[0].getKind()); ASSERT_EQ(StringRef(" "), Toks[0].getText()); - ASSERT_EQ(tok::command, Toks[1].getKind()); - ASSERT_EQ(StringRef("aaa"), Toks[1].getCommandName()); + ASSERT_EQ(tok::unknown_command, Toks[1].getKind()); + ASSERT_EQ(StringRef("aaa"), Toks[1].getUnknownCommandName()); - ASSERT_EQ(tok::command, Toks[2].getKind()); - ASSERT_EQ(StringRef("bbb"), Toks[2].getCommandName()); + ASSERT_EQ(tok::unknown_command, Toks[2].getKind()); + ASSERT_EQ(StringRef("bbb"), Toks[2].getUnknownCommandName()); ASSERT_EQ(tok::text, Toks[3].getKind()); ASSERT_EQ(StringRef(" "), Toks[3].getText()); - ASSERT_EQ(tok::command, Toks[4].getKind()); - ASSERT_EQ(StringRef("ccc"), Toks[4].getCommandName()); + ASSERT_EQ(tok::unknown_command, Toks[4].getKind()); + ASSERT_EQ(StringRef("ccc"), Toks[4].getUnknownCommandName()); ASSERT_EQ(tok::text, Toks[5].getKind()); ASSERT_EQ(StringRef("\t"), Toks[5].getText()); - ASSERT_EQ(tok::command, Toks[6].getKind()); - ASSERT_EQ(StringRef("ddd"), Toks[6].getCommandName()); + ASSERT_EQ(tok::unknown_command, Toks[6].getKind()); + ASSERT_EQ(StringRef("ddd"), Toks[6].getUnknownCommandName()); ASSERT_EQ(tok::newline, Toks[7].getKind()); } -TEST_F(CommentLexerTest, DoxygenCommand7) { +TEST_F(CommentLexerTest, DoxygenCommand9) { const char *Source = "// \\c\n"; std::vector<Token> Toks; @@ -374,7 +447,7 @@ TEST_F(CommentLexerTest, DoxygenCommand7) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::command, Toks[1].getKind()); - ASSERT_EQ(StringRef("c"), Toks[1].getCommandName()); + ASSERT_EQ(StringRef("c"), getCommandName(Toks[1])); ASSERT_EQ(tok::newline, Toks[2].getKind()); } @@ -397,10 +470,10 @@ TEST_F(CommentLexerTest, VerbatimBlock1) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); - ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); + ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1])); ASSERT_EQ(tok::verbatim_block_end, Toks[2].getKind()); - ASSERT_EQ(StringRef("endverbatim"), Toks[2].getVerbatimBlockName()); + ASSERT_EQ(StringRef("endverbatim"), getVerbatimBlockName(Toks[2])); ASSERT_EQ(tok::newline, Toks[3].getKind()); ASSERT_EQ(tok::newline, Toks[4].getKind()); @@ -421,7 +494,7 @@ TEST_F(CommentLexerTest, VerbatimBlock2) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); - ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); + ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1])); ASSERT_EQ(tok::newline, Toks[2].getKind()); } @@ -440,7 +513,7 @@ TEST_F(CommentLexerTest, VerbatimBlock3) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); - ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); + ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1])); ASSERT_EQ(tok::newline, Toks[2].getKind()); ASSERT_EQ(tok::newline, Toks[3].getKind()); @@ -464,13 +537,13 @@ TEST_F(CommentLexerTest, VerbatimBlock4) { ASSERT_EQ(StringRef(" Meow "), Toks[0].getText()); ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); - ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); + ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1])); ASSERT_EQ(tok::verbatim_block_line, Toks[2].getKind()); ASSERT_EQ(StringRef(" aaa "), Toks[2].getVerbatimBlockText()); ASSERT_EQ(tok::verbatim_block_end, Toks[3].getKind()); - ASSERT_EQ(StringRef("endverbatim"), Toks[3].getVerbatimBlockName()); + ASSERT_EQ(StringRef("endverbatim"), getVerbatimBlockName(Toks[3])); ASSERT_EQ(tok::newline, Toks[4].getKind()); ASSERT_EQ(tok::newline, Toks[5].getKind()); @@ -495,7 +568,7 @@ TEST_F(CommentLexerTest, VerbatimBlock5) { ASSERT_EQ(StringRef(" Meow "), Toks[0].getText()); ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); - ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); + ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1])); ASSERT_EQ(tok::verbatim_block_line, Toks[2].getKind()); ASSERT_EQ(StringRef(" aaa "), Toks[2].getVerbatimBlockText()); @@ -523,7 +596,7 @@ TEST_F(CommentLexerTest, VerbatimBlock6) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); - ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); + ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1])); ASSERT_EQ(tok::newline, Toks[2].getKind()); @@ -540,7 +613,7 @@ TEST_F(CommentLexerTest, VerbatimBlock6) { ASSERT_EQ(tok::newline, Toks[7].getKind()); ASSERT_EQ(tok::verbatim_block_end, Toks[8].getKind()); - ASSERT_EQ(StringRef("endverbatim"), Toks[8].getVerbatimBlockName()); + ASSERT_EQ(StringRef("endverbatim"), getVerbatimBlockName(Toks[8])); ASSERT_EQ(tok::newline, Toks[9].getKind()); } @@ -564,7 +637,7 @@ TEST_F(CommentLexerTest, VerbatimBlock7) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); - ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); + ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1])); ASSERT_EQ(tok::verbatim_block_line, Toks[2].getKind()); ASSERT_EQ(StringRef(" Aaa"), Toks[2].getVerbatimBlockText()); @@ -576,7 +649,7 @@ TEST_F(CommentLexerTest, VerbatimBlock7) { ASSERT_EQ(StringRef(" Bbb"), Toks[4].getVerbatimBlockText()); ASSERT_EQ(tok::verbatim_block_end, Toks[5].getKind()); - ASSERT_EQ(StringRef("endverbatim"), Toks[5].getVerbatimBlockName()); + ASSERT_EQ(StringRef("endverbatim"), getVerbatimBlockName(Toks[5])); ASSERT_EQ(tok::newline, Toks[6].getKind()); @@ -605,7 +678,7 @@ TEST_F(CommentLexerTest, VerbatimBlock8) { ASSERT_EQ(StringRef(" Meow "), Toks[0].getText()); ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); - ASSERT_EQ(StringRef("verbatim"), Toks[1].getVerbatimBlockName()); + ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[1])); ASSERT_EQ(tok::verbatim_block_line, Toks[2].getKind()); ASSERT_EQ(StringRef(" aaa\\$\\@"), Toks[2].getVerbatimBlockText()); @@ -620,19 +693,19 @@ TEST_F(CommentLexerTest, VerbatimBlock8) { ASSERT_EQ(StringRef("ddd "), Toks[5].getVerbatimBlockText()); ASSERT_EQ(tok::verbatim_block_end, Toks[6].getKind()); - ASSERT_EQ(StringRef("endverbatim"), Toks[6].getVerbatimBlockName()); + ASSERT_EQ(StringRef("endverbatim"), getVerbatimBlockName(Toks[6])); ASSERT_EQ(tok::text, Toks[7].getKind()); ASSERT_EQ(StringRef(" Blah "), Toks[7].getText()); ASSERT_EQ(tok::verbatim_block_begin, Toks[8].getKind()); - ASSERT_EQ(StringRef("verbatim"), Toks[8].getVerbatimBlockName()); + ASSERT_EQ(StringRef("verbatim"), getVerbatimBlockName(Toks[8])); ASSERT_EQ(tok::verbatim_block_line, Toks[9].getKind()); ASSERT_EQ(StringRef(" eee"), Toks[9].getVerbatimBlockText()); ASSERT_EQ(tok::verbatim_block_end, Toks[10].getKind()); - ASSERT_EQ(StringRef("endverbatim"), Toks[10].getVerbatimBlockName()); + ASSERT_EQ(StringRef("endverbatim"), getVerbatimBlockName(Toks[10])); ASSERT_EQ(tok::text, Toks[11].getKind()); ASSERT_EQ(StringRef(" BlahBlah"), Toks[11].getText()); @@ -655,37 +728,37 @@ TEST_F(CommentLexerTest, VerbatimBlock9) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::verbatim_block_begin, Toks[1].getKind()); - ASSERT_EQ(StringRef("f$"), Toks[1].getVerbatimBlockName()); + ASSERT_EQ(StringRef("f$"), getVerbatimBlockName(Toks[1])); ASSERT_EQ(tok::verbatim_block_line, Toks[2].getKind()); ASSERT_EQ(StringRef(" Aaa "), Toks[2].getVerbatimBlockText()); ASSERT_EQ(tok::verbatim_block_end, Toks[3].getKind()); - ASSERT_EQ(StringRef("f$"), Toks[3].getVerbatimBlockName()); + ASSERT_EQ(StringRef("f$"), getVerbatimBlockName(Toks[3])); ASSERT_EQ(tok::text, Toks[4].getKind()); ASSERT_EQ(StringRef(" "), Toks[4].getText()); ASSERT_EQ(tok::verbatim_block_begin, Toks[5].getKind()); - ASSERT_EQ(StringRef("f["), Toks[5].getVerbatimBlockName()); + ASSERT_EQ(StringRef("f["), getVerbatimBlockName(Toks[5])); ASSERT_EQ(tok::verbatim_block_line, Toks[6].getKind()); ASSERT_EQ(StringRef(" Bbb "), Toks[6].getVerbatimBlockText()); ASSERT_EQ(tok::verbatim_block_end, Toks[7].getKind()); - ASSERT_EQ(StringRef("f]"), Toks[7].getVerbatimBlockName()); + ASSERT_EQ(StringRef("f]"), getVerbatimBlockName(Toks[7])); ASSERT_EQ(tok::text, Toks[8].getKind()); ASSERT_EQ(StringRef(" "), Toks[8].getText()); ASSERT_EQ(tok::verbatim_block_begin, Toks[9].getKind()); - ASSERT_EQ(StringRef("f{"), Toks[9].getVerbatimBlockName()); + ASSERT_EQ(StringRef("f{"), getVerbatimBlockName(Toks[9])); ASSERT_EQ(tok::verbatim_block_line, Toks[10].getKind()); ASSERT_EQ(StringRef(" Ccc "), Toks[10].getVerbatimBlockText()); ASSERT_EQ(tok::verbatim_block_end, Toks[11].getKind()); - ASSERT_EQ(StringRef("f}"), Toks[11].getVerbatimBlockName()); + ASSERT_EQ(StringRef("f}"), getVerbatimBlockName(Toks[11])); ASSERT_EQ(tok::newline, Toks[12].getKind()); } @@ -708,7 +781,7 @@ TEST_F(CommentLexerTest, VerbatimLine1) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::verbatim_line_name, Toks[1].getKind()); - ASSERT_EQ(StringRef("fn"), Toks[1].getVerbatimLineName()); + ASSERT_EQ(StringRef("fn"), getVerbatimLineName(Toks[1])); ASSERT_EQ(tok::newline, Toks[2].getKind()); ASSERT_EQ(tok::newline, Toks[3].getKind()); @@ -733,7 +806,7 @@ TEST_F(CommentLexerTest, VerbatimLine2) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::verbatim_line_name, Toks[1].getKind()); - ASSERT_EQ(StringRef("fn"), Toks[1].getVerbatimLineName()); + ASSERT_EQ(StringRef("fn"), getVerbatimLineName(Toks[1])); ASSERT_EQ(tok::verbatim_line_text, Toks[2].getKind()); ASSERT_EQ(StringRef(" void *foo(const char *zzz = \"\\$\");"), @@ -761,7 +834,7 @@ TEST_F(CommentLexerTest, VerbatimLine3) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::verbatim_line_name, Toks[1].getKind()); - ASSERT_EQ(StringRef("fn"), Toks[1].getVerbatimLineName()); + ASSERT_EQ(StringRef("fn"), getVerbatimLineName(Toks[1])); ASSERT_EQ(tok::verbatim_line_text, Toks[2].getKind()); ASSERT_EQ(StringRef(" void *foo(const char *zzz = \"\\$\");"), @@ -822,7 +895,7 @@ TEST_F(CommentLexerTest, HTML2) { TEST_F(CommentLexerTest, HTML3) { const char *Source = - "// < tag"; + "// < img"; std::vector<Token> Toks; @@ -837,15 +910,15 @@ TEST_F(CommentLexerTest, HTML3) { ASSERT_EQ(StringRef("<"), Toks[1].getText()); ASSERT_EQ(tok::text, Toks[2].getKind()); - ASSERT_EQ(StringRef(" tag"), Toks[2].getText()); + ASSERT_EQ(StringRef(" img"), Toks[2].getText()); ASSERT_EQ(tok::newline, Toks[3].getKind()); } TEST_F(CommentLexerTest, HTML4) { const char *Sources[] = { - "// <tag", - "// <tag " + "// <img", + "// <img " }; for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { @@ -859,7 +932,7 @@ TEST_F(CommentLexerTest, HTML4) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_start_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName()); ASSERT_EQ(tok::newline, Toks[2].getKind()); } @@ -867,7 +940,7 @@ TEST_F(CommentLexerTest, HTML4) { TEST_F(CommentLexerTest, HTML5) { const char *Source = - "// <tag 42"; + "// <img 42"; std::vector<Token> Toks; @@ -879,7 +952,7 @@ TEST_F(CommentLexerTest, HTML5) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_start_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName()); ASSERT_EQ(tok::text, Toks[2].getKind()); ASSERT_EQ(StringRef("42"), Toks[2].getText()); @@ -888,7 +961,7 @@ TEST_F(CommentLexerTest, HTML5) { } TEST_F(CommentLexerTest, HTML6) { - const char *Source = "// <tag> Meow"; + const char *Source = "// <img> Meow"; std::vector<Token> Toks; @@ -900,7 +973,7 @@ TEST_F(CommentLexerTest, HTML6) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_start_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName()); ASSERT_EQ(tok::html_greater, Toks[2].getKind()); @@ -911,7 +984,7 @@ TEST_F(CommentLexerTest, HTML6) { } TEST_F(CommentLexerTest, HTML7) { - const char *Source = "// <tag="; + const char *Source = "// <img="; std::vector<Token> Toks; @@ -923,7 +996,7 @@ TEST_F(CommentLexerTest, HTML7) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_start_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName()); ASSERT_EQ(tok::text, Toks[2].getKind()); ASSERT_EQ(StringRef("="), Toks[2].getText()); @@ -932,7 +1005,7 @@ TEST_F(CommentLexerTest, HTML7) { } TEST_F(CommentLexerTest, HTML8) { - const char *Source = "// <tag attr=> Meow"; + const char *Source = "// <img src=> Meow"; std::vector<Token> Toks; @@ -944,10 +1017,10 @@ TEST_F(CommentLexerTest, HTML8) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_start_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName()); ASSERT_EQ(tok::html_ident, Toks[2].getKind()); - ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent()); + ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent()); ASSERT_EQ(tok::html_equals, Toks[3].getKind()); @@ -961,8 +1034,8 @@ TEST_F(CommentLexerTest, HTML8) { TEST_F(CommentLexerTest, HTML9) { const char *Sources[] = { - "// <tag attr", - "// <tag attr " + "// <img src", + "// <img src " }; for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { @@ -976,10 +1049,10 @@ TEST_F(CommentLexerTest, HTML9) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_start_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName()); ASSERT_EQ(tok::html_ident, Toks[2].getKind()); - ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent()); + ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent()); ASSERT_EQ(tok::newline, Toks[3].getKind()); } @@ -987,8 +1060,8 @@ TEST_F(CommentLexerTest, HTML9) { TEST_F(CommentLexerTest, HTML10) { const char *Sources[] = { - "// <tag attr=", - "// <tag attr =" + "// <img src=", + "// <img src =" }; for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { @@ -1002,10 +1075,10 @@ TEST_F(CommentLexerTest, HTML10) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_start_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName()); ASSERT_EQ(tok::html_ident, Toks[2].getKind()); - ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent()); + ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent()); ASSERT_EQ(tok::html_equals, Toks[3].getKind()); @@ -1015,10 +1088,10 @@ TEST_F(CommentLexerTest, HTML10) { TEST_F(CommentLexerTest, HTML11) { const char *Sources[] = { - "// <tag attr=\"", - "// <tag attr = \"", - "// <tag attr=\'", - "// <tag attr = \'" + "// <img src=\"", + "// <img src = \"", + "// <img src=\'", + "// <img src = \'" }; for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { @@ -1032,10 +1105,10 @@ TEST_F(CommentLexerTest, HTML11) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_start_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName()); ASSERT_EQ(tok::html_ident, Toks[2].getKind()); - ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent()); + ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent()); ASSERT_EQ(tok::html_equals, Toks[3].getKind()); @@ -1047,7 +1120,7 @@ TEST_F(CommentLexerTest, HTML11) { } TEST_F(CommentLexerTest, HTML12) { - const char *Source = "// <tag attr=@"; + const char *Source = "// <img src=@"; std::vector<Token> Toks; @@ -1059,10 +1132,10 @@ TEST_F(CommentLexerTest, HTML12) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_start_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName()); ASSERT_EQ(tok::html_ident, Toks[2].getKind()); - ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent()); + ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent()); ASSERT_EQ(tok::html_equals, Toks[3].getKind()); @@ -1074,10 +1147,10 @@ TEST_F(CommentLexerTest, HTML12) { TEST_F(CommentLexerTest, HTML13) { const char *Sources[] = { - "// <tag attr=\"val\\\"\\'val", - "// <tag attr=\"val\\\"\\'val\"", - "// <tag attr=\'val\\\"\\'val", - "// <tag attr=\'val\\\"\\'val\'" + "// <img src=\"val\\\"\\'val", + "// <img src=\"val\\\"\\'val\"", + "// <img src=\'val\\\"\\'val", + "// <img src=\'val\\\"\\'val\'" }; for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { @@ -1091,10 +1164,10 @@ TEST_F(CommentLexerTest, HTML13) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_start_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName()); ASSERT_EQ(tok::html_ident, Toks[2].getKind()); - ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent()); + ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent()); ASSERT_EQ(tok::html_equals, Toks[3].getKind()); @@ -1107,8 +1180,8 @@ TEST_F(CommentLexerTest, HTML13) { TEST_F(CommentLexerTest, HTML14) { const char *Sources[] = { - "// <tag attr=\"val\\\"\\'val\">", - "// <tag attr=\'val\\\"\\'val\'>" + "// <img src=\"val\\\"\\'val\">", + "// <img src=\'val\\\"\\'val\'>" }; for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { @@ -1122,10 +1195,10 @@ TEST_F(CommentLexerTest, HTML14) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_start_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName()); ASSERT_EQ(tok::html_ident, Toks[2].getKind()); - ASSERT_EQ(StringRef("attr"), Toks[2].getHTMLIdent()); + ASSERT_EQ(StringRef("src"), Toks[2].getHTMLIdent()); ASSERT_EQ(tok::html_equals, Toks[3].getKind()); @@ -1140,8 +1213,8 @@ TEST_F(CommentLexerTest, HTML14) { TEST_F(CommentLexerTest, HTML15) { const char *Sources[] = { - "// <tag/>", - "// <tag />" + "// <img/>", + "// <img />" }; for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { @@ -1155,7 +1228,7 @@ TEST_F(CommentLexerTest, HTML15) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_start_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName()); ASSERT_EQ(tok::html_slash_greater, Toks[2].getKind()); @@ -1165,8 +1238,8 @@ TEST_F(CommentLexerTest, HTML15) { TEST_F(CommentLexerTest, HTML16) { const char *Sources[] = { - "// <tag/ Aaa", - "// <tag / Aaa" + "// <img/ Aaa", + "// <img / Aaa" }; for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) { @@ -1180,7 +1253,7 @@ TEST_F(CommentLexerTest, HTML16) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_start_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagStartName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagStartName()); ASSERT_EQ(tok::text, Toks[2].getKind()); ASSERT_EQ(StringRef("/"), Toks[2].getText()); @@ -1201,13 +1274,13 @@ TEST_F(CommentLexerTest, HTML17) { 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::html_end_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef(""), Toks[1].getHTMLTagEndName()); + ASSERT_EQ(tok::text, Toks[1].getKind()); + ASSERT_EQ(StringRef("</"), Toks[1].getText()); - ASSERT_EQ(tok::newline, Toks[2].getKind()); + ASSERT_EQ(tok::newline, Toks[2].getKind()); } TEST_F(CommentLexerTest, HTML18) { @@ -1219,20 +1292,20 @@ TEST_F(CommentLexerTest, HTML18) { ASSERT_EQ(4U, 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::html_end_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef(""), Toks[1].getHTMLTagEndName()); + ASSERT_EQ(tok::text, Toks[1].getKind()); + ASSERT_EQ(StringRef("</"), Toks[1].getText()); - ASSERT_EQ(tok::text, Toks[2].getKind()); - ASSERT_EQ(StringRef("@"), Toks[2].getText()); + ASSERT_EQ(tok::text, Toks[2].getKind()); + ASSERT_EQ(StringRef("@"), Toks[2].getText()); - ASSERT_EQ(tok::newline, Toks[3].getKind()); + ASSERT_EQ(tok::newline, Toks[3].getKind()); } TEST_F(CommentLexerTest, HTML19) { - const char *Source = "// </tag"; + const char *Source = "// </img"; std::vector<Token> Toks; @@ -1244,35 +1317,51 @@ TEST_F(CommentLexerTest, HTML19) { ASSERT_EQ(StringRef(" "), Toks[0].getText()); ASSERT_EQ(tok::html_end_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagEndName()); + ASSERT_EQ(StringRef("img"), Toks[1].getHTMLTagEndName()); ASSERT_EQ(tok::newline, Toks[2].getKind()); } -TEST_F(CommentLexerTest, HTML20) { - const char *Sources[] = { - "// </tag>", - "// </ tag>", - "// </ tag >" - }; +TEST_F(CommentLexerTest, NotAKnownHTMLTag1) { + const char *Source = "// <tag>"; - 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(4U, 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::html_end_tag, Toks[1].getKind()); - ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagEndName()); + ASSERT_EQ(tok::text, Toks[1].getKind()); + ASSERT_EQ(StringRef("<tag"), Toks[1].getText()); - ASSERT_EQ(tok::html_greater, Toks[2].getKind()); + ASSERT_EQ(tok::text, Toks[2].getKind()); + ASSERT_EQ(StringRef(">"), Toks[2].getText()); - ASSERT_EQ(tok::newline, Toks[3].getKind()); - } + ASSERT_EQ(tok::newline, Toks[3].getKind()); +} + +TEST_F(CommentLexerTest, NotAKnownHTMLTag2) { + const char *Source = "// </tag>"; + + 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::text, Toks[1].getKind()); + ASSERT_EQ(StringRef("</tag"), Toks[1].getText()); + + ASSERT_EQ(tok::text, Toks[2].getKind()); + ASSERT_EQ(StringRef(">"), Toks[2].getText()); + + ASSERT_EQ(tok::newline, Toks[3].getKind()); } TEST_F(CommentLexerTest, HTMLCharacterReferences1) { diff --git a/unittests/AST/CommentParser.cpp b/unittests/AST/CommentParser.cpp index 7258a7ef576c6..8fde2478e74c0 100644 --- a/unittests/AST/CommentParser.cpp +++ b/unittests/AST/CommentParser.cpp @@ -10,6 +10,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/AST/Comment.h" #include "clang/AST/CommentLexer.h" #include "clang/AST/CommentParser.h" @@ -36,8 +37,9 @@ protected: CommentParserTest() : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()), - Diags(DiagID, new IgnoringDiagConsumer()), - SourceMgr(Diags, FileMgr) { + Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), + SourceMgr(Diags, FileMgr), + Traits(Allocator) { } FileSystemOptions FileMgrOpts; @@ -46,6 +48,7 @@ protected: DiagnosticsEngine Diags; SourceManager SourceMgr; llvm::BumpPtrAllocator Allocator; + CommandTraits Traits; FullComment *parseString(const char *Source); }; @@ -55,17 +58,15 @@ FullComment *CommentParserTest::parseString(const char *Source) { FileID File = SourceMgr.createFileIDForMemBuffer(Buf); SourceLocation Begin = SourceMgr.getLocForStartOfFile(File); - comments::CommandTraits Traits; - comments::Lexer L(Allocator, Traits, Begin, CommentOptions(), - Source, Source + strlen(Source)); + Lexer L(Allocator, Traits, Begin, Source, Source + strlen(Source)); - comments::Sema S(Allocator, SourceMgr, Diags, Traits); - comments::Parser P(L, S, Allocator, SourceMgr, Diags, Traits); - comments::FullComment *FC = P.parseFullComment(); + Sema S(Allocator, SourceMgr, Diags, Traits, /*PP=*/ NULL); + Parser P(L, S, Allocator, SourceMgr, Diags, Traits); + FullComment *FC = P.parseFullComment(); if (DEBUG) { llvm::errs() << "=== Source:\n" << Source << "\n=== AST:\n"; - FC->dump(SourceMgr); + FC->dump(llvm::errs(), &Traits, &SourceMgr); } Token Tok; @@ -157,6 +158,7 @@ template <typename T> } ::testing::AssertionResult HasBlockCommandAt(const Comment *C, + const CommandTraits &Traits, size_t Idx, BlockCommandComment *&BCC, StringRef Name, @@ -165,7 +167,7 @@ template <typename T> if (!AR) return AR; - StringRef ActualName = BCC->getCommandName(); + StringRef ActualName = BCC->getCommandName(Traits); if (ActualName != Name) return ::testing::AssertionFailure() << "BlockCommandComment has name \"" << ActualName.str() << "\", " @@ -178,6 +180,7 @@ template <typename T> ::testing::AssertionResult HasParamCommandAt( const Comment *C, + const CommandTraits &Traits, size_t Idx, ParamCommandComment *&PCC, StringRef CommandName, @@ -189,7 +192,7 @@ template <typename T> if (!AR) return AR; - StringRef ActualCommandName = PCC->getCommandName(); + StringRef ActualCommandName = PCC->getCommandName(Traits); if (ActualCommandName != CommandName) return ::testing::AssertionFailure() << "ParamCommandComment has name \"" << ActualCommandName.str() << "\", " @@ -211,7 +214,7 @@ template <typename T> return ::testing::AssertionFailure() << "ParamCommandComment has no parameter name"; - StringRef ActualParamName = PCC->hasParamName() ? PCC->getParamName() : ""; + StringRef ActualParamName = PCC->hasParamName() ? PCC->getParamNameAsWritten() : ""; if (ActualParamName != ParamName) return ::testing::AssertionFailure() << "ParamCommandComment has parameter name \"" << ActualParamName.str() @@ -225,6 +228,7 @@ template <typename T> ::testing::AssertionResult HasTParamCommandAt( const Comment *C, + const CommandTraits &Traits, size_t Idx, TParamCommandComment *&TPCC, StringRef CommandName, @@ -234,7 +238,7 @@ template <typename T> if (!AR) return AR; - StringRef ActualCommandName = TPCC->getCommandName(); + StringRef ActualCommandName = TPCC->getCommandName(Traits); if (ActualCommandName != CommandName) return ::testing::AssertionFailure() << "TParamCommandComment has name \"" << ActualCommandName.str() << "\", " @@ -244,7 +248,7 @@ template <typename T> return ::testing::AssertionFailure() << "TParamCommandComment has no parameter name"; - StringRef ActualParamName = TPCC->hasParamName() ? TPCC->getParamName() : ""; + StringRef ActualParamName = TPCC->hasParamName() ? TPCC->getParamNameAsWritten() : ""; if (ActualParamName != ParamName) return ::testing::AssertionFailure() << "TParamCommandComment has parameter name \"" << ActualParamName.str() @@ -257,6 +261,7 @@ template <typename T> } ::testing::AssertionResult HasInlineCommandAt(const Comment *C, + const CommandTraits &Traits, size_t Idx, InlineCommandComment *&ICC, StringRef Name) { @@ -264,7 +269,7 @@ template <typename T> if (!AR) return AR; - StringRef ActualName = ICC->getCommandName(); + StringRef ActualName = ICC->getCommandName(Traits); if (ActualName != Name) return ::testing::AssertionFailure() << "InlineCommandComment has name \"" << ActualName.str() << "\", " @@ -276,11 +281,12 @@ template <typename T> struct NoArgs {}; ::testing::AssertionResult HasInlineCommandAt(const Comment *C, + const CommandTraits &Traits, size_t Idx, InlineCommandComment *&ICC, StringRef Name, NoArgs) { - ::testing::AssertionResult AR = HasInlineCommandAt(C, Idx, ICC, Name); + ::testing::AssertionResult AR = HasInlineCommandAt(C, Traits, Idx, ICC, Name); if (!AR) return AR; @@ -293,11 +299,12 @@ struct NoArgs {}; } ::testing::AssertionResult HasInlineCommandAt(const Comment *C, + const CommandTraits &Traits, size_t Idx, InlineCommandComment *&ICC, StringRef Name, StringRef Arg) { - ::testing::AssertionResult AR = HasInlineCommandAt(C, Idx, ICC, Name); + ::testing::AssertionResult AR = HasInlineCommandAt(C, Traits, Idx, ICC, Name); if (!AR) return AR; @@ -452,6 +459,7 @@ struct NoAttrs {}; } ::testing::AssertionResult HasVerbatimBlockAt(const Comment *C, + const CommandTraits &Traits, size_t Idx, VerbatimBlockComment *&VBC, StringRef Name, @@ -460,7 +468,7 @@ struct NoAttrs {}; if (!AR) return AR; - StringRef ActualName = VBC->getCommandName(); + StringRef ActualName = VBC->getCommandName(Traits); if (ActualName != Name) return ::testing::AssertionFailure() << "VerbatimBlockComment has name \"" << ActualName.str() << "\", " @@ -480,12 +488,13 @@ struct NoLines {}; struct Lines {}; ::testing::AssertionResult HasVerbatimBlockAt(const Comment *C, + const CommandTraits &Traits, size_t Idx, VerbatimBlockComment *&VBC, StringRef Name, StringRef CloseName, NoLines) { - ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Idx, VBC, Name, + ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Traits, Idx, VBC, Name, CloseName); if (!AR) return AR; @@ -499,13 +508,14 @@ struct Lines {}; } ::testing::AssertionResult HasVerbatimBlockAt(const Comment *C, + const CommandTraits &Traits, size_t Idx, VerbatimBlockComment *&VBC, StringRef Name, StringRef CloseName, Lines, StringRef Line0) { - ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Idx, VBC, Name, + ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Traits, Idx, VBC, Name, CloseName); if (!AR) return AR; @@ -525,6 +535,7 @@ struct Lines {}; } ::testing::AssertionResult HasVerbatimBlockAt(const Comment *C, + const CommandTraits &Traits, size_t Idx, VerbatimBlockComment *&VBC, StringRef Name, @@ -532,7 +543,7 @@ struct Lines {}; Lines, StringRef Line0, StringRef Line1) { - ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Idx, VBC, Name, + ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Traits, Idx, VBC, Name, CloseName); if (!AR) return AR; @@ -558,6 +569,7 @@ struct Lines {}; } ::testing::AssertionResult HasVerbatimLineAt(const Comment *C, + const CommandTraits &Traits, size_t Idx, VerbatimLineComment *&VLC, StringRef Name, @@ -566,7 +578,7 @@ struct Lines {}; if (!AR) return AR; - StringRef ActualName = VLC->getCommandName(); + StringRef ActualName = VLC->getCommandName(Traits); if (ActualName != Name) return ::testing::AssertionFailure() << "VerbatimLineComment has name \"" << ActualName.str() << "\", " @@ -651,7 +663,7 @@ TEST_F(CommentParserTest, Paragraph2) { { BlockCommandComment *BCC; ParagraphComment *PC; - ASSERT_TRUE(HasBlockCommandAt(FC, 1, BCC, "brief", PC)); + ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC)); ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " Aaa")); } @@ -668,14 +680,14 @@ TEST_F(CommentParserTest, Paragraph3) { { BlockCommandComment *BCC; ParagraphComment *PC; - ASSERT_TRUE(HasBlockCommandAt(FC, 1, BCC, "brief", PC)); + ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC)); ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " ")); } { BlockCommandComment *BCC; ParagraphComment *PC; - ASSERT_TRUE(HasBlockCommandAt(FC, 2, BCC, "author", PC)); + ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "author", PC)); ASSERT_TRUE(GetChildAt(BCC, 0, PC)); ASSERT_TRUE(HasChildCount(PC, 0)); @@ -695,7 +707,7 @@ TEST_F(CommentParserTest, Paragraph4) { { BlockCommandComment *BCC; ParagraphComment *PC; - ASSERT_TRUE(HasBlockCommandAt(FC, 1, BCC, "brief", PC)); + ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC)); ASSERT_TRUE(GetChildAt(BCC, 0, PC)); ASSERT_TRUE(HasChildCount(PC, 2)); @@ -705,7 +717,7 @@ TEST_F(CommentParserTest, Paragraph4) { { BlockCommandComment *BCC; ParagraphComment *PC; - ASSERT_TRUE(HasBlockCommandAt(FC, 2, BCC, "author", PC)); + ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "author", PC)); ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " Ccc")); } @@ -721,7 +733,7 @@ TEST_F(CommentParserTest, ParamCommand1) { { ParamCommandComment *PCC; ParagraphComment *PC; - ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param", + ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param", ParamCommandComment::In, /* IsDirectionExplicit = */ false, "aaa", PC)); @@ -740,7 +752,7 @@ TEST_F(CommentParserTest, ParamCommand2) { { ParamCommandComment *PCC; ParagraphComment *PC; - ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param", + ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param", ParamCommandComment::In, /* IsDirectionExplicit = */ false, "", PC)); @@ -750,7 +762,7 @@ TEST_F(CommentParserTest, ParamCommand2) { { BlockCommandComment *BCC; ParagraphComment *PC; - ASSERT_TRUE(HasBlockCommandAt(FC, 2, BCC, "brief", PC)); + ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "brief", PC)); ASSERT_TRUE(HasChildCount(PC, 0)); } } @@ -774,7 +786,7 @@ TEST_F(CommentParserTest, ParamCommand3) { { ParamCommandComment *PCC; ParagraphComment *PC; - ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param", + ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param", ParamCommandComment::In, /* IsDirectionExplicit = */ false, "aaa", PC)); @@ -804,7 +816,7 @@ TEST_F(CommentParserTest, ParamCommand4) { { ParamCommandComment *PCC; ParagraphComment *PC; - ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param", + ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param", ParamCommandComment::In, /* IsDirectionExplicit = */ true, "aaa", PC)); @@ -834,7 +846,7 @@ TEST_F(CommentParserTest, ParamCommand5) { { ParamCommandComment *PCC; ParagraphComment *PC; - ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param", + ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param", ParamCommandComment::Out, /* IsDirectionExplicit = */ true, "aaa", PC)); @@ -865,7 +877,7 @@ TEST_F(CommentParserTest, ParamCommand6) { { ParamCommandComment *PCC; ParagraphComment *PC; - ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param", + ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param", ParamCommandComment::InOut, /* IsDirectionExplicit = */ true, "aaa", PC)); @@ -886,7 +898,7 @@ TEST_F(CommentParserTest, ParamCommand7) { { ParamCommandComment *PCC; ParagraphComment *PC; - ASSERT_TRUE(HasParamCommandAt(FC, 1, PCC, "param", + ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param", ParamCommandComment::In, /* IsDirectionExplicit = */ false, "aaa", PC)); @@ -920,7 +932,7 @@ TEST_F(CommentParserTest, TParamCommand1) { { TParamCommandComment *TPCC; ParagraphComment *PC; - ASSERT_TRUE(HasTParamCommandAt(FC, 1, TPCC, "tparam", + ASSERT_TRUE(HasTParamCommandAt(FC, Traits, 1, TPCC, "tparam", "aaa", PC)); ASSERT_TRUE(HasChildCount(TPCC, 1)); ASSERT_TRUE(HasParagraphCommentAt(TPCC, 0, " Bbb")); @@ -938,14 +950,14 @@ TEST_F(CommentParserTest, TParamCommand2) { { TParamCommandComment *TPCC; ParagraphComment *PC; - ASSERT_TRUE(HasTParamCommandAt(FC, 1, TPCC, "tparam", "", PC)); + ASSERT_TRUE(HasTParamCommandAt(FC, Traits, 1, TPCC, "tparam", "", PC)); ASSERT_TRUE(HasChildCount(TPCC, 1)); ASSERT_TRUE(HasChildCount(PC, 0)); } { BlockCommandComment *BCC; ParagraphComment *PC; - ASSERT_TRUE(HasBlockCommandAt(FC, 2, BCC, "brief", PC)); + ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "brief", PC)); ASSERT_TRUE(HasChildCount(PC, 0)); } } @@ -964,7 +976,7 @@ TEST_F(CommentParserTest, InlineCommand1) { ASSERT_TRUE(HasChildCount(PC, 2)); ASSERT_TRUE(HasTextAt(PC, 0, " ")); - ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", NoArgs())); + ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", NoArgs())); } } @@ -981,7 +993,7 @@ TEST_F(CommentParserTest, InlineCommand2) { ASSERT_TRUE(HasChildCount(PC, 3)); ASSERT_TRUE(HasTextAt(PC, 0, " ")); - ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", NoArgs())); + ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", NoArgs())); ASSERT_TRUE(HasTextAt(PC, 2, " ")); } } @@ -999,7 +1011,7 @@ TEST_F(CommentParserTest, InlineCommand3) { ASSERT_TRUE(HasChildCount(PC, 2)); ASSERT_TRUE(HasTextAt(PC, 0, " ")); - ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", "aaa")); + ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", "aaa")); } } @@ -1016,7 +1028,7 @@ TEST_F(CommentParserTest, InlineCommand4) { ASSERT_TRUE(HasChildCount(PC, 3)); ASSERT_TRUE(HasTextAt(PC, 0, " ")); - ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "c", "aaa")); + ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", "aaa")); ASSERT_TRUE(HasTextAt(PC, 2, " bbb")); } } @@ -1034,7 +1046,7 @@ TEST_F(CommentParserTest, InlineCommand5) { ASSERT_TRUE(HasChildCount(PC, 3)); ASSERT_TRUE(HasTextAt(PC, 0, " ")); - ASSERT_TRUE(HasInlineCommandAt(PC, 1, ICC, "unknown", NoArgs())); + ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "unknown", NoArgs())); ASSERT_TRUE(HasTextAt(PC, 2, " aaa")); } } @@ -1188,7 +1200,8 @@ TEST_F(CommentParserTest, VerbatimBlock1) { ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " ")); { VerbatimBlockComment *VCC; - ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VCC, "verbatim", "endverbatim", + ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VCC, + "verbatim", "endverbatim", NoLines())); } } @@ -1202,7 +1215,8 @@ TEST_F(CommentParserTest, VerbatimBlock2) { ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " ")); { VerbatimBlockComment *VBC; - ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "endverbatim", + ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC, + "verbatim", "endverbatim", Lines(), " Aaa ")); } } @@ -1216,7 +1230,7 @@ TEST_F(CommentParserTest, VerbatimBlock3) { ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " ")); { VerbatimBlockComment *VBC; - ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "", + ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC, "verbatim", "", Lines(), " Aaa")); } } @@ -1231,7 +1245,8 @@ TEST_F(CommentParserTest, VerbatimBlock4) { { VerbatimBlockComment *VBC; - ASSERT_TRUE(HasVerbatimBlockAt(FC, 0, VBC, "verbatim", "endverbatim", + ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 0, VBC, + "verbatim", "endverbatim", NoLines())); } } @@ -1253,7 +1268,8 @@ TEST_F(CommentParserTest, VerbatimBlock5) { { VerbatimBlockComment *VBC; - ASSERT_TRUE(HasVerbatimBlockAt(FC, 0, VBC, "verbatim", "endverbatim", + ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 0, VBC, + "verbatim", "endverbatim", Lines(), " Aaa")); } } @@ -1277,7 +1293,8 @@ TEST_F(CommentParserTest, VerbatimBlock6) { ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " ")); { VerbatimBlockComment *VBC; - ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "endverbatim", + ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC, + "verbatim", "endverbatim", Lines(), " Aaa")); } } @@ -1303,7 +1320,8 @@ TEST_F(CommentParserTest, VerbatimBlock7) { ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " ")); { VerbatimBlockComment *VBC; - ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "endverbatim", + ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC, + "verbatim", "endverbatim", Lines(), " Aaa", " Bbb")); } } @@ -1330,7 +1348,8 @@ TEST_F(CommentParserTest, VerbatimBlock8) { ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " ")); { VerbatimBlockComment *VBC; - ASSERT_TRUE(HasVerbatimBlockAt(FC, 1, VBC, "verbatim", "endverbatim")); + ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC, + "verbatim", "endverbatim")); ASSERT_EQ(3U, VBC->getNumLines()); ASSERT_EQ(" Aaa", VBC->getText(0)); ASSERT_EQ("", VBC->getText(1)); @@ -1352,7 +1371,7 @@ TEST_F(CommentParserTest, VerbatimLine1) { ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " ")); { VerbatimLineComment *VLC; - ASSERT_TRUE(HasVerbatimLineAt(FC, 1, VLC, "fn", "")); + ASSERT_TRUE(HasVerbatimLineAt(FC, Traits, 1, VLC, "fn", "")); } } } @@ -1370,7 +1389,7 @@ TEST_F(CommentParserTest, VerbatimLine2) { ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " ")); { VerbatimLineComment *VLC; - ASSERT_TRUE(HasVerbatimLineAt(FC, 1, VLC, "fn", + ASSERT_TRUE(HasVerbatimLineAt(FC, Traits, 1, VLC, "fn", " void *foo(const char *zzz = \"\\$\");")); } } diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp new file mode 100644 index 0000000000000..a2fc839b9c8e5 --- /dev/null +++ b/unittests/AST/DeclPrinterTest.cpp @@ -0,0 +1,1248 @@ +//===- unittests/AST/DeclPrinterTest.cpp --- Declaration printer tests ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains tests for Decl::print() and related methods. +// +// Search this file for WRONG to see test cases that are producing something +// completely wrong, invalid C++ or just misleading. +// +// These tests have a coding convention: +// * declaration to be printed is named 'A' unless it should have some special +// name (e.g., 'operator+'); +// * additional helper declarations are 'Z', 'Y', 'X' and so on. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/SmallString.h" +#include "gtest/gtest.h" + +using namespace clang; +using namespace ast_matchers; +using namespace tooling; + +namespace { + +void PrintDecl(raw_ostream &Out, const ASTContext *Context, const Decl *D) { + PrintingPolicy Policy = Context->getPrintingPolicy(); + Policy.TerseOutput = true; + D->print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ false); +} + +class PrintMatch : public MatchFinder::MatchCallback { + SmallString<1024> Printed; + unsigned NumFoundDecls; + +public: + PrintMatch() : NumFoundDecls(0) {} + + virtual void run(const MatchFinder::MatchResult &Result) { + const Decl *D = Result.Nodes.getDeclAs<Decl>("id"); + if (!D || D->isImplicit()) + return; + NumFoundDecls++; + if (NumFoundDecls > 1) + return; + + llvm::raw_svector_ostream Out(Printed); + PrintDecl(Out, Result.Context, D); + } + + StringRef getPrinted() const { + return Printed; + } + + unsigned getNumFoundDecls() const { + return NumFoundDecls; + } +}; + +::testing::AssertionResult PrintedDeclMatches( + StringRef Code, + const std::vector<std::string> &Args, + const DeclarationMatcher &NodeMatch, + StringRef ExpectedPrinted, + StringRef FileName) { + PrintMatch Printer; + MatchFinder Finder; + Finder.addMatcher(NodeMatch, &Printer); + OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder)); + + if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName)) + return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; + + if (Printer.getNumFoundDecls() == 0) + return testing::AssertionFailure() + << "Matcher didn't find any declarations"; + + if (Printer.getNumFoundDecls() > 1) + return testing::AssertionFailure() + << "Matcher should match only one declaration " + "(found " << Printer.getNumFoundDecls() << ")"; + + if (Printer.getPrinted() != ExpectedPrinted) + return ::testing::AssertionFailure() + << "Expected \"" << ExpectedPrinted << "\", " + "got \"" << Printer.getPrinted() << "\""; + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult PrintedDeclCXX98Matches(StringRef Code, + StringRef DeclName, + StringRef ExpectedPrinted) { + std::vector<std::string> Args(1, "-std=c++98"); + return PrintedDeclMatches(Code, + Args, + namedDecl(hasName(DeclName)).bind("id"), + ExpectedPrinted, + "input.cc"); +} + +::testing::AssertionResult PrintedDeclCXX98Matches( + StringRef Code, + const DeclarationMatcher &NodeMatch, + StringRef ExpectedPrinted) { + std::vector<std::string> Args(1, "-std=c++98"); + return PrintedDeclMatches(Code, + Args, + NodeMatch, + ExpectedPrinted, + "input.cc"); +} + +::testing::AssertionResult PrintedDeclCXX11Matches(StringRef Code, + StringRef DeclName, + StringRef ExpectedPrinted) { + std::vector<std::string> Args(1, "-std=c++11"); + return PrintedDeclMatches(Code, + Args, + namedDecl(hasName(DeclName)).bind("id"), + ExpectedPrinted, + "input.cc"); +} + +::testing::AssertionResult PrintedDeclCXX11Matches( + StringRef Code, + const DeclarationMatcher &NodeMatch, + StringRef ExpectedPrinted) { + std::vector<std::string> Args(1, "-std=c++11"); + return PrintedDeclMatches(Code, + Args, + NodeMatch, + ExpectedPrinted, + "input.cc"); +} + +::testing::AssertionResult PrintedDeclObjCMatches( + StringRef Code, + const DeclarationMatcher &NodeMatch, + StringRef ExpectedPrinted) { + std::vector<std::string> Args(1, ""); + return PrintedDeclMatches(Code, + Args, + NodeMatch, + ExpectedPrinted, + "input.m"); +} + +} // unnamed namespace + +TEST(DeclPrinter, TestNamespace1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "namespace A { int B; }", + "A", + "namespace A {\n}")); + // Should be: with { ... } +} + +TEST(DeclPrinter, TestNamespace2) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "inline namespace A { int B; }", + "A", + "inline namespace A {\n}")); + // Should be: with { ... } +} + +TEST(DeclPrinter, TestNamespaceAlias1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "namespace Z { }" + "namespace A = Z;", + "A", + "namespace A = Z")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestNamespaceAlias2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "namespace X { namespace Y {} }" + "namespace A = X::Y;", + "A", + "namespace A = X::Y")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestCXXRecordDecl1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "class A { int a; };", + "A", + "class A {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestCXXRecordDecl2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct A { int a; };", + "A", + "struct A {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestCXXRecordDecl3) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "union A { int a; };", + "A", + "union A {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestCXXRecordDecl4) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "class Z { int a; };" + "class A : Z { int b; };", + "A", + "class A : Z {\n}")); + // Should be: with semicolon, with { ... }, without two spaces +} + +TEST(DeclPrinter, TestCXXRecordDecl5) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z { int a; };" + "struct A : Z { int b; };", + "A", + "struct A : Z {\n}")); + // Should be: with semicolon, with { ... }, without two spaces +} + +TEST(DeclPrinter, TestCXXRecordDecl6) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "class Z { int a; };" + "class A : public Z { int b; };", + "A", + "class A : public Z {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestCXXRecordDecl7) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "class Z { int a; };" + "class A : protected Z { int b; };", + "A", + "class A : protected Z {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestCXXRecordDecl8) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "class Z { int a; };" + "class A : private Z { int b; };", + "A", + "class A : private Z {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestCXXRecordDecl9) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "class Z { int a; };" + "class A : virtual Z { int b; };", + "A", + "class A : virtual Z {\n}")); + // Should be: with semicolon, with { ... }, without two spaces +} + +TEST(DeclPrinter, TestCXXRecordDecl10) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "class Z { int a; };" + "class A : virtual public Z { int b; };", + "A", + "class A : virtual public Z {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestCXXRecordDecl11) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "class Z { int a; };" + "class Y : virtual public Z { int b; };" + "class A : virtual public Z, private Y { int c; };", + "A", + "class A : virtual public Z, private Y {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestFunctionDecl1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "void A();", + "A", + "void A()")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "void A() {}", + "A", + "void A()")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl3) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "void Z();" + "void A() { Z(); }", + "A", + "void A()")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl4) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "extern void A();", + "A", + "extern void A()")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl5) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "static void A();", + "A", + "static void A()")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl6) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "inline void A();", + "A", + "inline void A()")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl7) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "constexpr int A(int a);", + "A", + "int A(int a)")); + // WRONG; Should be: "constexpr int A(int a);" +} + +TEST(DeclPrinter, TestFunctionDecl8) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "void A(int a);", + "A", + "void A(int a)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl9) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "void A(...);", + "A", + "void A(...)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl10) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "void A(int a, ...);", + "A", + "void A(int a, ...)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl11) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "typedef long size_t;" + "typedef int *pInt;" + "void A(int a, pInt b, size_t c);", + "A", + "void A(int a, pInt b, size_t c)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl12) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "void A(int a, int b = 0);", + "A", + "void A(int a, int b = 0)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl13) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "void (*A(int a))(int b);", + "A", + "void (*A(int a))(int)")); + // Should be: with semicolon, with parameter name (?) +} + +TEST(DeclPrinter, TestFunctionDecl14) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T>" + "void A(T t) { }" + "template<>" + "void A(int N) { }", + functionDecl(hasName("A"), isExplicitTemplateSpecialization()).bind("id"), + "void A(int N)")); + // WRONG; Should be: "template <> void A(int N);")); +} + + +TEST(DeclPrinter, TestCXXConstructorDecl1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct A {" + " A();" + "};", + constructorDecl(ofClass(hasName("A"))).bind("id"), + "")); + // WRONG; Should be: "A();" +} + +TEST(DeclPrinter, TestCXXConstructorDecl2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct A {" + " A(int a);" + "};", + constructorDecl(ofClass(hasName("A"))).bind("id"), + "")); + // WRONG; Should be: "A(int a);" +} + +TEST(DeclPrinter, TestCXXConstructorDecl3) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct A {" + " A(const A &a);" + "};", + constructorDecl(ofClass(hasName("A"))).bind("id"), + "")); + // WRONG; Should be: "A(const A &a);" +} + +TEST(DeclPrinter, TestCXXConstructorDecl4) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct A {" + " A(const A &a, int = 0);" + "};", + constructorDecl(ofClass(hasName("A"))).bind("id"), + "")); + // WRONG; Should be: "A(const A &a, int = 0);" +} + +TEST(DeclPrinter, TestCXXConstructorDecl5) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "struct A {" + " A(const A &&a);" + "};", + constructorDecl(ofClass(hasName("A"))).bind("id"), + "")); + // WRONG; Should be: "A(const A &&a);" +} + +TEST(DeclPrinter, TestCXXConstructorDecl6) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct A {" + " explicit A(int a);" + "};", + constructorDecl(ofClass(hasName("A"))).bind("id"), + "")); + // WRONG; Should be: "explicit A(int a);" +} + +TEST(DeclPrinter, TestCXXConstructorDecl7) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "struct A {" + " constexpr A();" + "};", + constructorDecl(ofClass(hasName("A"))).bind("id"), + "")); + // WRONG; Should be: "constexpr A();" +} + +TEST(DeclPrinter, TestCXXConstructorDecl8) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "struct A {" + " A() = default;" + "};", + constructorDecl(ofClass(hasName("A"))).bind("id"), + "")); + // WRONG; Should be: "A() = default;" +} + +TEST(DeclPrinter, TestCXXConstructorDecl9) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "struct A {" + " A() = delete;" + "};", + constructorDecl(ofClass(hasName("A"))).bind("id"), + " = delete")); + // WRONG; Should be: "A() = delete;" +} + +TEST(DeclPrinter, TestCXXConstructorDecl10) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "template<typename... T>" + "struct A {" + " A(const A &a);" + "};", + constructorDecl(ofClass(hasName("A"))).bind("id"), + "")); + // WRONG; Should be: "A(const A &a);" +} + +#if !defined(_MSC_VER) +TEST(DeclPrinter, TestCXXConstructorDecl11) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "template<typename... T>" + "struct A : public T... {" + " A(T&&... ts) : T(ts)... {}" + "};", + constructorDecl(ofClass(hasName("A"))).bind("id"), + "A<T...>(T &&ts...) : T(ts)")); + // WRONG; Should be: "A(T&&... ts) : T(ts)..." +} +#endif + +TEST(DeclPrinter, TestCXXDestructorDecl1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct A {" + " ~A();" + "};", + destructorDecl(ofClass(hasName("A"))).bind("id"), + "void ~A()")); + // WRONG; Should be: "~A();" +} + +TEST(DeclPrinter, TestCXXDestructorDecl2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct A {" + " virtual ~A();" + "};", + destructorDecl(ofClass(hasName("A"))).bind("id"), + "virtual void ~A()")); + // WRONG; Should be: "virtual ~A();" +} + +TEST(DeclPrinter, TestCXXConversionDecl1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct A {" + " operator int();" + "};", + methodDecl(ofClass(hasName("A"))).bind("id"), + "int operator int()")); + // WRONG; Should be: "operator int();" +} + +TEST(DeclPrinter, TestCXXConversionDecl2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct A {" + " operator bool();" + "};", + methodDecl(ofClass(hasName("A"))).bind("id"), + "bool operator _Bool()")); + // WRONG; Should be: "operator bool();" +} + +TEST(DeclPrinter, TestCXXConversionDecl3) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z {};" + "struct A {" + " operator Z();" + "};", + methodDecl(ofClass(hasName("A"))).bind("id"), + "Z operator struct Z()")); + // WRONG; Should be: "operator Z();" +} + +TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction1) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "namespace std { typedef decltype(sizeof(int)) size_t; }" + "struct Z {" + " void *operator new(std::size_t);" + "};", + methodDecl(ofClass(hasName("Z"))).bind("id"), + "void *operator new(std::size_t)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction2) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "namespace std { typedef decltype(sizeof(int)) size_t; }" + "struct Z {" + " void *operator new[](std::size_t);" + "};", + methodDecl(ofClass(hasName("Z"))).bind("id"), + "void *operator new[](std::size_t)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction3) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "struct Z {" + " void operator delete(void *);" + "};", + methodDecl(ofClass(hasName("Z"))).bind("id"), + "void operator delete(void *) noexcept")); + // Should be: with semicolon, without noexcept? +} + +TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction4) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z {" + " void operator delete(void *);" + "};", + methodDecl(ofClass(hasName("Z"))).bind("id"), + "void operator delete(void *)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestCXXMethodDecl_AllocationFunction5) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "struct Z {" + " void operator delete[](void *);" + "};", + methodDecl(ofClass(hasName("Z"))).bind("id"), + "void operator delete[](void *) noexcept")); + // Should be: with semicolon, without noexcept? +} + +TEST(DeclPrinter, TestCXXMethodDecl_Operator1) { + const char *OperatorNames[] = { + "+", "-", "*", "/", "%", "^", "&", "|", + "=", "<", ">", "+=", "-=", "*=", "/=", "%=", + "^=", "&=", "|=", "<<", ">>", ">>=", "<<=", "==", "!=", + "<=", ">=", "&&", "||", ",", "->*", + "()", "[]" + }; + + for (unsigned i = 0, e = llvm::array_lengthof(OperatorNames); i != e; ++i) { + SmallString<128> Code; + Code.append("struct Z { void operator"); + Code.append(OperatorNames[i]); + Code.append("(Z z); };"); + + SmallString<128> Expected; + Expected.append("void operator"); + Expected.append(OperatorNames[i]); + Expected.append("(Z z)"); + // Should be: with semicolon + + ASSERT_TRUE(PrintedDeclCXX98Matches( + Code, + methodDecl(ofClass(hasName("Z"))).bind("id"), + Expected)); + } +} + +TEST(DeclPrinter, TestCXXMethodDecl_Operator2) { + const char *OperatorNames[] = { + "~", "!", "++", "--", "->" + }; + + for (unsigned i = 0, e = llvm::array_lengthof(OperatorNames); i != e; ++i) { + SmallString<128> Code; + Code.append("struct Z { void operator"); + Code.append(OperatorNames[i]); + Code.append("(); };"); + + SmallString<128> Expected; + Expected.append("void operator"); + Expected.append(OperatorNames[i]); + Expected.append("()"); + // Should be: with semicolon + + ASSERT_TRUE(PrintedDeclCXX98Matches( + Code, + methodDecl(ofClass(hasName("Z"))).bind("id"), + Expected)); + } +} + +TEST(DeclPrinter, TestCXXMethodDecl1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z {" + " void A(int a);" + "};", + "A", + "void A(int a)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestCXXMethodDecl2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z {" + " virtual void A(int a);" + "};", + "A", + "virtual void A(int a)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestCXXMethodDecl3) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z {" + " virtual void A(int a);" + "};" + "struct ZZ : Z {" + " void A(int a);" + "};", + "ZZ::A", + "void A(int a)")); + // Should be: with semicolon + // TODO: should we print "virtual"? +} + +TEST(DeclPrinter, TestCXXMethodDecl4) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z {" + " inline void A(int a);" + "};", + "A", + "inline void A(int a)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestCXXMethodDecl5) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z {" + " virtual void A(int a) = 0;" + "};", + "A", + "virtual void A(int a) = 0")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z {" + " void A(int a) const;" + "};", + "A", + "void A(int a) const")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z {" + " void A(int a) volatile;" + "};", + "A", + "void A(int a) volatile")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestCXXMethodDecl_CVQualifier3) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z {" + " void A(int a) const volatile;" + "};", + "A", + "void A(int a) const volatile")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestCXXMethodDecl_RefQualifier1) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "struct Z {" + " void A(int a) &;" + "};", + "A", + "void A(int a)")); + // WRONG; Should be: "void A(int a) &;" +} + +TEST(DeclPrinter, TestCXXMethodDecl_RefQualifier2) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "struct Z {" + " void A(int a) &&;" + "};", + "A", + "void A(int a)")); + // WRONG; Should be: "void A(int a) &&;" +} + +TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z {" + " void A(int a) throw();" + "};", + "A", + "void A(int a) throw()")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z {" + " void A(int a) throw(int);" + "};", + "A", + "void A(int a) throw(int)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification3) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "class ZZ {};" + "struct Z {" + " void A(int a) throw(ZZ, int);" + "};", + "A", + "void A(int a) throw(ZZ, int)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification4) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "struct Z {" + " void A(int a) noexcept;" + "};", + "A", + "void A(int a) noexcept")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification5) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "struct Z {" + " void A(int a) noexcept(true);" + "};", + "A", + "void A(int a) noexcept(trueA(int a) noexcept(true)")); + // WRONG; Should be: "void A(int a) noexcept(true);" +} + +TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification6) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "struct Z {" + " void A(int a) noexcept(1 < 2);" + "};", + "A", + "void A(int a) noexcept(1 < 2A(int a) noexcept(1 < 2)")); + // WRONG; Should be: "void A(int a) noexcept(1 < 2);" +} + +TEST(DeclPrinter, TestFunctionDecl_ExceptionSpecification7) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "template<int N>" + "struct Z {" + " void A(int a) noexcept(N < 2);" + "};", + "A", + "void A(int a) noexcept(N < 2A(int a) noexcept(N < 2)")); + // WRONG; Should be: "void A(int a) noexcept(N < 2);" +} + +TEST(DeclPrinter, TestVarDecl1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "char *const (*(*A)[5])(int);", + "A", + "char *const (*(*A)[5])(int)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestVarDecl2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "void (*A)() throw(int);", + "A", + "void (*A)() throw(int)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestVarDecl3) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "void (*A)() noexcept;", + "A", + "void (*A)() noexcept")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFieldDecl1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T>" + "struct Z { T A; };", + "A", + "T A")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFieldDecl2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<int N>" + "struct Z { int A[N]; };", + "A", + "int A[N]")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestClassTemplateDecl1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T>" + "struct A { T a; };", + classTemplateDecl(hasName("A")).bind("id"), + "template <typename T> struct A {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestClassTemplateDecl2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T = int>" + "struct A { T a; };", + classTemplateDecl(hasName("A")).bind("id"), + "template <typename T = int> struct A {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestClassTemplateDecl3) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<class T>" + "struct A { T a; };", + classTemplateDecl(hasName("A")).bind("id"), + "template <class T> struct A {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestClassTemplateDecl4) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T, typename U>" + "struct A { T a; U b; };", + classTemplateDecl(hasName("A")).bind("id"), + "template <typename T, typename U> struct A {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestClassTemplateDecl5) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<int N>" + "struct A { int a[N]; };", + classTemplateDecl(hasName("A")).bind("id"), + "template <int N> struct A {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestClassTemplateDecl6) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<int N = 42>" + "struct A { int a[N]; };", + classTemplateDecl(hasName("A")).bind("id"), + "template <int N = 42> struct A {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestClassTemplateDecl7) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "typedef int MyInt;" + "template<MyInt N>" + "struct A { int a[N]; };", + classTemplateDecl(hasName("A")).bind("id"), + "template <MyInt N> struct A {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestClassTemplateDecl8) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<template<typename U> class T> struct A { };", + classTemplateDecl(hasName("A")).bind("id"), + "template <template <typename U> class T> struct A {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestClassTemplateDecl9) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T> struct Z { };" + "template<template<typename U> class T = Z> struct A { };", + classTemplateDecl(hasName("A")).bind("id"), + "template <template <typename U> class T> struct A {\n}")); + // Should be: with semicolon, with { ... } +} + +TEST(DeclPrinter, TestClassTemplateDecl10) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "template<typename... T>" + "struct A { int a; };", + classTemplateDecl(hasName("A")).bind("id"), + "template <typename ... T> struct A {\n}")); + // Should be: with semicolon, with { ... }, without spaces before '...' +} + +TEST(DeclPrinter, TestClassTemplateDecl11) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "template<typename... T>" + "struct A : public T... { int a; };", + classTemplateDecl(hasName("A")).bind("id"), + "template <typename ... T> struct A : public T... {\n}")); + // Should be: with semicolon, with { ... }, without spaces before '...' +} + +TEST(DeclPrinter, TestClassTemplatePartialSpecializationDecl1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T, typename U>" + "struct A { T a; U b; };" + "template<typename T>" + "struct A<T, int> { T a; };", + classTemplateSpecializationDecl().bind("id"), + "struct A {\n}")); + // WRONG; Should be: "template<typename T> struct A<T, int> { ... }" +} + +TEST(DeclPrinter, TestClassTemplatePartialSpecializationDecl2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T>" + "struct A { T a; };" + "template<typename T>" + "struct A<T *> { T a; };", + classTemplateSpecializationDecl().bind("id"), + "struct A {\n}")); + // WRONG; Should be: "template<typename T> struct A<T *> { ... }" +} + +TEST(DeclPrinter, TestClassTemplateSpecializationDecl1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T>" + "struct A { T a; };" + "template<>" + "struct A<int> { int a; };", + classTemplateSpecializationDecl().bind("id"), + "struct A {\n}")); + // WRONG; Should be: "template<> struct A<int> { ... }" +} + +TEST(DeclPrinter, TestFunctionTemplateDecl1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T>" + "void A(T &t);", + functionTemplateDecl(hasName("A")).bind("id"), + "template <typename T> void A(T &t)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionTemplateDecl2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T>" + "void A(T &t) { }", + functionTemplateDecl(hasName("A")).bind("id"), + "template <typename T> void A(T &t)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionTemplateDecl3) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "template<typename... T>" + "void A(T... a);", + functionTemplateDecl(hasName("A")).bind("id"), + "template <typename ... T> void A(T a...)")); + // WRONG; Should be: "template <typename ... T> void A(T... a)" + // (not "T a...") + // Should be: with semicolon. +} + +TEST(DeclPrinter, TestFunctionTemplateDecl4) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z { template<typename T> void A(T t); };", + functionTemplateDecl(hasName("A")).bind("id"), + "template <typename T> void A(T t)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionTemplateDecl5) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "struct Z { template<typename T> void A(T t) {} };", + functionTemplateDecl(hasName("A")).bind("id"), + "template <typename T> void A(T t)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestFunctionTemplateDecl6) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T >struct Z {" + " template<typename U> void A(U t) {}" + "};", + functionTemplateDecl(hasName("A")).bind("id"), + "template <typename U> void A(U t)")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestTemplateArgumentList1) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T> struct Z {};" + "struct X {};" + "Z<X> A;", + "A", + "Z<X> A")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestTemplateArgumentList2) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T, typename U> struct Z {};" + "struct X {};" + "typedef int Y;" + "Z<X, Y> A;", + "A", + "Z<X, Y> A")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestTemplateArgumentList3) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T> struct Z {};" + "template<typename T> struct X {};" + "Z<X<int> > A;", + "A", + "Z<X<int> > A")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestTemplateArgumentList4) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "template<typename T> struct Z {};" + "template<typename T> struct X {};" + "Z<X<int>> A;", + "A", + "Z<X<int> > A")); + // Should be: with semicolon, without extra space in "> >" +} + +TEST(DeclPrinter, TestTemplateArgumentList5) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T> struct Z {};" + "template<typename T> struct X { Z<T> A; };", + "A", + "Z<T> A")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestTemplateArgumentList6) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<template<typename T> class U> struct Z {};" + "template<typename T> struct X {};" + "Z<X> A;", + "A", + "Z<X> A")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestTemplateArgumentList7) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<template<typename T> class U> struct Z {};" + "template<template<typename T> class U> struct Y {" + " Z<U> A;" + "};", + "A", + "Z<U> A")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestTemplateArgumentList8) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<typename T> struct Z {};" + "template<template<typename T> class U> struct Y {" + " Z<U<int> > A;" + "};", + "A", + "Z<U<int> > A")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestTemplateArgumentList9) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<unsigned I> struct Z {};" + "Z<0> A;", + "A", + "Z<0> A")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestTemplateArgumentList10) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<unsigned I> struct Z {};" + "template<unsigned I> struct X { Z<I> A; };", + "A", + "Z<I> A")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestTemplateArgumentList11) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<int I> struct Z {};" + "Z<42 * 10 - 420 / 1> A;", + "A", + "Z<42 * 10 - 420 / 1> A")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestTemplateArgumentList12) { + ASSERT_TRUE(PrintedDeclCXX98Matches( + "template<const char *p> struct Z {};" + "extern const char X[] = \"aaa\";" + "Z<X> A;", + "A", + "Z<X> A")); + // Should be: with semicolon +} + +TEST(DeclPrinter, TestTemplateArgumentList13) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "template<typename... T> struct Z {};" + "template<typename... T> struct X {" + " Z<T...> A;" + "};", + "A", + "Z<T...> A")); + // Should be: with semicolon, without extra space in "> >" +} + +TEST(DeclPrinter, TestTemplateArgumentList14) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "template<typename... T> struct Z {};" + "template<typename T> struct Y {};" + "template<typename... T> struct X {" + " Z<Y<T>...> A;" + "};", + "A", + "Z<Y<T>...> A")); + // Should be: with semicolon, without extra space in "> >" +} + +TEST(DeclPrinter, TestTemplateArgumentList15) { + ASSERT_TRUE(PrintedDeclCXX11Matches( + "template<unsigned I> struct Z {};" + "template<typename... T> struct X {" + " Z<sizeof...(T)> A;" + "};", + "A", + "Z<sizeof...(T)> A")); + // Should be: with semicolon, without extra space in "> >" +} + +TEST(DeclPrinter, TestObjCMethod1) { + ASSERT_TRUE(PrintedDeclObjCMatches( + "__attribute__((objc_root_class)) @interface X\n" + "- (int)A:(id)anObject inRange:(long)range;\n" + "@end\n" + "@implementation X\n" + "- (int)A:(id)anObject inRange:(long)range { int printThis; return 0; }\n" + "@end\n", + namedDecl(hasName("A:inRange:"), + hasDescendant(namedDecl(hasName("printThis")))).bind("id"), + "- (int) A:(id)anObject inRange:(long)range")); +} + diff --git a/unittests/AST/Makefile b/unittests/AST/Makefile index 31cd5de1b741a..e07fc45467b3f 100644 --- a/unittests/AST/Makefile +++ b/unittests/AST/Makefile @@ -9,7 +9,11 @@ CLANG_LEVEL = ../.. TESTNAME = AST -LINK_COMPONENTS := support mc -USEDLIBS = clangAST.a clangLex.a clangBasic.a +include $(CLANG_LEVEL)/../../Makefile.config +LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc +USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \ + clangRewriteCore.a clangRewriteFrontend.a \ + clangParse.a clangSema.a clangAnalysis.a \ + clangAST.a clangASTMatchers.a clangLex.a clangBasic.a clangEdit.a include $(CLANG_LEVEL)/unittests/Makefile diff --git a/unittests/AST/SourceLocationTest.cpp b/unittests/AST/SourceLocationTest.cpp new file mode 100644 index 0000000000000..dec833d15d802 --- /dev/null +++ b/unittests/AST/SourceLocationTest.cpp @@ -0,0 +1,289 @@ +//===- unittest/AST/SourceLocationTest.cpp - AST source loc unit tests ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains tests for SourceLocation and SourceRange fields +// in AST nodes. +// +// FIXME: In the long-term, when we test more than source locations, we may +// want to have a unit test file for an AST node (or group of related nodes), +// rather than a unit test file for source locations for all AST nodes. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" + +namespace clang { +namespace ast_matchers { + +using clang::tooling::newFrontendActionFactory; +using clang::tooling::runToolOnCodeWithArgs; +using clang::tooling::FrontendActionFactory; + +enum Language { Lang_C, Lang_C89, Lang_CXX }; + +/// \brief Base class for verifying some property of nodes found by a matcher. +/// +/// FIXME: This class should be shared with other AST tests. +template <typename NodeType> +class MatchVerifier : public MatchFinder::MatchCallback { +public: + template <typename MatcherType> + testing::AssertionResult match(const std::string &Code, + const MatcherType &AMatcher) { + return match(Code, AMatcher, Lang_CXX); + } + + template <typename MatcherType> + testing::AssertionResult match(const std::string &Code, + const MatcherType &AMatcher, Language L); + +protected: + virtual void run(const MatchFinder::MatchResult &Result); + virtual void verify(const MatchFinder::MatchResult &Result, + const NodeType &Node) = 0; + + void setFailure(const Twine &Result) { + Verified = false; + VerifyResult = Result.str(); + } + +private: + bool Verified; + std::string VerifyResult; +}; + +/// \brief Runs a matcher over some code, and returns the result of the +/// verifier for the matched node. +template <typename NodeType> template <typename MatcherType> +testing::AssertionResult MatchVerifier<NodeType>::match( + const std::string &Code, const MatcherType &AMatcher, Language L) { + MatchFinder Finder; + Finder.addMatcher(AMatcher.bind(""), this); + OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder)); + + std::vector<std::string> Args; + StringRef FileName; + switch (L) { + case Lang_C: + Args.push_back("-std=c99"); + FileName = "input.c"; + break; + case Lang_C89: + Args.push_back("-std=c89"); + FileName = "input.c"; + break; + case Lang_CXX: + Args.push_back("-std=c++98"); + FileName = "input.cc"; + break; + } + + // Default to failure in case callback is never called + setFailure("Could not find match"); + if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName)) + return testing::AssertionFailure() << "Parsing error"; + if (!Verified) + return testing::AssertionFailure() << VerifyResult; + return testing::AssertionSuccess(); +} + +template <typename NodeType> +void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) { + const NodeType *Node = Result.Nodes.getNodeAs<NodeType>(""); + if (!Node) { + setFailure("Matched node has wrong type"); + } else { + // Callback has been called, default to success + Verified = true; + verify(Result, *Node); + } +} + +/// \brief Verify whether a node has the correct source location. +/// +/// By default, Node.getSourceLocation() is checked. This can be changed +/// by overriding getLocation(). +template <typename NodeType> +class LocationVerifier : public MatchVerifier<NodeType> { +public: + void expectLocation(unsigned Line, unsigned Column) { + ExpectLine = Line; + ExpectColumn = Column; + } + +protected: + void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) { + SourceLocation Loc = getLocation(Node); + unsigned Line = Result.SourceManager->getSpellingLineNumber(Loc); + unsigned Column = Result.SourceManager->getSpellingColumnNumber(Loc); + if (Line != ExpectLine || Column != ExpectColumn) { + std::string MsgStr; + llvm::raw_string_ostream Msg(MsgStr); + Msg << "Expected location <" << ExpectLine << ":" << ExpectColumn + << ">, found <"; + Loc.print(Msg, *Result.SourceManager); + Msg << '>'; + this->setFailure(Msg.str()); + } + } + + virtual SourceLocation getLocation(const NodeType &Node) { + return Node.getLocation(); + } + +private: + unsigned ExpectLine, ExpectColumn; +}; + +/// \brief Verify whether a node has the correct source range. +/// +/// By default, Node.getSourceRange() is checked. This can be changed +/// by overriding getRange(). +template <typename NodeType> +class RangeVerifier : public MatchVerifier<NodeType> { +public: + void expectRange(unsigned BeginLine, unsigned BeginColumn, + unsigned EndLine, unsigned EndColumn) { + ExpectBeginLine = BeginLine; + ExpectBeginColumn = BeginColumn; + ExpectEndLine = EndLine; + ExpectEndColumn = EndColumn; + } + +protected: + void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) { + SourceRange R = getRange(Node); + SourceLocation Begin = R.getBegin(); + SourceLocation End = R.getEnd(); + unsigned BeginLine = Result.SourceManager->getSpellingLineNumber(Begin); + unsigned BeginColumn = Result.SourceManager->getSpellingColumnNumber(Begin); + unsigned EndLine = Result.SourceManager->getSpellingLineNumber(End); + unsigned EndColumn = Result.SourceManager->getSpellingColumnNumber(End); + if (BeginLine != ExpectBeginLine || BeginColumn != ExpectBeginColumn || + EndLine != ExpectEndLine || EndColumn != ExpectEndColumn) { + std::string MsgStr; + llvm::raw_string_ostream Msg(MsgStr); + Msg << "Expected range <" << ExpectBeginLine << ":" << ExpectBeginColumn + << '-' << ExpectEndLine << ":" << ExpectEndColumn << ">, found <"; + Begin.print(Msg, *Result.SourceManager); + Msg << '-'; + End.print(Msg, *Result.SourceManager); + Msg << '>'; + this->setFailure(Msg.str()); + } + } + + virtual SourceRange getRange(const NodeType &Node) { + return Node.getSourceRange(); + } + +private: + unsigned ExpectBeginLine, ExpectBeginColumn, ExpectEndLine, ExpectEndColumn; +}; + +TEST(MatchVerifier, ParseError) { + LocationVerifier<VarDecl> Verifier; + Verifier.expectLocation(1, 1); + EXPECT_FALSE(Verifier.match("int i", varDecl())); +} + +TEST(MatchVerifier, NoMatch) { + LocationVerifier<VarDecl> Verifier; + Verifier.expectLocation(1, 1); + EXPECT_FALSE(Verifier.match("int i;", recordDecl())); +} + +TEST(MatchVerifier, WrongType) { + LocationVerifier<RecordDecl> Verifier; + Verifier.expectLocation(1, 1); + EXPECT_FALSE(Verifier.match("int i;", varDecl())); +} + +TEST(LocationVerifier, WrongLocation) { + LocationVerifier<VarDecl> Verifier; + Verifier.expectLocation(1, 1); + EXPECT_FALSE(Verifier.match("int i;", varDecl())); +} + +TEST(RangeVerifier, WrongRange) { + RangeVerifier<VarDecl> Verifier; + Verifier.expectRange(1, 1, 1, 1); + EXPECT_FALSE(Verifier.match("int i;", varDecl())); +} + +class LabelDeclRangeVerifier : public RangeVerifier<LabelStmt> { +protected: + virtual SourceRange getRange(const LabelStmt &Node) { + return Node.getDecl()->getSourceRange(); + } +}; + +TEST(LabelDecl, Range) { + LabelDeclRangeVerifier Verifier; + Verifier.expectRange(1, 12, 1, 12); + EXPECT_TRUE(Verifier.match("void f() { l: return; }", labelStmt())); +} + +TEST(LabelStmt, Range) { + RangeVerifier<LabelStmt> Verifier; + Verifier.expectRange(1, 12, 1, 15); + EXPECT_TRUE(Verifier.match("void f() { l: return; }", labelStmt())); +} + +TEST(ParmVarDecl, KNRLocation) { + LocationVerifier<ParmVarDecl> Verifier; + Verifier.expectLocation(1, 8); + EXPECT_TRUE(Verifier.match("void f(i) {}", varDecl(), Lang_C)); +} + +TEST(ParmVarDecl, KNRRange) { + RangeVerifier<ParmVarDecl> Verifier; + Verifier.expectRange(1, 8, 1, 8); + EXPECT_TRUE(Verifier.match("void f(i) {}", varDecl(), Lang_C)); +} + +TEST(CXXNewExpr, ArrayRange) { + RangeVerifier<CXXNewExpr> Verifier; + Verifier.expectRange(1, 12, 1, 22); + EXPECT_TRUE(Verifier.match("void f() { new int[10]; }", newExpr())); +} + +TEST(CXXNewExpr, ParenRange) { + RangeVerifier<CXXNewExpr> Verifier; + Verifier.expectRange(1, 12, 1, 20); + EXPECT_TRUE(Verifier.match("void f() { new int(); }", newExpr())); +} + +TEST(MemberExpr, ImplicitMemberRange) { + RangeVerifier<MemberExpr> Verifier; + Verifier.expectRange(2, 30, 2, 30); + EXPECT_TRUE(Verifier.match("struct S { operator int() const; };\n" + "int foo(const S& s) { return s; }", + memberExpr())); +} + +TEST(VarDecl, VMTypeFixedVarDeclRange) { + RangeVerifier<VarDecl> Verifier; + Verifier.expectRange(1, 1, 1, 23); + EXPECT_TRUE(Verifier.match("int a[(int)(void*)1234];", + varDecl(), Lang_C89)); +} + +TEST(CXXConstructorDecl, NoRetFunTypeLocRange) { + RangeVerifier<CXXConstructorDecl> Verifier; + Verifier.expectRange(1, 11, 1, 13); + EXPECT_TRUE(Verifier.match("class C { C(); };", functionDecl())); +} + +} // end namespace ast_matchers +} // end namespace clang diff --git a/unittests/AST/StmtPrinterTest.cpp b/unittests/AST/StmtPrinterTest.cpp new file mode 100644 index 0000000000000..0fd1b2e6c3c85 --- /dev/null +++ b/unittests/AST/StmtPrinterTest.cpp @@ -0,0 +1,172 @@ +//===- unittests/AST/StmtPrinterTest.cpp --- Statement printer tests ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains tests for Stmt::printPretty() and related methods. +// +// Search this file for WRONG to see test cases that are producing something +// completely wrong, invalid C++ or just misleading. +// +// These tests have a coding convention: +// * statements to be printed should be contained within a function named 'A' +// unless it should have some special name (e.g., 'operator+'); +// * additional helper declarations are 'Z', 'Y', 'X' and so on. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/SmallString.h" +#include "gtest/gtest.h" + +using namespace clang; +using namespace ast_matchers; +using namespace tooling; + +namespace { + +void PrintStmt(raw_ostream &Out, const ASTContext *Context, const Stmt *S) { + PrintingPolicy Policy = Context->getPrintingPolicy(); + S->printPretty(Out, /*Helper*/ 0, Policy); +} + +class PrintMatch : public MatchFinder::MatchCallback { + SmallString<1024> Printed; + unsigned NumFoundStmts; + +public: + PrintMatch() : NumFoundStmts(0) {} + + virtual void run(const MatchFinder::MatchResult &Result) { + const Stmt *S = Result.Nodes.getStmtAs<Stmt>("id"); + if (!S) + return; + NumFoundStmts++; + if (NumFoundStmts > 1) + return; + + llvm::raw_svector_ostream Out(Printed); + PrintStmt(Out, Result.Context, S); + } + + StringRef getPrinted() const { + return Printed; + } + + unsigned getNumFoundStmts() const { + return NumFoundStmts; + } +}; + +::testing::AssertionResult PrintedStmtMatches( + StringRef Code, + const std::vector<std::string> &Args, + const DeclarationMatcher &NodeMatch, + StringRef ExpectedPrinted) { + + PrintMatch Printer; + MatchFinder Finder; + Finder.addMatcher(NodeMatch, &Printer); + OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder)); + + if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) + return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; + + if (Printer.getNumFoundStmts() == 0) + return testing::AssertionFailure() + << "Matcher didn't find any statements"; + + if (Printer.getNumFoundStmts() > 1) + return testing::AssertionFailure() + << "Matcher should match only one statement " + "(found " << Printer.getNumFoundStmts() << ")"; + + if (Printer.getPrinted() != ExpectedPrinted) + return ::testing::AssertionFailure() + << "Expected \"" << ExpectedPrinted << "\", " + "got \"" << Printer.getPrinted() << "\""; + + return ::testing::AssertionSuccess(); +} + +::testing::AssertionResult PrintedStmtCXX98Matches( + StringRef Code, + StringRef ContainingFunction, + StringRef ExpectedPrinted) { + std::vector<std::string> Args; + Args.push_back("-std=c++98"); + Args.push_back("-Wno-unused-value"); + return PrintedStmtMatches(Code, + Args, + functionDecl(hasName(ContainingFunction), + has(compoundStmt(has(stmt().bind("id"))))), + ExpectedPrinted); +} + +::testing::AssertionResult PrintedStmtMSMatches( + StringRef Code, + StringRef ContainingFunction, + StringRef ExpectedPrinted) { + std::vector<std::string> Args; + Args.push_back("-std=c++98"); + Args.push_back("-fms-extensions"); + Args.push_back("-Wno-unused-value"); + return PrintedStmtMatches(Code, + Args, + functionDecl(hasName(ContainingFunction), + has(compoundStmt(has(stmt().bind("id"))))), + ExpectedPrinted); +} + +} // unnamed namespace + +TEST(StmtPrinter, TestIntegerLiteral) { + ASSERT_TRUE(PrintedStmtCXX98Matches( + "void A() {" + " 1, -1, 1U, 1u," + " 1L, 1l, -1L, 1UL, 1ul," + " 1LL, -1LL, 1ULL;" + "}", + "A", + "1 , -1 , 1U , 1U , " + "1L , 1L , -1L , 1UL , 1UL , " + "1LL , -1LL , 1ULL")); + // Should be: with semicolon +} + +TEST(StmtPrinter, TestMSIntegerLiteral) { + ASSERT_TRUE(PrintedStmtMSMatches( + "void A() {" + " 1i8, -1i8, 1ui8, " + " 1i16, -1i16, 1ui16, " + " 1i32, -1i32, 1ui32, " + " 1i64, -1i64, 1ui64, " + " 1i128, -1i128, 1ui128, 1Ui128," + " 0x10000000000000000i128;" + "}", + "A", + "1 , -1 , 1U , " + "1 , -1 , 1U , " + "1L , -1L , 1UL , " + "1LL , -1LL , 1ULL , " + "1 , -1 , 1U , 1U , " + "18446744073709551616i128")); + // Should be: with semicolon + // WRONG; all 128-bit literals should be printed as 128-bit. + // (This is because currently we do semantic analysis incorrectly.) +} + +TEST(StmtPrinter, TestFloatingPointLiteral) { + ASSERT_TRUE(PrintedStmtCXX98Matches( + "void A() { 1.0f, -1.0f, 1.0, -1.0, 1.0l, -1.0l; }", + "A", + "1.F , -1.F , 1. , -1. , 1.L , -1.L")); + // Should be: with semicolon +} + |