aboutsummaryrefslogtreecommitdiff
path: root/unittests/AST
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/AST')
-rw-r--r--unittests/AST/CMakeLists.txt5
-rw-r--r--unittests/AST/CommentLexer.cpp327
-rw-r--r--unittests/AST/CommentParser.cpp125
-rw-r--r--unittests/AST/DeclPrinterTest.cpp1248
-rw-r--r--unittests/AST/Makefile8
-rw-r--r--unittests/AST/SourceLocationTest.cpp289
-rw-r--r--unittests/AST/StmtPrinterTest.cpp172
7 files changed, 1999 insertions, 175 deletions
diff --git a/unittests/AST/CMakeLists.txt b/unittests/AST/CMakeLists.txt
index 63418a2937a1..1ea293ee83ae 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 cab0fdddbc2f..2723a611e106 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 7258a7ef576c..8fde2478e74c 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 000000000000..a2fc839b9c8e
--- /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 31cd5de1b741..e07fc45467b3 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 000000000000..dec833d15d80
--- /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 000000000000..0fd1b2e6c3c8
--- /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
+}
+