summaryrefslogtreecommitdiffstats
path: root/unittests
diff options
context:
space:
mode:
Diffstat (limited to 'unittests')
-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
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp1859
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h20
-rw-r--r--unittests/ASTMatchers/Makefile3
-rw-r--r--unittests/Basic/SourceManagerTest.cpp32
-rw-r--r--unittests/Frontend/Makefile3
-rw-r--r--unittests/Lex/CMakeLists.txt1
-rw-r--r--unittests/Lex/LexerTest.cpp21
-rw-r--r--unittests/Lex/PPCallbacksTest.cpp246
-rw-r--r--unittests/Lex/PreprocessingRecordTest.cpp21
-rw-r--r--unittests/Tooling/CMakeLists.txt2
-rw-r--r--unittests/Tooling/CompilationDatabaseTest.cpp123
-rw-r--r--unittests/Tooling/Makefile3
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTest.cpp68
-rw-r--r--unittests/Tooling/RefactoringCallbacksTest.cpp16
-rw-r--r--unittests/Tooling/RefactoringTest.cpp4
-rw-r--r--unittests/Tooling/RewriterTestContext.h11
-rw-r--r--unittests/Tooling/TestVisitor.h161
-rw-r--r--unittests/Tooling/ToolingTest.cpp32
25 files changed, 3993 insertions, 807 deletions
diff --git a/unittests/AST/CMakeLists.txt b/unittests/AST/CMakeLists.txt
index 63418a2..1ea293e 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 cab0fdd..2723a61 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 7258a7e..8fde247 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 0000000..a2fc839
--- /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 31cd5de..e07fc45 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 0000000..dec833d
--- /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 0000000..0fd1b2e
--- /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
+}
+
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index adf0e94..e15940a 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -19,21 +19,21 @@ namespace ast_matchers {
#if GTEST_HAS_DEATH_TEST
TEST(HasNameDeathTest, DiesOnEmptyName) {
ASSERT_DEBUG_DEATH({
- DeclarationMatcher HasEmptyName = record(hasName(""));
+ DeclarationMatcher HasEmptyName = recordDecl(hasName(""));
EXPECT_TRUE(notMatches("class X {};", HasEmptyName));
}, "");
}
TEST(HasNameDeathTest, DiesOnEmptyPattern) {
ASSERT_DEBUG_DEATH({
- DeclarationMatcher HasEmptyName = record(matchesName(""));
+ DeclarationMatcher HasEmptyName = recordDecl(matchesName(""));
EXPECT_TRUE(notMatches("class X {};", HasEmptyName));
}, "");
}
TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) {
ASSERT_DEBUG_DEATH({
- DeclarationMatcher IsDerivedFromEmpty = record(isDerivedFrom(""));
+ DeclarationMatcher IsDerivedFromEmpty = recordDecl(isDerivedFrom(""));
EXPECT_TRUE(notMatches("class X {};", IsDerivedFromEmpty));
}, "");
}
@@ -46,7 +46,7 @@ TEST(Decl, MatchesDeclarations) {
}
TEST(NameableDeclaration, MatchesVariousDecls) {
- DeclarationMatcher NamedX = nameableDeclaration(hasName("X"));
+ DeclarationMatcher NamedX = namedDecl(hasName("X"));
EXPECT_TRUE(matches("typedef int X;", NamedX));
EXPECT_TRUE(matches("int X;", NamedX));
EXPECT_TRUE(matches("class foo { virtual void X(); };", NamedX));
@@ -59,7 +59,7 @@ TEST(NameableDeclaration, MatchesVariousDecls) {
}
TEST(NameableDeclaration, REMatchesVariousDecls) {
- DeclarationMatcher NamedX = nameableDeclaration(matchesName("::X"));
+ DeclarationMatcher NamedX = namedDecl(matchesName("::X"));
EXPECT_TRUE(matches("typedef int Xa;", NamedX));
EXPECT_TRUE(matches("int Xb;", NamedX));
EXPECT_TRUE(matches("class foo { virtual void Xc(); };", NamedX));
@@ -70,11 +70,11 @@ TEST(NameableDeclaration, REMatchesVariousDecls) {
EXPECT_TRUE(notMatches("#define Xkl 1", NamedX));
- DeclarationMatcher StartsWithNo = nameableDeclaration(matchesName("::no"));
+ DeclarationMatcher StartsWithNo = namedDecl(matchesName("::no"));
EXPECT_TRUE(matches("int no_foo;", StartsWithNo));
EXPECT_TRUE(matches("class foo { virtual void nobody(); };", StartsWithNo));
- DeclarationMatcher Abc = nameableDeclaration(matchesName("a.*b.*c"));
+ DeclarationMatcher Abc = namedDecl(matchesName("a.*b.*c"));
EXPECT_TRUE(matches("int abc;", Abc));
EXPECT_TRUE(matches("int aFOObBARc;", Abc));
EXPECT_TRUE(notMatches("int cab;", Abc));
@@ -82,7 +82,7 @@ TEST(NameableDeclaration, REMatchesVariousDecls) {
}
TEST(DeclarationMatcher, MatchClass) {
- DeclarationMatcher ClassMatcher(record());
+ DeclarationMatcher ClassMatcher(recordDecl());
#if !defined(_MSC_VER)
EXPECT_FALSE(matches("", ClassMatcher));
#else
@@ -90,7 +90,7 @@ TEST(DeclarationMatcher, MatchClass) {
EXPECT_TRUE(matches("", ClassMatcher));
#endif
- DeclarationMatcher ClassX = record(record(hasName("X")));
+ DeclarationMatcher ClassX = recordDecl(recordDecl(hasName("X")));
EXPECT_TRUE(matches("class X;", ClassX));
EXPECT_TRUE(matches("class X {};", ClassX));
EXPECT_TRUE(matches("template<class T> class X {};", ClassX));
@@ -98,17 +98,24 @@ TEST(DeclarationMatcher, MatchClass) {
}
TEST(DeclarationMatcher, ClassIsDerived) {
- DeclarationMatcher IsDerivedFromX = record(isDerivedFrom("X"));
+ DeclarationMatcher IsDerivedFromX = recordDecl(isDerivedFrom("X"));
EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsDerivedFromX));
- EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsDerivedFromX));
- EXPECT_TRUE(matches("class X {};", IsDerivedFromX));
- EXPECT_TRUE(matches("class X;", IsDerivedFromX));
+ EXPECT_TRUE(notMatches("class X {};", IsDerivedFromX));
+ EXPECT_TRUE(notMatches("class X;", IsDerivedFromX));
EXPECT_TRUE(notMatches("class Y;", IsDerivedFromX));
EXPECT_TRUE(notMatches("", IsDerivedFromX));
+ DeclarationMatcher IsAX = recordDecl(isSameOrDerivedFrom("X"));
+
+ EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsAX));
+ EXPECT_TRUE(matches("class X {};", IsAX));
+ EXPECT_TRUE(matches("class X;", IsAX));
+ EXPECT_TRUE(notMatches("class Y;", IsAX));
+ EXPECT_TRUE(notMatches("", IsAX));
+
DeclarationMatcher ZIsDerivedFromX =
- record(hasName("Z"), isDerivedFrom("X"));
+ recordDecl(hasName("Z"), isDerivedFrom("X"));
EXPECT_TRUE(
matches("class X {}; class Y : public X {}; class Z : public Y {};",
ZIsDerivedFromX));
@@ -239,19 +246,17 @@ TEST(DeclarationMatcher, ClassIsDerived) {
"void f() { Z<float> z_float; Z<double> z_double; Z<char> z_char; }";
EXPECT_TRUE(matches(
RecursiveTemplateOneParameter,
- variable(hasName("z_float"),
- hasInitializer(hasType(record(isDerivedFrom("Base1")))))));
+ varDecl(hasName("z_float"),
+ hasInitializer(hasType(recordDecl(isDerivedFrom("Base1")))))));
EXPECT_TRUE(notMatches(
RecursiveTemplateOneParameter,
- variable(
- hasName("z_float"),
- hasInitializer(hasType(record(isDerivedFrom("Base2")))))));
+ varDecl(hasName("z_float"),
+ hasInitializer(hasType(recordDecl(isDerivedFrom("Base2")))))));
EXPECT_TRUE(matches(
RecursiveTemplateOneParameter,
- variable(
- hasName("z_char"),
- hasInitializer(hasType(record(isDerivedFrom("Base1"),
- isDerivedFrom("Base2")))))));
+ varDecl(hasName("z_char"),
+ hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"),
+ isDerivedFrom("Base2")))))));
const char *RecursiveTemplateTwoParameters =
"class Base1 {}; class Base2 {};"
@@ -266,47 +271,81 @@ TEST(DeclarationMatcher, ClassIsDerived) {
" Z<char, void> z_char; }";
EXPECT_TRUE(matches(
RecursiveTemplateTwoParameters,
- variable(
- hasName("z_float"),
- hasInitializer(hasType(record(isDerivedFrom("Base1")))))));
+ varDecl(hasName("z_float"),
+ hasInitializer(hasType(recordDecl(isDerivedFrom("Base1")))))));
EXPECT_TRUE(notMatches(
RecursiveTemplateTwoParameters,
- variable(
- hasName("z_float"),
- hasInitializer(hasType(record(isDerivedFrom("Base2")))))));
+ varDecl(hasName("z_float"),
+ hasInitializer(hasType(recordDecl(isDerivedFrom("Base2")))))));
EXPECT_TRUE(matches(
RecursiveTemplateTwoParameters,
- variable(
- hasName("z_char"),
- hasInitializer(hasType(record(isDerivedFrom("Base1"),
- isDerivedFrom("Base2")))))));
+ varDecl(hasName("z_char"),
+ hasInitializer(hasType(recordDecl(isDerivedFrom("Base1"),
+ isDerivedFrom("Base2")))))));
EXPECT_TRUE(matches(
"namespace ns { class X {}; class Y : public X {}; }",
- record(isDerivedFrom("::ns::X"))));
+ recordDecl(isDerivedFrom("::ns::X"))));
EXPECT_TRUE(notMatches(
"class X {}; class Y : public X {};",
- record(isDerivedFrom("::ns::X"))));
+ recordDecl(isDerivedFrom("::ns::X"))));
EXPECT_TRUE(matches(
"class X {}; class Y : public X {};",
- record(isDerivedFrom(record(hasName("X")).bind("test")))));
+ recordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test")))));
+}
+
+TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) {
+ EXPECT_TRUE(matches(
+ "template <typename T> struct A {"
+ " template <typename T2> struct F {};"
+ "};"
+ "template <typename T> struct B : A<T>::template F<T> {};"
+ "B<int> b;",
+ recordDecl(hasName("B"), isDerivedFrom(recordDecl()))));
+}
+
+TEST(ClassTemplate, DoesNotMatchClass) {
+ DeclarationMatcher ClassX = classTemplateDecl(hasName("X"));
+ EXPECT_TRUE(notMatches("class X;", ClassX));
+ EXPECT_TRUE(notMatches("class X {};", ClassX));
+}
+
+TEST(ClassTemplate, MatchesClassTemplate) {
+ DeclarationMatcher ClassX = classTemplateDecl(hasName("X"));
+ EXPECT_TRUE(matches("template<typename T> class X {};", ClassX));
+ EXPECT_TRUE(matches("class Z { template<class T> class X {}; };", ClassX));
+}
+
+TEST(ClassTemplate, DoesNotMatchClassTemplateExplicitSpecialization) {
+ EXPECT_TRUE(notMatches("template<typename T> class X { };"
+ "template<> class X<int> { int a; };",
+ classTemplateDecl(hasName("X"),
+ hasDescendant(fieldDecl(hasName("a"))))));
+}
+
+TEST(ClassTemplate, DoesNotMatchClassTemplatePartialSpecialization) {
+ EXPECT_TRUE(notMatches("template<typename T, typename U> class X { };"
+ "template<typename T> class X<T, int> { int a; };",
+ classTemplateDecl(hasName("X"),
+ hasDescendant(fieldDecl(hasName("a"))))));
}
TEST(AllOf, AllOverloadsWork) {
const char Program[] =
"struct T { }; int f(int, T*); void g(int x) { T t; f(x, &t); }";
EXPECT_TRUE(matches(Program,
- call(allOf(callee(function(hasName("f"))),
- hasArgument(0, declarationReference(to(variable())))))));
+ callExpr(allOf(callee(functionDecl(hasName("f"))),
+ hasArgument(0, declRefExpr(to(varDecl())))))));
EXPECT_TRUE(matches(Program,
- call(allOf(callee(function(hasName("f"))),
- hasArgument(0, declarationReference(to(variable()))),
- hasArgument(1, hasType(pointsTo(record(hasName("T")))))))));
+ callExpr(allOf(callee(functionDecl(hasName("f"))),
+ hasArgument(0, declRefExpr(to(varDecl()))),
+ hasArgument(1, hasType(pointsTo(
+ recordDecl(hasName("T")))))))));
}
TEST(DeclarationMatcher, MatchAnyOf) {
DeclarationMatcher YOrZDerivedFromX =
- record(anyOf(hasName("Y"), allOf(isDerivedFrom("X"), hasName("Z"))));
+ recordDecl(anyOf(hasName("Y"), allOf(isDerivedFrom("X"), hasName("Z"))));
EXPECT_TRUE(
matches("class X {}; class Z : public X {};", YOrZDerivedFromX));
EXPECT_TRUE(matches("class Y {};", YOrZDerivedFromX));
@@ -315,13 +354,13 @@ TEST(DeclarationMatcher, MatchAnyOf) {
EXPECT_TRUE(notMatches("class Z {};", YOrZDerivedFromX));
DeclarationMatcher XOrYOrZOrU =
- record(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U")));
+ recordDecl(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U")));
EXPECT_TRUE(matches("class X {};", XOrYOrZOrU));
EXPECT_TRUE(notMatches("class V {};", XOrYOrZOrU));
DeclarationMatcher XOrYOrZOrUOrV =
- record(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U"),
- hasName("V")));
+ recordDecl(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U"),
+ hasName("V")));
EXPECT_TRUE(matches("class X {};", XOrYOrZOrUOrV));
EXPECT_TRUE(matches("class Y {};", XOrYOrZOrUOrV));
EXPECT_TRUE(matches("class Z {};", XOrYOrZOrUOrV));
@@ -331,13 +370,12 @@ TEST(DeclarationMatcher, MatchAnyOf) {
}
TEST(DeclarationMatcher, MatchHas) {
- DeclarationMatcher HasClassX = record(has(record(hasName("X"))));
-
+ DeclarationMatcher HasClassX = recordDecl(has(recordDecl(hasName("X"))));
EXPECT_TRUE(matches("class Y { class X {}; };", HasClassX));
EXPECT_TRUE(matches("class X {};", HasClassX));
DeclarationMatcher YHasClassX =
- record(hasName("Y"), has(record(hasName("X"))));
+ recordDecl(hasName("Y"), has(recordDecl(hasName("X"))));
EXPECT_TRUE(matches("class Y { class X {}; };", YHasClassX));
EXPECT_TRUE(notMatches("class X {};", YHasClassX));
EXPECT_TRUE(
@@ -346,14 +384,14 @@ TEST(DeclarationMatcher, MatchHas) {
TEST(DeclarationMatcher, MatchHasRecursiveAllOf) {
DeclarationMatcher Recursive =
- record(
- has(record(
- has(record(hasName("X"))),
- has(record(hasName("Y"))),
+ recordDecl(
+ has(recordDecl(
+ has(recordDecl(hasName("X"))),
+ has(recordDecl(hasName("Y"))),
hasName("Z"))),
- has(record(
- has(record(hasName("A"))),
- has(record(hasName("B"))),
+ has(recordDecl(
+ has(recordDecl(hasName("A"))),
+ has(recordDecl(hasName("B"))),
hasName("C"))),
hasName("F"));
@@ -404,21 +442,21 @@ TEST(DeclarationMatcher, MatchHasRecursiveAllOf) {
TEST(DeclarationMatcher, MatchHasRecursiveAnyOf) {
DeclarationMatcher Recursive =
- record(
+ recordDecl(
anyOf(
- has(record(
+ has(recordDecl(
anyOf(
- has(record(
+ has(recordDecl(
hasName("X"))),
- has(record(
+ has(recordDecl(
hasName("Y"))),
hasName("Z")))),
- has(record(
+ has(recordDecl(
anyOf(
hasName("C"),
- has(record(
+ has(recordDecl(
hasName("A"))),
- has(record(
+ has(recordDecl(
hasName("B")))))),
hasName("F")));
@@ -435,9 +473,8 @@ TEST(DeclarationMatcher, MatchHasRecursiveAnyOf) {
TEST(DeclarationMatcher, MatchNot) {
DeclarationMatcher NotClassX =
- record(
+ recordDecl(
isDerivedFrom("Y"),
- unless(hasName("Y")),
unless(hasName("X")));
EXPECT_TRUE(notMatches("", NotClassX));
EXPECT_TRUE(notMatches("class Y {};", NotClassX));
@@ -448,11 +485,11 @@ TEST(DeclarationMatcher, MatchNot) {
NotClassX));
DeclarationMatcher ClassXHasNotClassY =
- record(
+ recordDecl(
hasName("X"),
- has(record(hasName("Z"))),
+ has(recordDecl(hasName("Z"))),
unless(
- has(record(hasName("Y")))));
+ has(recordDecl(hasName("Y")))));
EXPECT_TRUE(matches("class X { class Z {}; };", ClassXHasNotClassY));
EXPECT_TRUE(notMatches("class X { class Y {}; class Z {}; };",
ClassXHasNotClassY));
@@ -460,8 +497,8 @@ TEST(DeclarationMatcher, MatchNot) {
TEST(DeclarationMatcher, HasDescendant) {
DeclarationMatcher ZDescendantClassX =
- record(
- hasDescendant(record(hasName("X"))),
+ recordDecl(
+ hasDescendant(recordDecl(hasName("X"))),
hasName("Z"));
EXPECT_TRUE(matches("class Z { class X {}; };", ZDescendantClassX));
EXPECT_TRUE(
@@ -475,8 +512,8 @@ TEST(DeclarationMatcher, HasDescendant) {
EXPECT_TRUE(notMatches("class Z {};", ZDescendantClassX));
DeclarationMatcher ZDescendantClassXHasClassY =
- record(
- hasDescendant(record(has(record(hasName("Y"))),
+ recordDecl(
+ hasDescendant(recordDecl(has(recordDecl(hasName("Y"))),
hasName("X"))),
hasName("Z"));
EXPECT_TRUE(matches("class Z { class X { class Y {}; }; };",
@@ -498,9 +535,9 @@ TEST(DeclarationMatcher, HasDescendant) {
"};", ZDescendantClassXHasClassY));
DeclarationMatcher ZDescendantClassXDescendantClassY =
- record(
- hasDescendant(record(hasDescendant(record(hasName("Y"))),
- hasName("X"))),
+ recordDecl(
+ hasDescendant(recordDecl(hasDescendant(recordDecl(hasName("Y"))),
+ hasName("X"))),
hasName("Z"));
EXPECT_TRUE(
matches("class Z { class A { class X { class B { class Y {}; }; }; }; };",
@@ -518,6 +555,118 @@ TEST(DeclarationMatcher, HasDescendant) {
"};", ZDescendantClassXDescendantClassY));
}
+// Implements a run method that returns whether BoundNodes contains a
+// Decl bound to Id that can be dynamically cast to T.
+// Optionally checks that the check succeeded a specific number of times.
+template <typename T>
+class VerifyIdIsBoundTo : public BoundNodesCallback {
+public:
+ // Create an object that checks that a node of type \c T was bound to \c Id.
+ // Does not check for a certain number of matches.
+ explicit VerifyIdIsBoundTo(llvm::StringRef Id)
+ : Id(Id), ExpectedCount(-1), Count(0) {}
+
+ // Create an object that checks that a node of type \c T was bound to \c Id.
+ // Checks that there were exactly \c ExpectedCount matches.
+ VerifyIdIsBoundTo(llvm::StringRef Id, int ExpectedCount)
+ : Id(Id), ExpectedCount(ExpectedCount), Count(0) {}
+
+ // Create an object that checks that a node of type \c T was bound to \c Id.
+ // Checks that there was exactly one match with the name \c ExpectedName.
+ // Note that \c T must be a NamedDecl for this to work.
+ VerifyIdIsBoundTo(llvm::StringRef Id, llvm::StringRef ExpectedName)
+ : Id(Id), ExpectedCount(1), Count(0), ExpectedName(ExpectedName) {}
+
+ ~VerifyIdIsBoundTo() {
+ if (ExpectedCount != -1)
+ EXPECT_EQ(ExpectedCount, Count);
+ if (!ExpectedName.empty())
+ EXPECT_EQ(ExpectedName, Name);
+ }
+
+ virtual bool run(const BoundNodes *Nodes) {
+ if (Nodes->getNodeAs<T>(Id)) {
+ ++Count;
+ if (const NamedDecl *Named = Nodes->getNodeAs<NamedDecl>(Id)) {
+ Name = Named->getNameAsString();
+ } else if (const NestedNameSpecifier *NNS =
+ Nodes->getNodeAs<NestedNameSpecifier>(Id)) {
+ llvm::raw_string_ostream OS(Name);
+ NNS->print(OS, PrintingPolicy(LangOptions()));
+ }
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
+ return run(Nodes);
+ }
+
+private:
+ const std::string Id;
+ const int ExpectedCount;
+ int Count;
+ const std::string ExpectedName;
+ std::string Name;
+};
+
+TEST(HasDescendant, MatchesDescendantTypes) {
+ EXPECT_TRUE(matches("void f() { int i = 3; }",
+ decl(hasDescendant(loc(builtinType())))));
+ EXPECT_TRUE(matches("void f() { int i = 3; }",
+ stmt(hasDescendant(builtinType()))));
+
+ EXPECT_TRUE(matches("void f() { int i = 3; }",
+ stmt(hasDescendant(loc(builtinType())))));
+ EXPECT_TRUE(matches("void f() { int i = 3; }",
+ stmt(hasDescendant(qualType(builtinType())))));
+
+ EXPECT_TRUE(notMatches("void f() { float f = 2.0f; }",
+ stmt(hasDescendant(isInteger()))));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void f() { int a; float c; int d; int e; }",
+ functionDecl(forEachDescendant(
+ varDecl(hasDescendant(isInteger())).bind("x"))),
+ new VerifyIdIsBoundTo<Decl>("x", 3)));
+}
+
+TEST(HasDescendant, MatchesDescendantsOfTypes) {
+ EXPECT_TRUE(matches("void f() { int*** i; }",
+ qualType(hasDescendant(builtinType()))));
+ EXPECT_TRUE(matches("void f() { int*** i; }",
+ qualType(hasDescendant(
+ pointerType(pointee(builtinType()))))));
+ EXPECT_TRUE(matches("void f() { int*** i; }",
+ typeLoc(hasDescendant(builtinTypeLoc()))));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void f() { int*** i; }",
+ qualType(asString("int ***"), forEachDescendant(pointerType().bind("x"))),
+ new VerifyIdIsBoundTo<Type>("x", 2)));
+}
+
+TEST(Has, MatchesChildrenOfTypes) {
+ EXPECT_TRUE(matches("int i;",
+ varDecl(hasName("i"), has(isInteger()))));
+ EXPECT_TRUE(notMatches("int** i;",
+ varDecl(hasName("i"), has(isInteger()))));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "int (*f)(float, int);",
+ qualType(functionType(), forEach(qualType(isInteger()).bind("x"))),
+ new VerifyIdIsBoundTo<QualType>("x", 2)));
+}
+
+TEST(Has, MatchesChildTypes) {
+ EXPECT_TRUE(matches(
+ "int* i;",
+ varDecl(hasName("i"), hasType(qualType(has(builtinType()))))));
+ EXPECT_TRUE(notMatches(
+ "int* i;",
+ varDecl(hasName("i"), hasType(qualType(has(pointerType()))))));
+}
+
TEST(Enum, DoesNotMatchClasses) {
EXPECT_TRUE(notMatches("class X {};", enumDecl(hasName("X"))));
}
@@ -527,7 +676,7 @@ TEST(Enum, MatchesEnums) {
}
TEST(EnumConstant, Matches) {
- DeclarationMatcher Matcher = enumConstant(hasName("A"));
+ DeclarationMatcher Matcher = enumConstantDecl(hasName("A"));
EXPECT_TRUE(matches("enum X{ A };", Matcher));
EXPECT_TRUE(notMatches("enum X{ B };", Matcher));
EXPECT_TRUE(notMatches("enum X {};", Matcher));
@@ -535,9 +684,8 @@ TEST(EnumConstant, Matches) {
TEST(StatementMatcher, Has) {
StatementMatcher HasVariableI =
- expression(
- hasType(pointsTo(record(hasName("X")))),
- has(declarationReference(to(variable(hasName("i"))))));
+ expr(hasType(pointsTo(recordDecl(hasName("X")))),
+ has(declRefExpr(to(varDecl(hasName("i"))))));
EXPECT_TRUE(matches(
"class X; X *x(int); void c() { int i; x(i); }", HasVariableI));
@@ -547,9 +695,8 @@ TEST(StatementMatcher, Has) {
TEST(StatementMatcher, HasDescendant) {
StatementMatcher HasDescendantVariableI =
- expression(
- hasType(pointsTo(record(hasName("X")))),
- hasDescendant(declarationReference(to(variable(hasName("i"))))));
+ expr(hasType(pointsTo(recordDecl(hasName("X")))),
+ hasDescendant(declRefExpr(to(varDecl(hasName("i"))))));
EXPECT_TRUE(matches(
"class X; X *x(bool); bool b(int); void c() { int i; x(b(i)); }",
@@ -560,160 +707,127 @@ TEST(StatementMatcher, HasDescendant) {
}
TEST(TypeMatcher, MatchesClassType) {
- TypeMatcher TypeA = hasDeclaration(record(hasName("A")));
+ TypeMatcher TypeA = hasDeclaration(recordDecl(hasName("A")));
EXPECT_TRUE(matches("class A { public: A *a; };", TypeA));
EXPECT_TRUE(notMatches("class A {};", TypeA));
- TypeMatcher TypeDerivedFromA = hasDeclaration(record(isDerivedFrom("A")));
+ TypeMatcher TypeDerivedFromA = hasDeclaration(recordDecl(isDerivedFrom("A")));
EXPECT_TRUE(matches("class A {}; class B : public A { public: B *b; };",
TypeDerivedFromA));
EXPECT_TRUE(notMatches("class A {};", TypeA));
TypeMatcher TypeAHasClassB = hasDeclaration(
- record(hasName("A"), has(record(hasName("B")))));
+ recordDecl(hasName("A"), has(recordDecl(hasName("B")))));
EXPECT_TRUE(
matches("class A { public: A *a; class B {}; };", TypeAHasClassB));
}
-// Returns from Run whether 'bound_nodes' contain a Decl bound to 'Id', which
-// can be dynamically casted to T.
-// Optionally checks that the check succeeded a specific number of times.
-template <typename T>
-class VerifyIdIsBoundToDecl : public BoundNodesCallback {
-public:
- // Create an object that checks that a node of type 'T' was bound to 'Id'.
- // Does not check for a certain number of matches.
- explicit VerifyIdIsBoundToDecl(const std::string& Id)
- : Id(Id), ExpectedCount(-1), Count(0) {}
-
- // Create an object that checks that a node of type 'T' was bound to 'Id'.
- // Checks that there were exactly 'ExpectedCount' matches.
- explicit VerifyIdIsBoundToDecl(const std::string& Id, int ExpectedCount)
- : Id(Id), ExpectedCount(ExpectedCount), Count(0) {}
-
- ~VerifyIdIsBoundToDecl() {
- if (ExpectedCount != -1) {
- EXPECT_EQ(ExpectedCount, Count);
- }
- }
-
- virtual bool run(const BoundNodes *Nodes) {
- if (Nodes->getDeclAs<T>(Id) != NULL) {
- ++Count;
- return true;
- }
- return false;
- }
-
-private:
- const std::string Id;
- const int ExpectedCount;
- int Count;
-};
-template <typename T>
-class VerifyIdIsBoundToStmt : public BoundNodesCallback {
-public:
- explicit VerifyIdIsBoundToStmt(const std::string &Id) : Id(Id) {}
- virtual bool run(const BoundNodes *Nodes) {
- const T *Node = Nodes->getStmtAs<T>(Id);
- return Node != NULL;
- }
-private:
- const std::string Id;
-};
-
TEST(Matcher, BindMatchedNodes) {
- DeclarationMatcher ClassX = has(record(hasName("::X")).bind("x"));
+ DeclarationMatcher ClassX = has(recordDecl(hasName("::X")).bind("x"));
EXPECT_TRUE(matchAndVerifyResultTrue("class X {};",
- ClassX, new VerifyIdIsBoundToDecl<CXXRecordDecl>("x")));
+ ClassX, new VerifyIdIsBoundTo<CXXRecordDecl>("x")));
EXPECT_TRUE(matchAndVerifyResultFalse("class X {};",
- ClassX, new VerifyIdIsBoundToDecl<CXXRecordDecl>("other-id")));
+ ClassX, new VerifyIdIsBoundTo<CXXRecordDecl>("other-id")));
TypeMatcher TypeAHasClassB = hasDeclaration(
- record(hasName("A"), has(record(hasName("B")).bind("b"))));
+ recordDecl(hasName("A"), has(recordDecl(hasName("B")).bind("b"))));
EXPECT_TRUE(matchAndVerifyResultTrue("class A { public: A *a; class B {}; };",
TypeAHasClassB,
- new VerifyIdIsBoundToDecl<Decl>("b")));
+ new VerifyIdIsBoundTo<Decl>("b")));
- StatementMatcher MethodX = call(callee(method(hasName("x")))).bind("x");
+ StatementMatcher MethodX =
+ callExpr(callee(methodDecl(hasName("x")))).bind("x");
EXPECT_TRUE(matchAndVerifyResultTrue("class A { void x() { x(); } };",
MethodX,
- new VerifyIdIsBoundToStmt<CXXMemberCallExpr>("x")));
+ new VerifyIdIsBoundTo<CXXMemberCallExpr>("x")));
}
TEST(Matcher, BindTheSameNameInAlternatives) {
StatementMatcher matcher = anyOf(
binaryOperator(hasOperatorName("+"),
- hasLHS(expression().bind("x")),
+ hasLHS(expr().bind("x")),
hasRHS(integerLiteral(equals(0)))),
binaryOperator(hasOperatorName("+"),
hasLHS(integerLiteral(equals(0))),
- hasRHS(expression().bind("x"))));
+ hasRHS(expr().bind("x"))));
EXPECT_TRUE(matchAndVerifyResultTrue(
// The first branch of the matcher binds x to 0 but then fails.
// The second branch binds x to f() and succeeds.
"int f() { return 0 + f(); }",
matcher,
- new VerifyIdIsBoundToStmt<CallExpr>("x")));
+ new VerifyIdIsBoundTo<CallExpr>("x")));
+}
+
+TEST(Matcher, BindsIDForMemoizedResults) {
+ // Using the same matcher in two match expressions will make memoization
+ // kick in.
+ DeclarationMatcher ClassX = recordDecl(hasName("X")).bind("x");
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { class B { class X {}; }; };",
+ DeclarationMatcher(anyOf(
+ recordDecl(hasName("A"), hasDescendant(ClassX)),
+ recordDecl(hasName("B"), hasDescendant(ClassX)))),
+ new VerifyIdIsBoundTo<Decl>("x", 2)));
}
TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
- TypeMatcher ClassX = hasDeclaration(record(hasName("X")));
+ TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X")));
EXPECT_TRUE(
- matches("class X {}; void y(X &x) { x; }", expression(hasType(ClassX))));
+ matches("class X {}; void y(X &x) { x; }", expr(hasType(ClassX))));
EXPECT_TRUE(
notMatches("class X {}; void y(X *x) { x; }",
- expression(hasType(ClassX))));
+ expr(hasType(ClassX))));
EXPECT_TRUE(
matches("class X {}; void y(X *x) { x; }",
- expression(hasType(pointsTo(ClassX)))));
+ expr(hasType(pointsTo(ClassX)))));
}
TEST(HasType, TakesQualTypeMatcherAndMatchesValueDecl) {
- TypeMatcher ClassX = hasDeclaration(record(hasName("X")));
+ TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X")));
EXPECT_TRUE(
- matches("class X {}; void y() { X x; }", variable(hasType(ClassX))));
+ matches("class X {}; void y() { X x; }", varDecl(hasType(ClassX))));
EXPECT_TRUE(
- notMatches("class X {}; void y() { X *x; }", variable(hasType(ClassX))));
+ notMatches("class X {}; void y() { X *x; }", varDecl(hasType(ClassX))));
EXPECT_TRUE(
matches("class X {}; void y() { X *x; }",
- variable(hasType(pointsTo(ClassX)))));
+ varDecl(hasType(pointsTo(ClassX)))));
}
TEST(HasType, TakesDeclMatcherAndMatchesExpr) {
- DeclarationMatcher ClassX = record(hasName("X"));
+ DeclarationMatcher ClassX = recordDecl(hasName("X"));
EXPECT_TRUE(
- matches("class X {}; void y(X &x) { x; }", expression(hasType(ClassX))));
+ matches("class X {}; void y(X &x) { x; }", expr(hasType(ClassX))));
EXPECT_TRUE(
notMatches("class X {}; void y(X *x) { x; }",
- expression(hasType(ClassX))));
+ expr(hasType(ClassX))));
}
TEST(HasType, TakesDeclMatcherAndMatchesValueDecl) {
- DeclarationMatcher ClassX = record(hasName("X"));
+ DeclarationMatcher ClassX = recordDecl(hasName("X"));
EXPECT_TRUE(
- matches("class X {}; void y() { X x; }", variable(hasType(ClassX))));
+ matches("class X {}; void y() { X x; }", varDecl(hasType(ClassX))));
EXPECT_TRUE(
- notMatches("class X {}; void y() { X *x; }", variable(hasType(ClassX))));
+ notMatches("class X {}; void y() { X *x; }", varDecl(hasType(ClassX))));
}
TEST(Matcher, Call) {
// FIXME: Do we want to overload Call() to directly take
// Matcher<Decl>, too?
- StatementMatcher MethodX = call(hasDeclaration(method(hasName("x"))));
+ StatementMatcher MethodX = callExpr(hasDeclaration(methodDecl(hasName("x"))));
EXPECT_TRUE(matches("class Y { void x() { x(); } };", MethodX));
EXPECT_TRUE(notMatches("class Y { void x() {} };", MethodX));
- StatementMatcher MethodOnY = memberCall(on(hasType(record(hasName("Y")))));
+ StatementMatcher MethodOnY =
+ memberCallExpr(on(hasType(recordDecl(hasName("Y")))));
EXPECT_TRUE(
matches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
@@ -732,7 +846,7 @@ TEST(Matcher, Call) {
MethodOnY));
StatementMatcher MethodOnYPointer =
- memberCall(on(hasType(pointsTo(record(hasName("Y"))))));
+ memberCallExpr(on(hasType(pointsTo(recordDecl(hasName("Y"))))));
EXPECT_TRUE(
matches("class Y { public: void x(); }; void z() { Y *y; y->x(); }",
@@ -751,20 +865,50 @@ TEST(Matcher, Call) {
MethodOnYPointer));
}
+TEST(Matcher, Lambda) {
+ EXPECT_TRUE(matches("auto f = [&] (int i) { return i; };",
+ lambdaExpr()));
+}
+
+TEST(Matcher, ForRange) {
+ EXPECT_TRUE(matches("int as[] = { 1, 2, 3 };"
+ "void f() { for (auto &a : as); }",
+ forRangeStmt()));
+ EXPECT_TRUE(notMatches("void f() { for (int i; i<5; ++i); }",
+ forRangeStmt()));
+}
+
+TEST(Matcher, UserDefinedLiteral) {
+ EXPECT_TRUE(matches("constexpr char operator \"\" _inc (const char i) {"
+ " return i + 1;"
+ "}"
+ "char c = 'a'_inc;",
+ userDefinedLiteral()));
+}
+
+TEST(Matcher, FlowControl) {
+ EXPECT_TRUE(matches("void f() { while(true) { break; } }", breakStmt()));
+ EXPECT_TRUE(matches("void f() { while(true) { continue; } }",
+ continueStmt()));
+ EXPECT_TRUE(matches("void f() { goto FOO; FOO: ;}", gotoStmt()));
+ EXPECT_TRUE(matches("void f() { goto FOO; FOO: ;}", labelStmt()));
+ EXPECT_TRUE(matches("void f() { return; }", returnStmt()));
+}
+
TEST(HasType, MatchesAsString) {
EXPECT_TRUE(
matches("class Y { public: void x(); }; void z() {Y* y; y->x(); }",
- memberCall(on(hasType(asString("class Y *"))))));
+ memberCallExpr(on(hasType(asString("class Y *"))))));
EXPECT_TRUE(matches("class X { void x(int x) {} };",
- method(hasParameter(0, hasType(asString("int"))))));
+ methodDecl(hasParameter(0, hasType(asString("int"))))));
EXPECT_TRUE(matches("namespace ns { struct A {}; } struct B { ns::A a; };",
- field(hasType(asString("ns::A")))));
+ fieldDecl(hasType(asString("ns::A")))));
EXPECT_TRUE(matches("namespace { struct A {}; } struct B { A a; };",
- field(hasType(asString("struct <anonymous>::A")))));
+ fieldDecl(hasType(asString("struct <anonymous>::A")))));
}
TEST(Matcher, OverloadedOperatorCall) {
- StatementMatcher OpCall = overloadedOperatorCall();
+ StatementMatcher OpCall = operatorCallExpr();
// Unary operator
EXPECT_TRUE(matches("class Y { }; "
"bool operator!(Y x) { return false; }; "
@@ -791,12 +935,12 @@ TEST(Matcher, OverloadedOperatorCall) {
TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) {
StatementMatcher OpCallAndAnd =
- overloadedOperatorCall(hasOverloadedOperatorName("&&"));
+ operatorCallExpr(hasOverloadedOperatorName("&&"));
EXPECT_TRUE(matches("class Y { }; "
"bool operator&&(Y x, Y y) { return true; }; "
"Y a; Y b; bool c = a && b;", OpCallAndAnd));
StatementMatcher OpCallLessLess =
- overloadedOperatorCall(hasOverloadedOperatorName("<<"));
+ operatorCallExpr(hasOverloadedOperatorName("<<"));
EXPECT_TRUE(notMatches("class Y { }; "
"bool operator&&(Y x, Y y) { return true; }; "
"Y a; Y b; bool c = a && b;",
@@ -805,7 +949,7 @@ TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) {
TEST(Matcher, ThisPointerType) {
StatementMatcher MethodOnY =
- memberCall(thisPointerType(record(hasName("Y"))));
+ memberCallExpr(thisPointerType(recordDecl(hasName("Y"))));
EXPECT_TRUE(
matches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
@@ -835,9 +979,9 @@ TEST(Matcher, ThisPointerType) {
TEST(Matcher, VariableUsage) {
StatementMatcher Reference =
- declarationReference(to(
- variable(hasInitializer(
- memberCall(thisPointerType(record(hasName("Y"))))))));
+ declRefExpr(to(
+ varDecl(hasInitializer(
+ memberCallExpr(thisPointerType(recordDecl(hasName("Y"))))))));
EXPECT_TRUE(matches(
"class Y {"
@@ -862,12 +1006,12 @@ TEST(Matcher, VariableUsage) {
TEST(Matcher, FindsVarDeclInFuncitonParameter) {
EXPECT_TRUE(matches(
"void f(int i) {}",
- variable(hasName("i"))));
+ varDecl(hasName("i"))));
}
TEST(Matcher, CalledVariable) {
- StatementMatcher CallOnVariableY = expression(
- memberCall(on(declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher CallOnVariableY =
+ memberCallExpr(on(declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(matches(
"class Y { public: void x() { Y y; y.x(); } };", CallOnVariableY));
@@ -904,81 +1048,81 @@ TEST(UnaryExpressionOrTypeTraitExpression, MatchesCorrectType) {
hasArgumentOfType(asString("float")))));
EXPECT_TRUE(matches(
"struct A {}; void x() { A a; int b = sizeof(a); }",
- sizeOfExpr(hasArgumentOfType(hasDeclaration(record(hasName("A")))))));
+ sizeOfExpr(hasArgumentOfType(hasDeclaration(recordDecl(hasName("A")))))));
EXPECT_TRUE(notMatches("void x() { int a = sizeof(a); }", sizeOfExpr(
- hasArgumentOfType(hasDeclaration(record(hasName("string")))))));
+ hasArgumentOfType(hasDeclaration(recordDecl(hasName("string")))))));
}
TEST(MemberExpression, DoesNotMatchClasses) {
- EXPECT_TRUE(notMatches("class Y { void x() {} };", memberExpression()));
+ EXPECT_TRUE(notMatches("class Y { void x() {} };", memberExpr()));
}
TEST(MemberExpression, MatchesMemberFunctionCall) {
- EXPECT_TRUE(matches("class Y { void x() { x(); } };", memberExpression()));
+ EXPECT_TRUE(matches("class Y { void x() { x(); } };", memberExpr()));
}
TEST(MemberExpression, MatchesVariable) {
EXPECT_TRUE(
- matches("class Y { void x() { this->y; } int y; };", memberExpression()));
+ matches("class Y { void x() { this->y; } int y; };", memberExpr()));
EXPECT_TRUE(
- matches("class Y { void x() { y; } int y; };", memberExpression()));
+ matches("class Y { void x() { y; } int y; };", memberExpr()));
EXPECT_TRUE(
- matches("class Y { void x() { Y y; y.y; } int y; };",
- memberExpression()));
+ matches("class Y { void x() { Y y; y.y; } int y; };", memberExpr()));
}
TEST(MemberExpression, MatchesStaticVariable) {
EXPECT_TRUE(matches("class Y { void x() { this->y; } static int y; };",
- memberExpression()));
+ memberExpr()));
EXPECT_TRUE(notMatches("class Y { void x() { y; } static int y; };",
- memberExpression()));
+ memberExpr()));
EXPECT_TRUE(notMatches("class Y { void x() { Y::y; } static int y; };",
- memberExpression()));
+ memberExpr()));
}
TEST(IsInteger, MatchesIntegers) {
- EXPECT_TRUE(matches("int i = 0;", variable(hasType(isInteger()))));
- EXPECT_TRUE(matches("long long i = 0; void f(long long) { }; void g() {f(i);}",
- call(hasArgument(0, declarationReference(
- to(variable(hasType(isInteger()))))))));
+ EXPECT_TRUE(matches("int i = 0;", varDecl(hasType(isInteger()))));
+ EXPECT_TRUE(matches(
+ "long long i = 0; void f(long long) { }; void g() {f(i);}",
+ callExpr(hasArgument(0, declRefExpr(
+ to(varDecl(hasType(isInteger()))))))));
}
TEST(IsInteger, ReportsNoFalsePositives) {
- EXPECT_TRUE(notMatches("int *i;", variable(hasType(isInteger()))));
+ EXPECT_TRUE(notMatches("int *i;", varDecl(hasType(isInteger()))));
EXPECT_TRUE(notMatches("struct T {}; T t; void f(T *) { }; void g() {f(&t);}",
- call(hasArgument(0, declarationReference(
- to(variable(hasType(isInteger()))))))));
+ callExpr(hasArgument(0, declRefExpr(
+ to(varDecl(hasType(isInteger()))))))));
}
TEST(IsArrow, MatchesMemberVariablesViaArrow) {
EXPECT_TRUE(matches("class Y { void x() { this->y; } int y; };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
EXPECT_TRUE(matches("class Y { void x() { y; } int y; };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } int y; };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
}
TEST(IsArrow, MatchesStaticMemberVariablesViaArrow) {
EXPECT_TRUE(matches("class Y { void x() { this->y; } static int y; };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
EXPECT_TRUE(notMatches("class Y { void x() { y; } static int y; };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } static int y; };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
}
TEST(IsArrow, MatchesMemberCallsViaArrow) {
EXPECT_TRUE(matches("class Y { void x() { this->x(); } };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
EXPECT_TRUE(matches("class Y { void x() { x(); } };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
EXPECT_TRUE(notMatches("class Y { void x() { Y y; y.x(); } };",
- memberExpression(isArrow())));
+ memberExpr(isArrow())));
}
TEST(Callee, MatchesDeclarations) {
- StatementMatcher CallMethodX = call(callee(method(hasName("x"))));
+ StatementMatcher CallMethodX = callExpr(callee(methodDecl(hasName("x"))));
EXPECT_TRUE(matches("class Y { void x() { x(); } };", CallMethodX));
EXPECT_TRUE(notMatches("class Y { void x() {} };", CallMethodX));
@@ -986,13 +1130,13 @@ TEST(Callee, MatchesDeclarations) {
TEST(Callee, MatchesMemberExpressions) {
EXPECT_TRUE(matches("class Y { void x() { this->x(); } };",
- call(callee(memberExpression()))));
+ callExpr(callee(memberExpr()))));
EXPECT_TRUE(
- notMatches("class Y { void x() { this->x(); } };", call(callee(call()))));
+ notMatches("class Y { void x() { this->x(); } };", callExpr(callee(callExpr()))));
}
TEST(Function, MatchesFunctionDeclarations) {
- StatementMatcher CallFunctionF = call(callee(function(hasName("f"))));
+ StatementMatcher CallFunctionF = callExpr(callee(functionDecl(hasName("f"))));
EXPECT_TRUE(matches("void f() { f(); }", CallFunctionF));
EXPECT_TRUE(notMatches("void f() { }", CallFunctionF));
@@ -1017,30 +1161,51 @@ TEST(Function, MatchesFunctionDeclarations) {
CallFunctionF));
}
+TEST(FunctionTemplate, MatchesFunctionTemplateDeclarations) {
+ EXPECT_TRUE(
+ matches("template <typename T> void f(T t) {}",
+ functionTemplateDecl(hasName("f"))));
+}
+
+TEST(FunctionTemplate, DoesNotMatchFunctionDeclarations) {
+ EXPECT_TRUE(
+ notMatches("void f(double d); void f(int t) {}",
+ functionTemplateDecl(hasName("f"))));
+}
+
+TEST(FunctionTemplate, DoesNotMatchFunctionTemplateSpecializations) {
+ EXPECT_TRUE(
+ notMatches("void g(); template <typename T> void f(T t) {}"
+ "template <> void f(int t) { g(); }",
+ functionTemplateDecl(hasName("f"),
+ hasDescendant(declRefExpr(to(
+ functionDecl(hasName("g"))))))));
+}
+
TEST(Matcher, Argument) {
- StatementMatcher CallArgumentY = expression(call(
- hasArgument(0, declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher CallArgumentY = callExpr(
+ hasArgument(0, declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(matches("void x(int) { int y; x(y); }", CallArgumentY));
EXPECT_TRUE(
matches("class X { void x(int) { int y; x(y); } };", CallArgumentY));
EXPECT_TRUE(notMatches("void x(int) { int z; x(z); }", CallArgumentY));
- StatementMatcher WrongIndex = expression(call(
- hasArgument(42, declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher WrongIndex = callExpr(
+ hasArgument(42, declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(notMatches("void x(int) { int y; x(y); }", WrongIndex));
}
TEST(Matcher, AnyArgument) {
- StatementMatcher CallArgumentY = expression(call(
- hasAnyArgument(declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher CallArgumentY = callExpr(
+ hasAnyArgument(declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(matches("void x(int, int) { int y; x(1, y); }", CallArgumentY));
EXPECT_TRUE(matches("void x(int, int) { int y; x(y, 42); }", CallArgumentY));
EXPECT_TRUE(notMatches("void x(int, int) { x(1, 2); }", CallArgumentY));
}
TEST(Matcher, ArgumentCount) {
- StatementMatcher Call1Arg = expression(call(argumentCountIs(1)));
+ StatementMatcher Call1Arg = callExpr(argumentCountIs(1));
EXPECT_TRUE(matches("void x(int) { x(0); }", Call1Arg));
EXPECT_TRUE(matches("class X { void x(int) { x(0); } };", Call1Arg));
@@ -1048,8 +1213,8 @@ TEST(Matcher, ArgumentCount) {
}
TEST(Matcher, References) {
- DeclarationMatcher ReferenceClassX = variable(
- hasType(references(record(hasName("X")))));
+ DeclarationMatcher ReferenceClassX = varDecl(
+ hasType(references(recordDecl(hasName("X")))));
EXPECT_TRUE(matches("class X {}; void y(X y) { X &x = y; }",
ReferenceClassX));
EXPECT_TRUE(
@@ -1062,81 +1227,86 @@ TEST(Matcher, References) {
TEST(HasParameter, CallsInnerMatcher) {
EXPECT_TRUE(matches("class X { void x(int) {} };",
- method(hasParameter(0, variable()))));
+ methodDecl(hasParameter(0, varDecl()))));
EXPECT_TRUE(notMatches("class X { void x(int) {} };",
- method(hasParameter(0, hasName("x")))));
+ methodDecl(hasParameter(0, hasName("x")))));
}
TEST(HasParameter, DoesNotMatchIfIndexOutOfBounds) {
EXPECT_TRUE(notMatches("class X { void x(int) {} };",
- method(hasParameter(42, variable()))));
+ methodDecl(hasParameter(42, varDecl()))));
}
TEST(HasType, MatchesParameterVariableTypesStrictly) {
EXPECT_TRUE(matches("class X { void x(X x) {} };",
- method(hasParameter(0, hasType(record(hasName("X")))))));
+ methodDecl(hasParameter(0, hasType(recordDecl(hasName("X")))))));
EXPECT_TRUE(notMatches("class X { void x(const X &x) {} };",
- method(hasParameter(0, hasType(record(hasName("X")))))));
+ methodDecl(hasParameter(0, hasType(recordDecl(hasName("X")))))));
EXPECT_TRUE(matches("class X { void x(const X *x) {} };",
- method(hasParameter(0, hasType(pointsTo(record(hasName("X"))))))));
+ methodDecl(hasParameter(0,
+ hasType(pointsTo(recordDecl(hasName("X"))))))));
EXPECT_TRUE(matches("class X { void x(const X &x) {} };",
- method(hasParameter(0, hasType(references(record(hasName("X"))))))));
+ methodDecl(hasParameter(0,
+ hasType(references(recordDecl(hasName("X"))))))));
}
TEST(HasAnyParameter, MatchesIndependentlyOfPosition) {
EXPECT_TRUE(matches("class Y {}; class X { void x(X x, Y y) {} };",
- method(hasAnyParameter(hasType(record(hasName("X")))))));
+ methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X")))))));
EXPECT_TRUE(matches("class Y {}; class X { void x(Y y, X x) {} };",
- method(hasAnyParameter(hasType(record(hasName("X")))))));
+ methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X")))))));
}
TEST(Returns, MatchesReturnTypes) {
EXPECT_TRUE(matches("class Y { int f() { return 1; } };",
- function(returns(asString("int")))));
+ functionDecl(returns(asString("int")))));
EXPECT_TRUE(notMatches("class Y { int f() { return 1; } };",
- function(returns(asString("float")))));
+ functionDecl(returns(asString("float")))));
EXPECT_TRUE(matches("class Y { Y getMe() { return *this; } };",
- function(returns(hasDeclaration(record(hasName("Y")))))));
+ functionDecl(returns(hasDeclaration(
+ recordDecl(hasName("Y")))))));
}
TEST(IsExternC, MatchesExternCFunctionDeclarations) {
- EXPECT_TRUE(matches("extern \"C\" void f() {}", function(isExternC())));
- EXPECT_TRUE(matches("extern \"C\" { void f() {} }", function(isExternC())));
- EXPECT_TRUE(notMatches("void f() {}", function(isExternC())));
+ EXPECT_TRUE(matches("extern \"C\" void f() {}", functionDecl(isExternC())));
+ EXPECT_TRUE(matches("extern \"C\" { void f() {} }",
+ functionDecl(isExternC())));
+ EXPECT_TRUE(notMatches("void f() {}", functionDecl(isExternC())));
}
TEST(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) {
EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };",
- method(hasAnyParameter(hasType(record(hasName("X")))))));
+ methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X")))))));
}
TEST(HasAnyParameter, DoesNotMatchThisPointer) {
EXPECT_TRUE(notMatches("class Y {}; class X { void x() {} };",
- method(hasAnyParameter(hasType(pointsTo(record(hasName("X"))))))));
+ methodDecl(hasAnyParameter(hasType(pointsTo(
+ recordDecl(hasName("X"))))))));
}
TEST(HasName, MatchesParameterVariableDeclartions) {
EXPECT_TRUE(matches("class Y {}; class X { void x(int x) {} };",
- method(hasAnyParameter(hasName("x")))));
+ methodDecl(hasAnyParameter(hasName("x")))));
EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };",
- method(hasAnyParameter(hasName("x")))));
+ methodDecl(hasAnyParameter(hasName("x")))));
}
TEST(Matcher, MatchesClassTemplateSpecialization) {
EXPECT_TRUE(matches("template<typename T> struct A {};"
"template<> struct A<int> {};",
- classTemplateSpecialization()));
+ classTemplateSpecializationDecl()));
EXPECT_TRUE(matches("template<typename T> struct A {}; A<int> a;",
- classTemplateSpecialization()));
+ classTemplateSpecializationDecl()));
EXPECT_TRUE(notMatches("template<typename T> struct A {};",
- classTemplateSpecialization()));
+ classTemplateSpecializationDecl()));
}
TEST(Matcher, MatchesTypeTemplateArgument) {
EXPECT_TRUE(matches(
"template<typename T> struct B {};"
"B<int> b;",
- classTemplateSpecialization(hasAnyTemplateArgument(refersToType(
+ classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType(
asString("int"))))));
}
@@ -1145,25 +1315,31 @@ TEST(Matcher, MatchesDeclarationReferenceTemplateArgument) {
"struct B { int next; };"
"template<int(B::*next_ptr)> struct A {};"
"A<&B::next> a;",
- classTemplateSpecialization(hasAnyTemplateArgument(
- refersToDeclaration(field(hasName("next")))))));
+ classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToDeclaration(fieldDecl(hasName("next")))))));
+
+ EXPECT_TRUE(notMatches(
+ "template <typename T> struct A {};"
+ "A<int> a;",
+ classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToDeclaration(decl())))));
}
TEST(Matcher, MatchesSpecificArgument) {
EXPECT_TRUE(matches(
"template<typename T, typename U> class A {};"
"A<bool, int> a;",
- classTemplateSpecialization(hasTemplateArgument(
+ classTemplateSpecializationDecl(hasTemplateArgument(
1, refersToType(asString("int"))))));
EXPECT_TRUE(notMatches(
"template<typename T, typename U> class A {};"
"A<int, bool> a;",
- classTemplateSpecialization(hasTemplateArgument(
+ classTemplateSpecializationDecl(hasTemplateArgument(
1, refersToType(asString("int"))))));
}
TEST(Matcher, ConstructorCall) {
- StatementMatcher Constructor = expression(constructorCall());
+ StatementMatcher Constructor = constructExpr();
EXPECT_TRUE(
matches("class X { public: X(); }; void x() { X x; }", Constructor));
@@ -1177,8 +1353,8 @@ TEST(Matcher, ConstructorCall) {
}
TEST(Matcher, ConstructorArgument) {
- StatementMatcher Constructor = expression(constructorCall(
- hasArgument(0, declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher Constructor = constructExpr(
+ hasArgument(0, declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(
matches("class X { public: X(int); }; void x() { int y; X x(y); }",
@@ -1193,16 +1369,15 @@ TEST(Matcher, ConstructorArgument) {
notMatches("class X { public: X(int); }; void x() { int z; X x(z); }",
Constructor));
- StatementMatcher WrongIndex = expression(constructorCall(
- hasArgument(42, declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher WrongIndex = constructExpr(
+ hasArgument(42, declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(
notMatches("class X { public: X(int); }; void x() { int y; X x(y); }",
WrongIndex));
}
TEST(Matcher, ConstructorArgumentCount) {
- StatementMatcher Constructor1Arg =
- expression(constructorCall(argumentCountIs(1)));
+ StatementMatcher Constructor1Arg = constructExpr(argumentCountIs(1));
EXPECT_TRUE(
matches("class X { public: X(int); }; void x() { X x(0); }",
@@ -1218,8 +1393,15 @@ TEST(Matcher, ConstructorArgumentCount) {
Constructor1Arg));
}
+TEST(Matcher,ThisExpr) {
+ EXPECT_TRUE(
+ matches("struct X { int a; int f () { return a; } };", thisExpr()));
+ EXPECT_TRUE(
+ notMatches("struct X { int f () { int a; return a; } };", thisExpr()));
+}
+
TEST(Matcher, BindTemporaryExpression) {
- StatementMatcher TempExpression = expression(bindTemporaryExpression());
+ StatementMatcher TempExpression = bindTemporaryExpr();
std::string ClassString = "class string { public: string(); ~string(); }; ";
@@ -1249,44 +1431,80 @@ TEST(Matcher, BindTemporaryExpression) {
TempExpression));
}
+TEST(MaterializeTemporaryExpr, MatchesTemporary) {
+ std::string ClassString =
+ "class string { public: string(); int length(); }; ";
+
+ EXPECT_TRUE(
+ matches(ClassString +
+ "string GetStringByValue();"
+ "void FunctionTakesString(string s);"
+ "void run() { FunctionTakesString(GetStringByValue()); }",
+ materializeTemporaryExpr()));
+
+ EXPECT_TRUE(
+ notMatches(ClassString +
+ "string* GetStringPointer(); "
+ "void FunctionTakesStringPtr(string* s);"
+ "void run() {"
+ " string* s = GetStringPointer();"
+ " FunctionTakesStringPtr(GetStringPointer());"
+ " FunctionTakesStringPtr(s);"
+ "}",
+ materializeTemporaryExpr()));
+
+ EXPECT_TRUE(
+ notMatches(ClassString +
+ "string GetStringByValue();"
+ "void run() { int k = GetStringByValue().length(); }",
+ materializeTemporaryExpr()));
+
+ EXPECT_TRUE(
+ notMatches(ClassString +
+ "string GetStringByValue();"
+ "void run() { GetStringByValue(); }",
+ materializeTemporaryExpr()));
+}
+
TEST(ConstructorDeclaration, SimpleCase) {
EXPECT_TRUE(matches("class Foo { Foo(int i); };",
- constructor(ofClass(hasName("Foo")))));
+ constructorDecl(ofClass(hasName("Foo")))));
EXPECT_TRUE(notMatches("class Foo { Foo(int i); };",
- constructor(ofClass(hasName("Bar")))));
+ constructorDecl(ofClass(hasName("Bar")))));
}
TEST(ConstructorDeclaration, IsImplicit) {
// This one doesn't match because the constructor is not added by the
// compiler (it is not needed).
EXPECT_TRUE(notMatches("class Foo { };",
- constructor(isImplicit())));
+ constructorDecl(isImplicit())));
// The compiler added the implicit default constructor.
EXPECT_TRUE(matches("class Foo { }; Foo* f = new Foo();",
- constructor(isImplicit())));
+ constructorDecl(isImplicit())));
EXPECT_TRUE(matches("class Foo { Foo(){} };",
- constructor(unless(isImplicit()))));
+ constructorDecl(unless(isImplicit()))));
}
TEST(DestructorDeclaration, MatchesVirtualDestructor) {
EXPECT_TRUE(matches("class Foo { virtual ~Foo(); };",
- destructor(ofClass(hasName("Foo")))));
+ destructorDecl(ofClass(hasName("Foo")))));
}
TEST(DestructorDeclaration, DoesNotMatchImplicitDestructor) {
- EXPECT_TRUE(notMatches("class Foo {};", destructor(ofClass(hasName("Foo")))));
+ EXPECT_TRUE(notMatches("class Foo {};",
+ destructorDecl(ofClass(hasName("Foo")))));
}
TEST(HasAnyConstructorInitializer, SimpleCase) {
EXPECT_TRUE(notMatches(
"class Foo { Foo() { } };",
- constructor(hasAnyConstructorInitializer(anything()))));
+ constructorDecl(hasAnyConstructorInitializer(anything()))));
EXPECT_TRUE(matches(
"class Foo {"
" Foo() : foo_() { }"
" int foo_;"
"};",
- constructor(hasAnyConstructorInitializer(anything()))));
+ constructorDecl(hasAnyConstructorInitializer(anything()))));
}
TEST(HasAnyConstructorInitializer, ForField) {
@@ -1297,12 +1515,12 @@ TEST(HasAnyConstructorInitializer, ForField) {
" Baz foo_;"
" Baz bar_;"
"};";
- EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
- forField(hasType(record(hasName("Baz"))))))));
- EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
+ EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer(
+ forField(hasType(recordDecl(hasName("Baz"))))))));
+ EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer(
forField(hasName("foo_"))))));
- EXPECT_TRUE(notMatches(Code, constructor(hasAnyConstructorInitializer(
- forField(hasType(record(hasName("Bar"))))))));
+ EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer(
+ forField(hasType(recordDecl(hasName("Bar"))))))));
}
TEST(HasAnyConstructorInitializer, WithInitializer) {
@@ -1311,9 +1529,9 @@ TEST(HasAnyConstructorInitializer, WithInitializer) {
" Foo() : foo_(0) { }"
" int foo_;"
"};";
- EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
+ EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer(
withInitializer(integerLiteral(equals(0)))))));
- EXPECT_TRUE(notMatches(Code, constructor(hasAnyConstructorInitializer(
+ EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer(
withInitializer(integerLiteral(equals(1)))))));
}
@@ -1325,16 +1543,16 @@ TEST(HasAnyConstructorInitializer, IsWritten) {
" Bar foo_;"
" Bar bar_;"
"};";
- EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
+ EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer(
allOf(forField(hasName("foo_")), isWritten())))));
- EXPECT_TRUE(notMatches(Code, constructor(hasAnyConstructorInitializer(
+ EXPECT_TRUE(notMatches(Code, constructorDecl(hasAnyConstructorInitializer(
allOf(forField(hasName("bar_")), isWritten())))));
- EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
+ EXPECT_TRUE(matches(Code, constructorDecl(hasAnyConstructorInitializer(
allOf(forField(hasName("bar_")), unless(isWritten()))))));
}
TEST(Matcher, NewExpression) {
- StatementMatcher New = expression(newExpression());
+ StatementMatcher New = newExpr();
EXPECT_TRUE(matches("class X { public: X(); }; void x() { new X; }", New));
EXPECT_TRUE(
@@ -1345,9 +1563,8 @@ TEST(Matcher, NewExpression) {
}
TEST(Matcher, NewExpressionArgument) {
- StatementMatcher New = expression(constructorCall(
- hasArgument(
- 0, declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher New = constructExpr(
+ hasArgument(0, declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(
matches("class X { public: X(int); }; void x() { int y; new X(y); }",
@@ -1359,16 +1576,15 @@ TEST(Matcher, NewExpressionArgument) {
notMatches("class X { public: X(int); }; void x() { int z; new X(z); }",
New));
- StatementMatcher WrongIndex = expression(constructorCall(
- hasArgument(
- 42, declarationReference(to(variable(hasName("y")))))));
+ StatementMatcher WrongIndex = constructExpr(
+ hasArgument(42, declRefExpr(to(varDecl(hasName("y"))))));
EXPECT_TRUE(
notMatches("class X { public: X(int); }; void x() { int y; new X(y); }",
WrongIndex));
}
TEST(Matcher, NewExpressionArgumentCount) {
- StatementMatcher New = constructorCall(argumentCountIs(1));
+ StatementMatcher New = constructExpr(argumentCountIs(1));
EXPECT_TRUE(
matches("class X { public: X(int); }; void x() { new X(0); }", New));
@@ -1379,11 +1595,11 @@ TEST(Matcher, NewExpressionArgumentCount) {
TEST(Matcher, DeleteExpression) {
EXPECT_TRUE(matches("struct A {}; void f(A* a) { delete a; }",
- deleteExpression()));
+ deleteExpr()));
}
TEST(Matcher, DefaultArgument) {
- StatementMatcher Arg = defaultArgument();
+ StatementMatcher Arg = defaultArgExpr();
EXPECT_TRUE(matches("void x(int, int = 0) { int y; x(y); }", Arg));
EXPECT_TRUE(
@@ -1392,7 +1608,7 @@ TEST(Matcher, DefaultArgument) {
}
TEST(Matcher, StringLiterals) {
- StatementMatcher Literal = expression(stringLiteral());
+ StatementMatcher Literal = stringLiteral();
EXPECT_TRUE(matches("const char *s = \"string\";", Literal));
// wide string
EXPECT_TRUE(matches("const wchar_t *s = L\"string\";", Literal));
@@ -1403,7 +1619,7 @@ TEST(Matcher, StringLiterals) {
}
TEST(Matcher, CharacterLiterals) {
- StatementMatcher CharLiteral = expression(characterLiteral());
+ StatementMatcher CharLiteral = characterLiteral();
EXPECT_TRUE(matches("const char c = 'c';", CharLiteral));
// wide character
EXPECT_TRUE(matches("const char c = L'c';", CharLiteral));
@@ -1413,7 +1629,7 @@ TEST(Matcher, CharacterLiterals) {
}
TEST(Matcher, IntegerLiterals) {
- StatementMatcher HasIntLiteral = expression(integerLiteral());
+ StatementMatcher HasIntLiteral = integerLiteral();
EXPECT_TRUE(matches("int i = 10;", HasIntLiteral));
EXPECT_TRUE(matches("int i = 0x1AB;", HasIntLiteral));
EXPECT_TRUE(matches("int i = 10L;", HasIntLiteral));
@@ -1428,6 +1644,14 @@ TEST(Matcher, IntegerLiterals) {
EXPECT_TRUE(notMatches("int i = 10.0;", HasIntLiteral));
}
+TEST(Matcher, NullPtrLiteral) {
+ EXPECT_TRUE(matches("int* i = nullptr;", nullPtrLiteralExpr()));
+}
+
+TEST(Matcher, AsmStatement) {
+ EXPECT_TRUE(matches("void foo() { __asm(\"mov al, 2\"); }", asmStmt()));
+}
+
TEST(Matcher, Conditions) {
StatementMatcher Condition = ifStmt(hasCondition(boolLiteral(equals(true))));
@@ -1654,87 +1878,91 @@ TEST(ArraySubscriptMatchers, ArrayIndex) {
TEST(ArraySubscriptMatchers, MatchesArrayBase) {
EXPECT_TRUE(matches(
"int i[2]; void f() { i[1] = 2; }",
- arraySubscriptExpr(hasBase(implicitCast(
- hasSourceExpression(declarationReference()))))));
+ arraySubscriptExpr(hasBase(implicitCastExpr(
+ hasSourceExpression(declRefExpr()))))));
}
TEST(Matcher, HasNameSupportsNamespaces) {
EXPECT_TRUE(matches("namespace a { namespace b { class C; } }",
- record(hasName("a::b::C"))));
+ recordDecl(hasName("a::b::C"))));
EXPECT_TRUE(matches("namespace a { namespace b { class C; } }",
- record(hasName("::a::b::C"))));
+ recordDecl(hasName("::a::b::C"))));
EXPECT_TRUE(matches("namespace a { namespace b { class C; } }",
- record(hasName("b::C"))));
+ recordDecl(hasName("b::C"))));
EXPECT_TRUE(matches("namespace a { namespace b { class C; } }",
- record(hasName("C"))));
+ recordDecl(hasName("C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("c::b::C"))));
+ recordDecl(hasName("c::b::C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("a::c::C"))));
+ recordDecl(hasName("a::c::C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("a::b::A"))));
+ recordDecl(hasName("a::b::A"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("::C"))));
+ recordDecl(hasName("::C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("::b::C"))));
+ recordDecl(hasName("::b::C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("z::a::b::C"))));
+ recordDecl(hasName("z::a::b::C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
- record(hasName("a+b::C"))));
+ recordDecl(hasName("a+b::C"))));
EXPECT_TRUE(notMatches("namespace a { namespace b { class AC; } }",
- record(hasName("C"))));
+ recordDecl(hasName("C"))));
}
TEST(Matcher, HasNameSupportsOuterClasses) {
EXPECT_TRUE(
- matches("class A { class B { class C; }; };", record(hasName("A::B::C"))));
+ matches("class A { class B { class C; }; };",
+ recordDecl(hasName("A::B::C"))));
EXPECT_TRUE(
matches("class A { class B { class C; }; };",
- record(hasName("::A::B::C"))));
+ recordDecl(hasName("::A::B::C"))));
EXPECT_TRUE(
- matches("class A { class B { class C; }; };", record(hasName("B::C"))));
+ matches("class A { class B { class C; }; };",
+ recordDecl(hasName("B::C"))));
EXPECT_TRUE(
- matches("class A { class B { class C; }; };", record(hasName("C"))));
+ matches("class A { class B { class C; }; };",
+ recordDecl(hasName("C"))));
EXPECT_TRUE(
notMatches("class A { class B { class C; }; };",
- record(hasName("c::B::C"))));
+ recordDecl(hasName("c::B::C"))));
EXPECT_TRUE(
notMatches("class A { class B { class C; }; };",
- record(hasName("A::c::C"))));
+ recordDecl(hasName("A::c::C"))));
EXPECT_TRUE(
notMatches("class A { class B { class C; }; };",
- record(hasName("A::B::A"))));
+ recordDecl(hasName("A::B::A"))));
EXPECT_TRUE(
- notMatches("class A { class B { class C; }; };", record(hasName("::C"))));
+ notMatches("class A { class B { class C; }; };",
+ recordDecl(hasName("::C"))));
EXPECT_TRUE(
notMatches("class A { class B { class C; }; };",
- record(hasName("::B::C"))));
+ recordDecl(hasName("::B::C"))));
EXPECT_TRUE(notMatches("class A { class B { class C; }; };",
- record(hasName("z::A::B::C"))));
+ recordDecl(hasName("z::A::B::C"))));
EXPECT_TRUE(
notMatches("class A { class B { class C; }; };",
- record(hasName("A+B::C"))));
+ recordDecl(hasName("A+B::C"))));
}
TEST(Matcher, IsDefinition) {
DeclarationMatcher DefinitionOfClassA =
- record(hasName("A"), isDefinition());
+ recordDecl(hasName("A"), isDefinition());
EXPECT_TRUE(matches("class A {};", DefinitionOfClassA));
EXPECT_TRUE(notMatches("class A;", DefinitionOfClassA));
DeclarationMatcher DefinitionOfVariableA =
- variable(hasName("a"), isDefinition());
+ varDecl(hasName("a"), isDefinition());
EXPECT_TRUE(matches("int a;", DefinitionOfVariableA));
EXPECT_TRUE(notMatches("extern int a;", DefinitionOfVariableA));
DeclarationMatcher DefinitionOfMethodA =
- method(hasName("a"), isDefinition());
+ methodDecl(hasName("a"), isDefinition());
EXPECT_TRUE(matches("class A { void a() {} };", DefinitionOfMethodA));
EXPECT_TRUE(notMatches("class A { void a(); };", DefinitionOfMethodA));
}
TEST(Matcher, OfClass) {
- StatementMatcher Constructor = constructorCall(hasDeclaration(method(
+ StatementMatcher Constructor = constructExpr(hasDeclaration(methodDecl(
ofClass(hasName("X")))));
EXPECT_TRUE(
@@ -1751,7 +1979,8 @@ TEST(Matcher, VisitsTemplateInstantiations) {
EXPECT_TRUE(matches(
"class A { public: void x(); };"
"template <typename T> class B { public: void y() { T t; t.x(); } };"
- "void f() { B<A> b; b.y(); }", call(callee(method(hasName("x"))))));
+ "void f() { B<A> b; b.y(); }",
+ callExpr(callee(methodDecl(hasName("x"))))));
EXPECT_TRUE(matches(
"class A { public: void x(); };"
@@ -1761,8 +1990,9 @@ TEST(Matcher, VisitsTemplateInstantiations) {
"};"
"void f() {"
" C::B<A> b; b.y();"
- "}", record(hasName("C"),
- hasDescendant(call(callee(method(hasName("x"))))))));
+ "}",
+ recordDecl(hasName("C"),
+ hasDescendant(callExpr(callee(methodDecl(hasName("x"))))))));
}
TEST(Matcher, HandlesNullQualTypes) {
@@ -1781,7 +2011,7 @@ TEST(Matcher, HandlesNullQualTypes) {
"void g() {"
" f(0);"
"}",
- expression(hasType(TypeMatcher(
+ expr(hasType(TypeMatcher(
anyOf(
TypeMatcher(hasDeclaration(anything())),
pointsTo(AnyType),
@@ -1798,16 +2028,16 @@ AST_MATCHER_P(Decl, just, internal::Matcher<Decl>, AMatcher) {
}
TEST(AstMatcherPMacro, Works) {
- DeclarationMatcher HasClassB = just(has(record(hasName("B")).bind("b")));
+ DeclarationMatcher HasClassB = just(has(recordDecl(hasName("B")).bind("b")));
EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
- HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
+ HasClassB, new VerifyIdIsBoundTo<Decl>("b")));
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
- HasClassB, new VerifyIdIsBoundToDecl<Decl>("a")));
+ HasClassB, new VerifyIdIsBoundTo<Decl>("a")));
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
- HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
+ HasClassB, new VerifyIdIsBoundTo<Decl>("b")));
}
AST_POLYMORPHIC_MATCHER_P(
@@ -1815,27 +2045,27 @@ AST_POLYMORPHIC_MATCHER_P(
TOOLING_COMPILE_ASSERT((llvm::is_same<NodeType, Decl>::value) ||
(llvm::is_same<NodeType, Stmt>::value),
assert_node_type_is_accessible);
- internal::TypedBaseMatcher<Decl> ChildMatcher(AMatcher);
return Finder->matchesChildOf(
- Node, ChildMatcher, Builder,
+ Node, AMatcher, Builder,
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
ASTMatchFinder::BK_First);
}
TEST(AstPolymorphicMatcherPMacro, Works) {
- DeclarationMatcher HasClassB = polymorphicHas(record(hasName("B")).bind("b"));
+ DeclarationMatcher HasClassB =
+ polymorphicHas(recordDecl(hasName("B")).bind("b"));
EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
- HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
+ HasClassB, new VerifyIdIsBoundTo<Decl>("b")));
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
- HasClassB, new VerifyIdIsBoundToDecl<Decl>("a")));
+ HasClassB, new VerifyIdIsBoundTo<Decl>("a")));
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
- HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
+ HasClassB, new VerifyIdIsBoundTo<Decl>("b")));
StatementMatcher StatementHasClassB =
- polymorphicHas(record(hasName("B")));
+ polymorphicHas(recordDecl(hasName("B")));
EXPECT_TRUE(matches("void x() { class B {}; }", StatementHasClassB));
}
@@ -1843,6 +2073,9 @@ TEST(AstPolymorphicMatcherPMacro, Works) {
TEST(For, FindsForLoops) {
EXPECT_TRUE(matches("void f() { for(;;); }", forStmt()));
EXPECT_TRUE(matches("void f() { if(true) for(;;); }", forStmt()));
+ EXPECT_TRUE(notMatches("int as[] = { 1, 2, 3 };"
+ "void f() { for (auto &a : as); }",
+ forStmt()));
}
TEST(For, ForLoopInternals) {
@@ -1854,7 +2087,7 @@ TEST(For, ForLoopInternals) {
TEST(For, NegativeForLoopInternals) {
EXPECT_TRUE(notMatches("void f(){ for (int i = 0; ; ++i); }",
- forStmt(hasCondition(expression()))));
+ forStmt(hasCondition(expr()))));
EXPECT_TRUE(notMatches("void f() {int i; for (; i < 4; ++i) {} }",
forStmt(hasLoopInit(anything()))));
}
@@ -1865,29 +2098,29 @@ TEST(For, ReportsNoFalsePositives) {
}
TEST(CompoundStatement, HandlesSimpleCases) {
- EXPECT_TRUE(notMatches("void f();", compoundStatement()));
- EXPECT_TRUE(matches("void f() {}", compoundStatement()));
- EXPECT_TRUE(matches("void f() {{}}", compoundStatement()));
+ EXPECT_TRUE(notMatches("void f();", compoundStmt()));
+ EXPECT_TRUE(matches("void f() {}", compoundStmt()));
+ EXPECT_TRUE(matches("void f() {{}}", compoundStmt()));
}
TEST(CompoundStatement, DoesNotMatchEmptyStruct) {
// It's not a compound statement just because there's "{}" in the source
// text. This is an AST search, not grep.
EXPECT_TRUE(notMatches("namespace n { struct S {}; }",
- compoundStatement()));
+ compoundStmt()));
EXPECT_TRUE(matches("namespace n { struct S { void f() {{}} }; }",
- compoundStatement()));
+ compoundStmt()));
}
TEST(HasBody, FindsBodyOfForWhileDoLoops) {
EXPECT_TRUE(matches("void f() { for(;;) {} }",
- forStmt(hasBody(compoundStatement()))));
+ forStmt(hasBody(compoundStmt()))));
EXPECT_TRUE(notMatches("void f() { for(;;); }",
- forStmt(hasBody(compoundStatement()))));
+ forStmt(hasBody(compoundStmt()))));
EXPECT_TRUE(matches("void f() { while(true) {} }",
- whileStmt(hasBody(compoundStatement()))));
+ whileStmt(hasBody(compoundStmt()))));
EXPECT_TRUE(matches("void f() { do {} while(true); }",
- doStmt(hasBody(compoundStatement()))));
+ doStmt(hasBody(compoundStmt()))));
}
TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) {
@@ -1895,67 +2128,67 @@ TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) {
// definition, and the function body itself must be a compound
// statement.
EXPECT_TRUE(matches("void f() { for (;;); }",
- compoundStatement(hasAnySubstatement(forStmt()))));
+ compoundStmt(hasAnySubstatement(forStmt()))));
}
TEST(HasAnySubstatement, IsNotRecursive) {
// It's really "has any immediate substatement".
EXPECT_TRUE(notMatches("void f() { if (true) for (;;); }",
- compoundStatement(hasAnySubstatement(forStmt()))));
+ compoundStmt(hasAnySubstatement(forStmt()))));
}
TEST(HasAnySubstatement, MatchesInNestedCompoundStatements) {
EXPECT_TRUE(matches("void f() { if (true) { for (;;); } }",
- compoundStatement(hasAnySubstatement(forStmt()))));
+ compoundStmt(hasAnySubstatement(forStmt()))));
}
TEST(HasAnySubstatement, FindsSubstatementBetweenOthers) {
EXPECT_TRUE(matches("void f() { 1; 2; 3; for (;;); 4; 5; 6; }",
- compoundStatement(hasAnySubstatement(forStmt()))));
+ compoundStmt(hasAnySubstatement(forStmt()))));
}
TEST(StatementCountIs, FindsNoStatementsInAnEmptyCompoundStatement) {
EXPECT_TRUE(matches("void f() { }",
- compoundStatement(statementCountIs(0))));
+ compoundStmt(statementCountIs(0))));
EXPECT_TRUE(notMatches("void f() {}",
- compoundStatement(statementCountIs(1))));
+ compoundStmt(statementCountIs(1))));
}
TEST(StatementCountIs, AppearsToMatchOnlyOneCount) {
EXPECT_TRUE(matches("void f() { 1; }",
- compoundStatement(statementCountIs(1))));
+ compoundStmt(statementCountIs(1))));
EXPECT_TRUE(notMatches("void f() { 1; }",
- compoundStatement(statementCountIs(0))));
+ compoundStmt(statementCountIs(0))));
EXPECT_TRUE(notMatches("void f() { 1; }",
- compoundStatement(statementCountIs(2))));
+ compoundStmt(statementCountIs(2))));
}
TEST(StatementCountIs, WorksWithMultipleStatements) {
EXPECT_TRUE(matches("void f() { 1; 2; 3; }",
- compoundStatement(statementCountIs(3))));
+ compoundStmt(statementCountIs(3))));
}
TEST(StatementCountIs, WorksWithNestedCompoundStatements) {
EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }",
- compoundStatement(statementCountIs(1))));
+ compoundStmt(statementCountIs(1))));
EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }",
- compoundStatement(statementCountIs(2))));
+ compoundStmt(statementCountIs(2))));
EXPECT_TRUE(notMatches("void f() { { 1; } { 1; 2; 3; 4; } }",
- compoundStatement(statementCountIs(3))));
+ compoundStmt(statementCountIs(3))));
EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }",
- compoundStatement(statementCountIs(4))));
+ compoundStmt(statementCountIs(4))));
}
TEST(Member, WorksInSimplestCase) {
EXPECT_TRUE(matches("struct { int first; } s; int i(s.first);",
- memberExpression(member(hasName("first")))));
+ memberExpr(member(hasName("first")))));
}
TEST(Member, DoesNotMatchTheBaseExpression) {
// Don't pick out the wrong part of the member expression, this should
// be checking the member (name) only.
EXPECT_TRUE(notMatches("struct { int i; } first; int i(first.i);",
- memberExpression(member(hasName("first")))));
+ memberExpr(member(hasName("first")))));
}
TEST(Member, MatchesInMemberFunctionCall) {
@@ -1963,211 +2196,246 @@ TEST(Member, MatchesInMemberFunctionCall) {
" struct { void first() {}; } s;"
" s.first();"
"};",
- memberExpression(member(hasName("first")))));
+ memberExpr(member(hasName("first")))));
+}
+
+TEST(Member, MatchesMember) {
+ EXPECT_TRUE(matches(
+ "struct A { int i; }; void f() { A a; a.i = 2; }",
+ memberExpr(hasDeclaration(fieldDecl(hasType(isInteger()))))));
+ EXPECT_TRUE(notMatches(
+ "struct A { float f; }; void f() { A a; a.f = 2.0f; }",
+ memberExpr(hasDeclaration(fieldDecl(hasType(isInteger()))))));
+}
+
+TEST(Member, MatchesMemberAllocationFunction) {
+ // Fails in C++11 mode
+ EXPECT_TRUE(matchesConditionally(
+ "namespace std { typedef typeof(sizeof(int)) size_t; }"
+ "class X { void *operator new(std::size_t); };",
+ methodDecl(ofClass(hasName("X"))), true, "-std=gnu++98"));
+
+ EXPECT_TRUE(matches("class X { void operator delete(void*); };",
+ methodDecl(ofClass(hasName("X")))));
+
+ // Fails in C++11 mode
+ EXPECT_TRUE(matchesConditionally(
+ "namespace std { typedef typeof(sizeof(int)) size_t; }"
+ "class X { void operator delete[](void*, std::size_t); };",
+ methodDecl(ofClass(hasName("X"))), true, "-std=gnu++98"));
}
TEST(HasObjectExpression, DoesNotMatchMember) {
EXPECT_TRUE(notMatches(
"class X {}; struct Z { X m; }; void f(Z z) { z.m; }",
- memberExpression(hasObjectExpression(hasType(record(hasName("X")))))));
+ memberExpr(hasObjectExpression(hasType(recordDecl(hasName("X")))))));
}
TEST(HasObjectExpression, MatchesBaseOfVariable) {
EXPECT_TRUE(matches(
"struct X { int m; }; void f(X x) { x.m; }",
- memberExpression(hasObjectExpression(hasType(record(hasName("X")))))));
+ memberExpr(hasObjectExpression(hasType(recordDecl(hasName("X")))))));
EXPECT_TRUE(matches(
"struct X { int m; }; void f(X* x) { x->m; }",
- memberExpression(hasObjectExpression(
- hasType(pointsTo(record(hasName("X"))))))));
+ memberExpr(hasObjectExpression(
+ hasType(pointsTo(recordDecl(hasName("X"))))))));
}
TEST(HasObjectExpression,
MatchesObjectExpressionOfImplicitlyFormedMemberExpression) {
EXPECT_TRUE(matches(
"class X {}; struct S { X m; void f() { this->m; } };",
- memberExpression(hasObjectExpression(
- hasType(pointsTo(record(hasName("S"))))))));
+ memberExpr(hasObjectExpression(
+ hasType(pointsTo(recordDecl(hasName("S"))))))));
EXPECT_TRUE(matches(
"class X {}; struct S { X m; void f() { m; } };",
- memberExpression(hasObjectExpression(
- hasType(pointsTo(record(hasName("S"))))))));
+ memberExpr(hasObjectExpression(
+ hasType(pointsTo(recordDecl(hasName("S"))))))));
}
TEST(Field, DoesNotMatchNonFieldMembers) {
- EXPECT_TRUE(notMatches("class X { void m(); };", field(hasName("m"))));
- EXPECT_TRUE(notMatches("class X { class m {}; };", field(hasName("m"))));
- EXPECT_TRUE(notMatches("class X { enum { m }; };", field(hasName("m"))));
- EXPECT_TRUE(notMatches("class X { enum m {}; };", field(hasName("m"))));
+ EXPECT_TRUE(notMatches("class X { void m(); };", fieldDecl(hasName("m"))));
+ EXPECT_TRUE(notMatches("class X { class m {}; };", fieldDecl(hasName("m"))));
+ EXPECT_TRUE(notMatches("class X { enum { m }; };", fieldDecl(hasName("m"))));
+ EXPECT_TRUE(notMatches("class X { enum m {}; };", fieldDecl(hasName("m"))));
}
TEST(Field, MatchesField) {
- EXPECT_TRUE(matches("class X { int m; };", field(hasName("m"))));
+ EXPECT_TRUE(matches("class X { int m; };", fieldDecl(hasName("m"))));
}
TEST(IsConstQualified, MatchesConstInt) {
EXPECT_TRUE(matches("const int i = 42;",
- variable(hasType(isConstQualified()))));
+ varDecl(hasType(isConstQualified()))));
}
TEST(IsConstQualified, MatchesConstPointer) {
EXPECT_TRUE(matches("int i = 42; int* const p(&i);",
- variable(hasType(isConstQualified()))));
+ varDecl(hasType(isConstQualified()))));
}
TEST(IsConstQualified, MatchesThroughTypedef) {
EXPECT_TRUE(matches("typedef const int const_int; const_int i = 42;",
- variable(hasType(isConstQualified()))));
+ varDecl(hasType(isConstQualified()))));
EXPECT_TRUE(matches("typedef int* int_ptr; const int_ptr p(0);",
- variable(hasType(isConstQualified()))));
+ varDecl(hasType(isConstQualified()))));
}
TEST(IsConstQualified, DoesNotMatchInappropriately) {
EXPECT_TRUE(notMatches("typedef int nonconst_int; nonconst_int i = 42;",
- variable(hasType(isConstQualified()))));
+ varDecl(hasType(isConstQualified()))));
EXPECT_TRUE(notMatches("int const* p;",
- variable(hasType(isConstQualified()))));
+ varDecl(hasType(isConstQualified()))));
}
TEST(CastExpression, MatchesExplicitCasts) {
- EXPECT_TRUE(matches("char *p = reinterpret_cast<char *>(&p);",
- expression(castExpr())));
- EXPECT_TRUE(matches("void *p = (void *)(&p);", expression(castExpr())));
- EXPECT_TRUE(matches("char q, *p = const_cast<char *>(&q);",
- expression(castExpr())));
- EXPECT_TRUE(matches("char c = char(0);", expression(castExpr())));
+ EXPECT_TRUE(matches("char *p = reinterpret_cast<char *>(&p);",castExpr()));
+ EXPECT_TRUE(matches("void *p = (void *)(&p);", castExpr()));
+ EXPECT_TRUE(matches("char q, *p = const_cast<char *>(&q);", castExpr()));
+ EXPECT_TRUE(matches("char c = char(0);", castExpr()));
}
TEST(CastExpression, MatchesImplicitCasts) {
// This test creates an implicit cast from int to char.
- EXPECT_TRUE(matches("char c = 0;", expression(castExpr())));
+ EXPECT_TRUE(matches("char c = 0;", castExpr()));
// This test creates an implicit cast from lvalue to rvalue.
- EXPECT_TRUE(matches("char c = 0, d = c;", expression(castExpr())));
+ EXPECT_TRUE(matches("char c = 0, d = c;", castExpr()));
}
TEST(CastExpression, DoesNotMatchNonCasts) {
- EXPECT_TRUE(notMatches("char c = '0';", expression(castExpr())));
- EXPECT_TRUE(notMatches("char c, &q = c;", expression(castExpr())));
- EXPECT_TRUE(notMatches("int i = (0);", expression(castExpr())));
- EXPECT_TRUE(notMatches("int i = 0;", expression(castExpr())));
+ EXPECT_TRUE(notMatches("char c = '0';", castExpr()));
+ EXPECT_TRUE(notMatches("char c, &q = c;", castExpr()));
+ EXPECT_TRUE(notMatches("int i = (0);", castExpr()));
+ EXPECT_TRUE(notMatches("int i = 0;", castExpr()));
}
TEST(ReinterpretCast, MatchesSimpleCase) {
EXPECT_TRUE(matches("char* p = reinterpret_cast<char*>(&p);",
- expression(reinterpretCast())));
+ reinterpretCastExpr()));
}
TEST(ReinterpretCast, DoesNotMatchOtherCasts) {
- EXPECT_TRUE(notMatches("char* p = (char*)(&p);",
- expression(reinterpretCast())));
+ EXPECT_TRUE(notMatches("char* p = (char*)(&p);", reinterpretCastExpr()));
EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);",
- expression(reinterpretCast())));
+ reinterpretCastExpr()));
EXPECT_TRUE(notMatches("void* p = static_cast<void*>(&p);",
- expression(reinterpretCast())));
+ reinterpretCastExpr()));
EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};"
"B b;"
"D* p = dynamic_cast<D*>(&b);",
- expression(reinterpretCast())));
+ reinterpretCastExpr()));
}
TEST(FunctionalCast, MatchesSimpleCase) {
std::string foo_class = "class Foo { public: Foo(char*); };";
EXPECT_TRUE(matches(foo_class + "void r() { Foo f = Foo(\"hello world\"); }",
- expression(functionalCast())));
+ functionalCastExpr()));
}
TEST(FunctionalCast, DoesNotMatchOtherCasts) {
std::string FooClass = "class Foo { public: Foo(char*); };";
EXPECT_TRUE(
notMatches(FooClass + "void r() { Foo f = (Foo) \"hello world\"; }",
- expression(functionalCast())));
+ functionalCastExpr()));
EXPECT_TRUE(
notMatches(FooClass + "void r() { Foo f = \"hello world\"; }",
- expression(functionalCast())));
+ functionalCastExpr()));
}
TEST(DynamicCast, MatchesSimpleCase) {
EXPECT_TRUE(matches("struct B { virtual ~B() {} }; struct D : B {};"
"B b;"
"D* p = dynamic_cast<D*>(&b);",
- expression(dynamicCast())));
+ dynamicCastExpr()));
}
TEST(StaticCast, MatchesSimpleCase) {
EXPECT_TRUE(matches("void* p(static_cast<void*>(&p));",
- expression(staticCast())));
+ staticCastExpr()));
}
TEST(StaticCast, DoesNotMatchOtherCasts) {
- EXPECT_TRUE(notMatches("char* p = (char*)(&p);",
- expression(staticCast())));
+ EXPECT_TRUE(notMatches("char* p = (char*)(&p);", staticCastExpr()));
EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);",
- expression(staticCast())));
+ staticCastExpr()));
EXPECT_TRUE(notMatches("void* p = reinterpret_cast<char*>(&p);",
- expression(staticCast())));
+ staticCastExpr()));
EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};"
"B b;"
"D* p = dynamic_cast<D*>(&b);",
- expression(staticCast())));
+ staticCastExpr()));
+}
+
+TEST(CStyleCast, MatchesSimpleCase) {
+ EXPECT_TRUE(matches("int i = (int) 2.2f;", cStyleCastExpr()));
+}
+
+TEST(CStyleCast, DoesNotMatchOtherCasts) {
+ EXPECT_TRUE(notMatches("char* p = static_cast<char*>(0);"
+ "char q, *r = const_cast<char*>(&q);"
+ "void* s = reinterpret_cast<char*>(&s);"
+ "struct B { virtual ~B() {} }; struct D : B {};"
+ "B b;"
+ "D* t = dynamic_cast<D*>(&b);",
+ cStyleCastExpr()));
}
TEST(HasDestinationType, MatchesSimpleCase) {
EXPECT_TRUE(matches("char* p = static_cast<char*>(0);",
- expression(
- staticCast(hasDestinationType(
- pointsTo(TypeMatcher(anything())))))));
+ staticCastExpr(hasDestinationType(
+ pointsTo(TypeMatcher(anything()))))));
}
TEST(HasImplicitDestinationType, MatchesSimpleCase) {
// This test creates an implicit const cast.
EXPECT_TRUE(matches("int x; const int i = x;",
- expression(implicitCast(
- hasImplicitDestinationType(isInteger())))));
+ implicitCastExpr(
+ hasImplicitDestinationType(isInteger()))));
// This test creates an implicit array-to-pointer cast.
EXPECT_TRUE(matches("int arr[3]; int *p = arr;",
- expression(implicitCast(hasImplicitDestinationType(
- pointsTo(TypeMatcher(anything())))))));
+ implicitCastExpr(hasImplicitDestinationType(
+ pointsTo(TypeMatcher(anything()))))));
}
TEST(HasImplicitDestinationType, DoesNotMatchIncorrectly) {
// This test creates an implicit cast from int to char.
EXPECT_TRUE(notMatches("char c = 0;",
- expression(implicitCast(hasImplicitDestinationType(
- unless(anything()))))));
+ implicitCastExpr(hasImplicitDestinationType(
+ unless(anything())))));
// This test creates an implicit array-to-pointer cast.
EXPECT_TRUE(notMatches("int arr[3]; int *p = arr;",
- expression(implicitCast(hasImplicitDestinationType(
- unless(anything()))))));
+ implicitCastExpr(hasImplicitDestinationType(
+ unless(anything())))));
}
TEST(ImplicitCast, MatchesSimpleCase) {
// This test creates an implicit const cast.
EXPECT_TRUE(matches("int x = 0; const int y = x;",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
// This test creates an implicit cast from int to char.
EXPECT_TRUE(matches("char c = 0;",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
// This test creates an implicit array-to-pointer cast.
EXPECT_TRUE(matches("int arr[6]; int *p = arr;",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
}
TEST(ImplicitCast, DoesNotMatchIncorrectly) {
- // This test verifies that implicitCast() matches exactly when implicit casts
+ // This test verifies that implicitCastExpr() matches exactly when implicit casts
// are present, and that it ignores explicit and paren casts.
// These two test cases have no casts.
EXPECT_TRUE(notMatches("int x = 0;",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
EXPECT_TRUE(notMatches("int x = 0, &y = x;",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
EXPECT_TRUE(notMatches("int x = 0; double d = (double) x;",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
EXPECT_TRUE(notMatches("const int *p; int *q = const_cast<int *>(p);",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
EXPECT_TRUE(notMatches("int x = (0);",
- variable(hasInitializer(implicitCast()))));
+ varDecl(hasInitializer(implicitCastExpr()))));
}
TEST(IgnoringImpCasts, MatchesImpCasts) {
@@ -2175,11 +2443,11 @@ TEST(IgnoringImpCasts, MatchesImpCasts) {
// present and its inner matcher alone does not match.
// Note that this test creates an implicit const cast.
EXPECT_TRUE(matches("int x = 0; const int y = x;",
- variable(hasInitializer(ignoringImpCasts(
- declarationReference(to(variable(hasName("x")))))))));
+ varDecl(hasInitializer(ignoringImpCasts(
+ declRefExpr(to(varDecl(hasName("x")))))))));
// This test creates an implict cast from int to char.
EXPECT_TRUE(matches("char x = 0;",
- variable(hasInitializer(ignoringImpCasts(
+ varDecl(hasInitializer(ignoringImpCasts(
integerLiteral(equals(0)))))));
}
@@ -2188,82 +2456,82 @@ TEST(IgnoringImpCasts, DoesNotMatchIncorrectly) {
// matcher does not match.
// Note that the first test creates an implicit const cast.
EXPECT_TRUE(notMatches("int x; const int y = x;",
- variable(hasInitializer(ignoringImpCasts(
+ varDecl(hasInitializer(ignoringImpCasts(
unless(anything()))))));
EXPECT_TRUE(notMatches("int x; int y = x;",
- variable(hasInitializer(ignoringImpCasts(
+ varDecl(hasInitializer(ignoringImpCasts(
unless(anything()))))));
// These tests verify that ignoringImplictCasts does not look through explicit
// casts or parentheses.
EXPECT_TRUE(notMatches("char* p = static_cast<char*>(0);",
- variable(hasInitializer(ignoringImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringImpCasts(
+ integerLiteral())))));
EXPECT_TRUE(notMatches("int i = (0);",
- variable(hasInitializer(ignoringImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringImpCasts(
+ integerLiteral())))));
EXPECT_TRUE(notMatches("float i = (float)0;",
- variable(hasInitializer(ignoringImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringImpCasts(
+ integerLiteral())))));
EXPECT_TRUE(notMatches("float i = float(0);",
- variable(hasInitializer(ignoringImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringImpCasts(
+ integerLiteral())))));
}
TEST(IgnoringImpCasts, MatchesWithoutImpCasts) {
// This test verifies that expressions that do not have implicit casts
// still match the inner matcher.
EXPECT_TRUE(matches("int x = 0; int &y = x;",
- variable(hasInitializer(ignoringImpCasts(
- declarationReference(to(variable(hasName("x")))))))));
+ varDecl(hasInitializer(ignoringImpCasts(
+ declRefExpr(to(varDecl(hasName("x")))))))));
}
TEST(IgnoringParenCasts, MatchesParenCasts) {
// This test checks that ignoringParenCasts matches when parentheses and/or
// casts are present and its inner matcher alone does not match.
EXPECT_TRUE(matches("int x = (0);",
- variable(hasInitializer(ignoringParenCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenCasts(
+ integerLiteral(equals(0)))))));
EXPECT_TRUE(matches("int x = (((((0)))));",
- variable(hasInitializer(ignoringParenCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenCasts(
+ integerLiteral(equals(0)))))));
// This test creates an implict cast from int to char in addition to the
// parentheses.
EXPECT_TRUE(matches("char x = (0);",
- variable(hasInitializer(ignoringParenCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenCasts(
+ integerLiteral(equals(0)))))));
EXPECT_TRUE(matches("char x = (char)0;",
- variable(hasInitializer(ignoringParenCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenCasts(
+ integerLiteral(equals(0)))))));
EXPECT_TRUE(matches("char* p = static_cast<char*>(0);",
- variable(hasInitializer(ignoringParenCasts(
+ varDecl(hasInitializer(ignoringParenCasts(
integerLiteral(equals(0)))))));
}
TEST(IgnoringParenCasts, MatchesWithoutParenCasts) {
// This test verifies that expressions that do not have any casts still match.
EXPECT_TRUE(matches("int x = 0;",
- variable(hasInitializer(ignoringParenCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenCasts(
+ integerLiteral(equals(0)))))));
}
TEST(IgnoringParenCasts, DoesNotMatchIncorrectly) {
// These tests verify that ignoringImpCasts does not match if the inner
// matcher does not match.
EXPECT_TRUE(notMatches("int x = ((0));",
- variable(hasInitializer(ignoringParenCasts(
+ varDecl(hasInitializer(ignoringParenCasts(
unless(anything()))))));
// This test creates an implicit cast from int to char in addition to the
// parentheses.
EXPECT_TRUE(notMatches("char x = ((0));",
- variable(hasInitializer(ignoringParenCasts(
+ varDecl(hasInitializer(ignoringParenCasts(
unless(anything()))))));
EXPECT_TRUE(notMatches("char *x = static_cast<char *>((0));",
- variable(hasInitializer(ignoringParenCasts(
+ varDecl(hasInitializer(ignoringParenCasts(
unless(anything()))))));
}
@@ -2273,23 +2541,23 @@ TEST(IgnoringParenAndImpCasts, MatchesParenImpCasts) {
// does not match.
// Note that this test creates an implicit const cast.
EXPECT_TRUE(matches("int x = 0; const int y = x;",
- variable(hasInitializer(ignoringParenImpCasts(
- declarationReference(to(variable(hasName("x")))))))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ declRefExpr(to(varDecl(hasName("x")))))))));
// This test creates an implicit cast from int to char.
EXPECT_TRUE(matches("const char x = (0);",
- variable(hasInitializer(ignoringParenImpCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ integerLiteral(equals(0)))))));
}
TEST(IgnoringParenAndImpCasts, MatchesWithoutParenImpCasts) {
// This test verifies that expressions that do not have parentheses or
// implicit casts still match.
EXPECT_TRUE(matches("int x = 0; int &y = x;",
- variable(hasInitializer(ignoringParenImpCasts(
- declarationReference(to(variable(hasName("x")))))))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ declRefExpr(to(varDecl(hasName("x")))))))));
EXPECT_TRUE(matches("int x = 0;",
- variable(hasInitializer(ignoringParenImpCasts(
- integerLiteral(equals(0)))))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ integerLiteral(equals(0)))))));
}
TEST(IgnoringParenAndImpCasts, DoesNotMatchIncorrectly) {
@@ -2297,56 +2565,56 @@ TEST(IgnoringParenAndImpCasts, DoesNotMatchIncorrectly) {
// the inner matcher does not match.
// This test creates an implicit cast.
EXPECT_TRUE(notMatches("char c = ((3));",
- variable(hasInitializer(ignoringParenImpCasts(
+ varDecl(hasInitializer(ignoringParenImpCasts(
unless(anything()))))));
// These tests verify that ignoringParenAndImplictCasts does not look
// through explicit casts.
EXPECT_TRUE(notMatches("float y = (float(0));",
- variable(hasInitializer(ignoringParenImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ integerLiteral())))));
EXPECT_TRUE(notMatches("float y = (float)0;",
- variable(hasInitializer(ignoringParenImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ integerLiteral())))));
EXPECT_TRUE(notMatches("char* p = static_cast<char*>(0);",
- variable(hasInitializer(ignoringParenImpCasts(
- integerLiteral())))));
+ varDecl(hasInitializer(ignoringParenImpCasts(
+ integerLiteral())))));
}
TEST(HasSourceExpression, MatchesImplicitCasts) {
EXPECT_TRUE(matches("class string {}; class URL { public: URL(string s); };"
"void r() {string a_string; URL url = a_string; }",
- expression(implicitCast(
- hasSourceExpression(constructorCall())))));
+ implicitCastExpr(
+ hasSourceExpression(constructExpr()))));
}
TEST(HasSourceExpression, MatchesExplicitCasts) {
EXPECT_TRUE(matches("float x = static_cast<float>(42);",
- expression(explicitCast(
- hasSourceExpression(hasDescendant(
- expression(integerLiteral())))))));
+ explicitCastExpr(
+ hasSourceExpression(hasDescendant(
+ expr(integerLiteral()))))));
}
TEST(Statement, DoesNotMatchDeclarations) {
- EXPECT_TRUE(notMatches("class X {};", statement()));
+ EXPECT_TRUE(notMatches("class X {};", stmt()));
}
TEST(Statement, MatchesCompoundStatments) {
- EXPECT_TRUE(matches("void x() {}", statement()));
+ EXPECT_TRUE(matches("void x() {}", stmt()));
}
TEST(DeclarationStatement, DoesNotMatchCompoundStatements) {
- EXPECT_TRUE(notMatches("void x() {}", declarationStatement()));
+ EXPECT_TRUE(notMatches("void x() {}", declStmt()));
}
TEST(DeclarationStatement, MatchesVariableDeclarationStatements) {
- EXPECT_TRUE(matches("void x() { int a; }", declarationStatement()));
+ EXPECT_TRUE(matches("void x() { int a; }", declStmt()));
}
TEST(InitListExpression, MatchesInitListExpression) {
EXPECT_TRUE(matches("int a[] = { 1, 2 };",
initListExpr(hasType(asString("int [2]")))));
EXPECT_TRUE(matches("struct B { int x, y; }; B b = { 5, 6 };",
- initListExpr(hasType(record(hasName("B"))))));
+ initListExpr(hasType(recordDecl(hasName("B"))))));
}
TEST(UsingDeclaration, MatchesUsingDeclarations) {
@@ -2362,24 +2630,24 @@ TEST(UsingDeclaration, MatchesShadowUsingDelcarations) {
TEST(UsingDeclaration, MatchesSpecificTarget) {
EXPECT_TRUE(matches("namespace f { int a; void b(); } using f::b;",
usingDecl(hasAnyUsingShadowDecl(
- hasTargetDecl(function())))));
+ hasTargetDecl(functionDecl())))));
EXPECT_TRUE(notMatches("namespace f { int a; void b(); } using f::a;",
usingDecl(hasAnyUsingShadowDecl(
- hasTargetDecl(function())))));
+ hasTargetDecl(functionDecl())))));
}
TEST(UsingDeclaration, ThroughUsingDeclaration) {
EXPECT_TRUE(matches(
"namespace a { void f(); } using a::f; void g() { f(); }",
- declarationReference(throughUsingDecl(anything()))));
+ declRefExpr(throughUsingDecl(anything()))));
EXPECT_TRUE(notMatches(
"namespace a { void f(); } using a::f; void g() { a::f(); }",
- declarationReference(throughUsingDecl(anything()))));
+ declRefExpr(throughUsingDecl(anything()))));
}
TEST(SingleDecl, IsSingleDecl) {
StatementMatcher SingleDeclStmt =
- declarationStatement(hasSingleDecl(variable(hasInitializer(anything()))));
+ declStmt(hasSingleDecl(varDecl(hasInitializer(anything()))));
EXPECT_TRUE(matches("void f() {int a = 4;}", SingleDeclStmt));
EXPECT_TRUE(notMatches("void f() {int a;}", SingleDeclStmt));
EXPECT_TRUE(notMatches("void f() {int a = 4, b = 3;}",
@@ -2387,28 +2655,26 @@ TEST(SingleDecl, IsSingleDecl) {
}
TEST(DeclStmt, ContainsDeclaration) {
- DeclarationMatcher MatchesInit = variable(hasInitializer(anything()));
+ DeclarationMatcher MatchesInit = varDecl(hasInitializer(anything()));
EXPECT_TRUE(matches("void f() {int a = 4;}",
- declarationStatement(containsDeclaration(0,
- MatchesInit))));
+ declStmt(containsDeclaration(0, MatchesInit))));
EXPECT_TRUE(matches("void f() {int a = 4, b = 3;}",
- declarationStatement(containsDeclaration(0, MatchesInit),
- containsDeclaration(1,
- MatchesInit))));
+ declStmt(containsDeclaration(0, MatchesInit),
+ containsDeclaration(1, MatchesInit))));
unsigned WrongIndex = 42;
EXPECT_TRUE(notMatches("void f() {int a = 4, b = 3;}",
- declarationStatement(containsDeclaration(WrongIndex,
+ declStmt(containsDeclaration(WrongIndex,
MatchesInit))));
}
TEST(DeclCount, DeclCountIsCorrect) {
EXPECT_TRUE(matches("void f() {int i,j;}",
- declarationStatement(declCountIs(2))));
+ declStmt(declCountIs(2))));
EXPECT_TRUE(notMatches("void f() {int i,j; int k;}",
- declarationStatement(declCountIs(3))));
+ declStmt(declCountIs(3))));
EXPECT_TRUE(notMatches("void f() {int i,j, k, l;}",
- declarationStatement(declCountIs(3))));
+ declStmt(declCountIs(3))));
}
TEST(While, MatchesWhileLoops) {
@@ -2433,61 +2699,91 @@ TEST(SwitchCase, MatchesCase) {
EXPECT_TRUE(notMatches("void x() { switch(42) {} }", switchCase()));
}
+TEST(SwitchCase, MatchesSwitch) {
+ EXPECT_TRUE(matches("void x() { switch(42) { case 42:; } }", switchStmt()));
+ EXPECT_TRUE(matches("void x() { switch(42) { default:; } }", switchStmt()));
+ EXPECT_TRUE(matches("void x() { switch(42) default:; }", switchStmt()));
+ EXPECT_TRUE(notMatches("void x() {}", switchStmt()));
+}
+
+TEST(ExceptionHandling, SimpleCases) {
+ EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", catchStmt()));
+ EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", tryStmt()));
+ EXPECT_TRUE(notMatches("void foo() try { } catch(int X) { }", throwExpr()));
+ EXPECT_TRUE(matches("void foo() try { throw; } catch(int X) { }",
+ throwExpr()));
+ EXPECT_TRUE(matches("void foo() try { throw 5;} catch(int X) { }",
+ throwExpr()));
+}
+
TEST(HasConditionVariableStatement, DoesNotMatchCondition) {
EXPECT_TRUE(notMatches(
"void x() { if(true) {} }",
- ifStmt(hasConditionVariableStatement(declarationStatement()))));
+ ifStmt(hasConditionVariableStatement(declStmt()))));
EXPECT_TRUE(notMatches(
"void x() { int x; if((x = 42)) {} }",
- ifStmt(hasConditionVariableStatement(declarationStatement()))));
+ ifStmt(hasConditionVariableStatement(declStmt()))));
}
TEST(HasConditionVariableStatement, MatchesConditionVariables) {
EXPECT_TRUE(matches(
"void x() { if(int* a = 0) {} }",
- ifStmt(hasConditionVariableStatement(declarationStatement()))));
+ ifStmt(hasConditionVariableStatement(declStmt()))));
}
TEST(ForEach, BindsOneNode) {
EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; };",
- record(hasName("C"), forEach(field(hasName("x")).bind("x"))),
- new VerifyIdIsBoundToDecl<FieldDecl>("x", 1)));
+ recordDecl(hasName("C"), forEach(fieldDecl(hasName("x")).bind("x"))),
+ new VerifyIdIsBoundTo<FieldDecl>("x", 1)));
}
TEST(ForEach, BindsMultipleNodes) {
EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; int y; int z; };",
- record(hasName("C"), forEach(field().bind("f"))),
- new VerifyIdIsBoundToDecl<FieldDecl>("f", 3)));
+ recordDecl(hasName("C"), forEach(fieldDecl().bind("f"))),
+ new VerifyIdIsBoundTo<FieldDecl>("f", 3)));
}
TEST(ForEach, BindsRecursiveCombinations) {
EXPECT_TRUE(matchAndVerifyResultTrue(
"class C { class D { int x; int y; }; class E { int y; int z; }; };",
- record(hasName("C"), forEach(record(forEach(field().bind("f"))))),
- new VerifyIdIsBoundToDecl<FieldDecl>("f", 4)));
+ recordDecl(hasName("C"),
+ forEach(recordDecl(forEach(fieldDecl().bind("f"))))),
+ new VerifyIdIsBoundTo<FieldDecl>("f", 4)));
}
TEST(ForEachDescendant, BindsOneNode) {
EXPECT_TRUE(matchAndVerifyResultTrue("class C { class D { int x; }; };",
- record(hasName("C"), forEachDescendant(field(hasName("x")).bind("x"))),
- new VerifyIdIsBoundToDecl<FieldDecl>("x", 1)));
+ recordDecl(hasName("C"),
+ forEachDescendant(fieldDecl(hasName("x")).bind("x"))),
+ new VerifyIdIsBoundTo<FieldDecl>("x", 1)));
}
TEST(ForEachDescendant, BindsMultipleNodes) {
EXPECT_TRUE(matchAndVerifyResultTrue(
"class C { class D { int x; int y; }; "
" class E { class F { int y; int z; }; }; };",
- record(hasName("C"), forEachDescendant(field().bind("f"))),
- new VerifyIdIsBoundToDecl<FieldDecl>("f", 4)));
+ recordDecl(hasName("C"), forEachDescendant(fieldDecl().bind("f"))),
+ new VerifyIdIsBoundTo<FieldDecl>("f", 4)));
}
TEST(ForEachDescendant, BindsRecursiveCombinations) {
EXPECT_TRUE(matchAndVerifyResultTrue(
"class C { class D { "
" class E { class F { class G { int y; int z; }; }; }; }; };",
- record(hasName("C"), forEachDescendant(record(
- forEachDescendant(field().bind("f"))))),
- new VerifyIdIsBoundToDecl<FieldDecl>("f", 8)));
+ recordDecl(hasName("C"), forEachDescendant(recordDecl(
+ forEachDescendant(fieldDecl().bind("f"))))),
+ new VerifyIdIsBoundTo<FieldDecl>("f", 8)));
+}
+
+TEST(ForEachDescendant, BindsCorrectNodes) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class C { void f(); int i; };",
+ recordDecl(hasName("C"), forEachDescendant(decl().bind("decl"))),
+ new VerifyIdIsBoundTo<FieldDecl>("decl", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class C { void f() {} int i; };",
+ recordDecl(hasName("C"), forEachDescendant(decl().bind("decl"))),
+ new VerifyIdIsBoundTo<FunctionDecl>("decl", 1)));
}
@@ -2497,18 +2793,18 @@ TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) {
EXPECT_TRUE(matches(
"template <typename T> class X {}; class A {}; X<A> x;",
- record(hasName("::X"), isTemplateInstantiation())));
+ recordDecl(hasName("::X"), isTemplateInstantiation())));
EXPECT_TRUE(matches(
"template <typename T> class X { T t; }; class A {}; X<A> x;",
- record(isTemplateInstantiation(), hasDescendant(
- field(hasType(record(hasName("A"))))))));
+ recordDecl(isTemplateInstantiation(), hasDescendant(
+ fieldDecl(hasType(recordDecl(hasName("A"))))))));
}
TEST(IsTemplateInstantiation, MatchesImplicitFunctionTemplateInstantiation) {
EXPECT_TRUE(matches(
"template <typename T> void f(T t) {} class A {}; void g() { f(A()); }",
- function(hasParameter(0, hasType(record(hasName("A")))),
+ functionDecl(hasParameter(0, hasType(recordDecl(hasName("A")))),
isTemplateInstantiation())));
}
@@ -2516,8 +2812,8 @@ TEST(IsTemplateInstantiation, MatchesExplicitClassTemplateInstantiation) {
EXPECT_TRUE(matches(
"template <typename T> class X { T t; }; class A {};"
"template class X<A>;",
- record(isTemplateInstantiation(), hasDescendant(
- field(hasType(record(hasName("A"))))))));
+ recordDecl(isTemplateInstantiation(), hasDescendant(
+ fieldDecl(hasType(recordDecl(hasName("A"))))))));
}
TEST(IsTemplateInstantiation,
@@ -2525,7 +2821,7 @@ TEST(IsTemplateInstantiation,
EXPECT_TRUE(matches(
"template <typename T> class X {};"
"template <typename T> class X<T*> {}; class A {}; X<A*> x;",
- record(hasName("::X"), isTemplateInstantiation())));
+ recordDecl(hasName("::X"), isTemplateInstantiation())));
}
TEST(IsTemplateInstantiation,
@@ -2536,7 +2832,7 @@ TEST(IsTemplateInstantiation,
" template <typename U> class Y { U u; };"
" Y<A> y;"
"};",
- record(hasName("::X::Y"), isTemplateInstantiation())));
+ recordDecl(hasName("::X::Y"), isTemplateInstantiation())));
}
TEST(IsTemplateInstantiation, DoesNotMatchInstantiationsInsideOfInstantiation) {
@@ -2549,20 +2845,557 @@ TEST(IsTemplateInstantiation, DoesNotMatchInstantiationsInsideOfInstantiation) {
" template <typename U> class Y { U u; };"
" Y<T> y;"
"}; X<A> x;",
- record(hasName("::X<A>::Y"), unless(isTemplateInstantiation()))));
+ recordDecl(hasName("::X<A>::Y"), unless(isTemplateInstantiation()))));
}
TEST(IsTemplateInstantiation, DoesNotMatchExplicitClassTemplateSpecialization) {
EXPECT_TRUE(notMatches(
"template <typename T> class X {}; class A {};"
"template <> class X<A> {}; X<A> x;",
- record(hasName("::X"), isTemplateInstantiation())));
+ recordDecl(hasName("::X"), isTemplateInstantiation())));
}
TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) {
EXPECT_TRUE(notMatches(
"class A {}; class Y { A a; };",
- record(isTemplateInstantiation())));
+ recordDecl(isTemplateInstantiation())));
+}
+
+TEST(IsExplicitTemplateSpecialization,
+ DoesNotMatchPrimaryTemplate) {
+ EXPECT_TRUE(notMatches(
+ "template <typename T> class X {};",
+ recordDecl(isExplicitTemplateSpecialization())));
+ EXPECT_TRUE(notMatches(
+ "template <typename T> void f(T t);",
+ functionDecl(isExplicitTemplateSpecialization())));
+}
+
+TEST(IsExplicitTemplateSpecialization,
+ DoesNotMatchExplicitTemplateInstantiations) {
+ EXPECT_TRUE(notMatches(
+ "template <typename T> class X {};"
+ "template class X<int>; extern template class X<long>;",
+ recordDecl(isExplicitTemplateSpecialization())));
+ EXPECT_TRUE(notMatches(
+ "template <typename T> void f(T t) {}"
+ "template void f(int t); extern template void f(long t);",
+ functionDecl(isExplicitTemplateSpecialization())));
+}
+
+TEST(IsExplicitTemplateSpecialization,
+ DoesNotMatchImplicitTemplateInstantiations) {
+ EXPECT_TRUE(notMatches(
+ "template <typename T> class X {}; X<int> x;",
+ recordDecl(isExplicitTemplateSpecialization())));
+ EXPECT_TRUE(notMatches(
+ "template <typename T> void f(T t); void g() { f(10); }",
+ functionDecl(isExplicitTemplateSpecialization())));
+}
+
+TEST(IsExplicitTemplateSpecialization,
+ MatchesExplicitTemplateSpecializations) {
+ EXPECT_TRUE(matches(
+ "template <typename T> class X {};"
+ "template<> class X<int> {};",
+ recordDecl(isExplicitTemplateSpecialization())));
+ EXPECT_TRUE(matches(
+ "template <typename T> void f(T t) {}"
+ "template<> void f(int t) {}",
+ functionDecl(isExplicitTemplateSpecialization())));
+}
+
+TEST(HasAncenstor, MatchesDeclarationAncestors) {
+ EXPECT_TRUE(matches(
+ "class A { class B { class C {}; }; };",
+ recordDecl(hasName("C"), hasAncestor(recordDecl(hasName("A"))))));
+}
+
+TEST(HasAncenstor, FailsIfNoAncestorMatches) {
+ EXPECT_TRUE(notMatches(
+ "class A { class B { class C {}; }; };",
+ recordDecl(hasName("C"), hasAncestor(recordDecl(hasName("X"))))));
+}
+
+TEST(HasAncestor, MatchesDeclarationsThatGetVisitedLater) {
+ EXPECT_TRUE(matches(
+ "class A { class B { void f() { C c; } class C {}; }; };",
+ varDecl(hasName("c"), hasType(recordDecl(hasName("C"),
+ hasAncestor(recordDecl(hasName("A"))))))));
+}
+
+TEST(HasAncenstor, MatchesStatementAncestors) {
+ EXPECT_TRUE(matches(
+ "void f() { if (true) { while (false) { 42; } } }",
+ integerLiteral(equals(42), hasAncestor(ifStmt()))));
+}
+
+TEST(HasAncestor, DrillsThroughDifferentHierarchies) {
+ EXPECT_TRUE(matches(
+ "void f() { if (true) { int x = 42; } }",
+ integerLiteral(equals(42), hasAncestor(functionDecl(hasName("f"))))));
+}
+
+TEST(HasAncestor, BindsRecursiveCombinations) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class C { class D { class E { class F { int y; }; }; }; };",
+ fieldDecl(hasAncestor(recordDecl(hasAncestor(recordDecl().bind("r"))))),
+ new VerifyIdIsBoundTo<CXXRecordDecl>("r", 1)));
+}
+
+TEST(HasAncestor, BindsCombinationsWithHasDescendant) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class C { class D { class E { class F { int y; }; }; }; };",
+ fieldDecl(hasAncestor(
+ decl(
+ hasDescendant(recordDecl(isDefinition(),
+ hasAncestor(recordDecl())))
+ ).bind("d")
+ )),
+ new VerifyIdIsBoundTo<CXXRecordDecl>("d", "E")));
+}
+
+TEST(HasAncestor, MatchesInTemplateInstantiations) {
+ EXPECT_TRUE(matches(
+ "template <typename T> struct A { struct B { struct C { T t; }; }; }; "
+ "A<int>::B::C a;",
+ fieldDecl(hasType(asString("int")),
+ hasAncestor(recordDecl(hasName("A"))))));
+}
+
+TEST(HasAncestor, MatchesInImplicitCode) {
+ EXPECT_TRUE(matches(
+ "struct X {}; struct A { A() {} X x; };",
+ constructorDecl(
+ hasAnyConstructorInitializer(withInitializer(expr(
+ hasAncestor(recordDecl(hasName("A")))))))));
+}
+
+TEST(HasParent, MatchesOnlyParent) {
+ EXPECT_TRUE(matches(
+ "void f() { if (true) { int x = 42; } }",
+ compoundStmt(hasParent(ifStmt()))));
+ EXPECT_TRUE(notMatches(
+ "void f() { for (;;) { int x = 42; } }",
+ compoundStmt(hasParent(ifStmt()))));
+ EXPECT_TRUE(notMatches(
+ "void f() { if (true) for (;;) { int x = 42; } }",
+ compoundStmt(hasParent(ifStmt()))));
+}
+
+TEST(TypeMatching, MatchesTypes) {
+ EXPECT_TRUE(matches("struct S {};", qualType().bind("loc")));
+}
+
+TEST(TypeMatching, MatchesArrayTypes) {
+ EXPECT_TRUE(matches("int a[] = {2,3};", arrayType()));
+ EXPECT_TRUE(matches("int a[42];", arrayType()));
+ EXPECT_TRUE(matches("void f(int b) { int a[b]; }", arrayType()));
+
+ EXPECT_TRUE(notMatches("struct A {}; A a[7];",
+ arrayType(hasElementType(builtinType()))));
+
+ EXPECT_TRUE(matches(
+ "int const a[] = { 2, 3 };",
+ qualType(arrayType(hasElementType(builtinType())))));
+ EXPECT_TRUE(matches(
+ "int const a[] = { 2, 3 };",
+ qualType(isConstQualified(), arrayType(hasElementType(builtinType())))));
+ EXPECT_TRUE(matches(
+ "typedef const int T; T x[] = { 1, 2 };",
+ qualType(isConstQualified(), arrayType())));
+
+ EXPECT_TRUE(notMatches(
+ "int a[] = { 2, 3 };",
+ qualType(isConstQualified(), arrayType(hasElementType(builtinType())))));
+ EXPECT_TRUE(notMatches(
+ "int a[] = { 2, 3 };",
+ qualType(arrayType(hasElementType(isConstQualified(), builtinType())))));
+ EXPECT_TRUE(notMatches(
+ "int const a[] = { 2, 3 };",
+ qualType(arrayType(hasElementType(builtinType())),
+ unless(isConstQualified()))));
+
+ EXPECT_TRUE(matches("int a[2];",
+ constantArrayType(hasElementType(builtinType()))));
+ EXPECT_TRUE(matches("const int a = 0;", qualType(isInteger())));
+}
+
+TEST(TypeMatching, MatchesComplexTypes) {
+ EXPECT_TRUE(matches("_Complex float f;", complexType()));
+ EXPECT_TRUE(matches(
+ "_Complex float f;",
+ complexType(hasElementType(builtinType()))));
+ EXPECT_TRUE(notMatches(
+ "_Complex float f;",
+ complexType(hasElementType(isInteger()))));
+}
+
+TEST(TypeMatching, MatchesConstantArrayTypes) {
+ EXPECT_TRUE(matches("int a[2];", constantArrayType()));
+ EXPECT_TRUE(notMatches(
+ "void f() { int a[] = { 2, 3 }; int b[a[0]]; }",
+ constantArrayType(hasElementType(builtinType()))));
+
+ EXPECT_TRUE(matches("int a[42];", constantArrayType(hasSize(42))));
+ EXPECT_TRUE(matches("int b[2*21];", constantArrayType(hasSize(42))));
+ EXPECT_TRUE(notMatches("int c[41], d[43];", constantArrayType(hasSize(42))));
+}
+
+TEST(TypeMatching, MatchesDependentSizedArrayTypes) {
+ EXPECT_TRUE(matches(
+ "template <typename T, int Size> class array { T data[Size]; };",
+ dependentSizedArrayType()));
+ EXPECT_TRUE(notMatches(
+ "int a[42]; int b[] = { 2, 3 }; void f() { int c[b[0]]; }",
+ dependentSizedArrayType()));
+}
+
+TEST(TypeMatching, MatchesIncompleteArrayType) {
+ EXPECT_TRUE(matches("int a[] = { 2, 3 };", incompleteArrayType()));
+ EXPECT_TRUE(matches("void f(int a[]) {}", incompleteArrayType()));
+
+ EXPECT_TRUE(notMatches("int a[42]; void f() { int b[a[0]]; }",
+ incompleteArrayType()));
+}
+
+TEST(TypeMatching, MatchesVariableArrayType) {
+ EXPECT_TRUE(matches("void f(int b) { int a[b]; }", variableArrayType()));
+ EXPECT_TRUE(notMatches("int a[] = {2, 3}; int b[42];", variableArrayType()));
+
+ EXPECT_TRUE(matches(
+ "void f(int b) { int a[b]; }",
+ variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to(
+ varDecl(hasName("b")))))))));
+}
+
+TEST(TypeMatching, MatchesAtomicTypes) {
+ EXPECT_TRUE(matches("_Atomic(int) i;", atomicType()));
+
+ EXPECT_TRUE(matches("_Atomic(int) i;",
+ atomicType(hasValueType(isInteger()))));
+ EXPECT_TRUE(notMatches("_Atomic(float) f;",
+ atomicType(hasValueType(isInteger()))));
+}
+
+TEST(TypeMatching, MatchesAutoTypes) {
+ EXPECT_TRUE(matches("auto i = 2;", autoType()));
+ EXPECT_TRUE(matches("int v[] = { 2, 3 }; void f() { for (int i : v) {} }",
+ autoType()));
+
+ EXPECT_TRUE(matches("auto a = 1;",
+ autoType(hasDeducedType(isInteger()))));
+ EXPECT_TRUE(notMatches("auto b = 2.0;",
+ autoType(hasDeducedType(isInteger()))));
+}
+
+TEST(TypeMatching, MatchesFunctionTypes) {
+ EXPECT_TRUE(matches("int (*f)(int);", functionType()));
+ EXPECT_TRUE(matches("void f(int i) {}", functionType()));
+}
+
+TEST(TypeMatching, PointerTypes) {
+ // FIXME: Reactive when these tests can be more specific (not matching
+ // implicit code on certain platforms), likely when we have hasDescendant for
+ // Types/TypeLocs.
+ //EXPECT_TRUE(matchAndVerifyResultTrue(
+ // "int* a;",
+ // pointerTypeLoc(pointeeLoc(typeLoc().bind("loc"))),
+ // new VerifyIdIsBoundTo<TypeLoc>("loc", 1)));
+ //EXPECT_TRUE(matchAndVerifyResultTrue(
+ // "int* a;",
+ // pointerTypeLoc().bind("loc"),
+ // new VerifyIdIsBoundTo<TypeLoc>("loc", 1)));
+ EXPECT_TRUE(matches(
+ "int** a;",
+ pointerTypeLoc(pointeeLoc(loc(qualType())))));
+ EXPECT_TRUE(matches(
+ "int** a;",
+ loc(pointerType(pointee(pointerType())))));
+ EXPECT_TRUE(matches(
+ "int* b; int* * const a = &b;",
+ loc(qualType(isConstQualified(), pointerType()))));
+
+ std::string Fragment = "struct A { int i; }; int A::* ptr = &A::i;";
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(blockPointerType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("ptr"),
+ hasType(memberPointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(pointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(referenceType()))));
+
+ Fragment = "int *ptr;";
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(blockPointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(memberPointerType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("ptr"),
+ hasType(pointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(referenceType()))));
+
+ Fragment = "int a; int &ref = a;";
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(blockPointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(memberPointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(pointerType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
+ hasType(referenceType()))));
+}
+
+TEST(TypeMatching, PointeeTypes) {
+ EXPECT_TRUE(matches("int b; int &a = b;",
+ referenceType(pointee(builtinType()))));
+ EXPECT_TRUE(matches("int *a;", pointerType(pointee(builtinType()))));
+
+ EXPECT_TRUE(matches("int *a;",
+ pointerTypeLoc(pointeeLoc(loc(builtinType())))));
+
+ EXPECT_TRUE(matches(
+ "int const *A;",
+ pointerType(pointee(isConstQualified(), builtinType()))));
+ EXPECT_TRUE(notMatches(
+ "int *A;",
+ pointerType(pointee(isConstQualified(), builtinType()))));
+}
+
+TEST(TypeMatching, MatchesPointersToConstTypes) {
+ EXPECT_TRUE(matches("int b; int * const a = &b;",
+ loc(pointerType())));
+ EXPECT_TRUE(matches("int b; int * const a = &b;",
+ pointerTypeLoc()));
+ EXPECT_TRUE(matches(
+ "int b; const int * a = &b;",
+ pointerTypeLoc(pointeeLoc(builtinTypeLoc()))));
+ EXPECT_TRUE(matches(
+ "int b; const int * a = &b;",
+ pointerType(pointee(builtinType()))));
+}
+
+TEST(TypeMatching, MatchesTypedefTypes) {
+ EXPECT_TRUE(matches("typedef int X; X a;", varDecl(hasName("a"),
+ hasType(typedefType()))));
+
+ EXPECT_TRUE(matches("typedef int X; X a;",
+ varDecl(hasName("a"),
+ hasType(typedefType(hasDecl(decl()))))));
+}
+
+TEST(NNS, MatchesNestedNameSpecifiers) {
+ EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;",
+ nestedNameSpecifier()));
+ EXPECT_TRUE(matches("template <typename T> class A { typename T::B b; };",
+ nestedNameSpecifier()));
+ EXPECT_TRUE(matches("struct A { void f(); }; void A::f() {}",
+ nestedNameSpecifier()));
+
+ EXPECT_TRUE(matches(
+ "struct A { static void f() {} }; void g() { A::f(); }",
+ nestedNameSpecifier()));
+ EXPECT_TRUE(notMatches(
+ "struct A { static void f() {} }; void g(A* a) { a->f(); }",
+ nestedNameSpecifier()));
+}
+
+TEST(NullStatement, SimpleCases) {
+ EXPECT_TRUE(matches("void f() {int i;;}", nullStmt()));
+ EXPECT_TRUE(notMatches("void f() {int i;}", nullStmt()));
+}
+
+TEST(NNS, MatchesTypes) {
+ NestedNameSpecifierMatcher Matcher = nestedNameSpecifier(
+ specifiesType(hasDeclaration(recordDecl(hasName("A")))));
+ EXPECT_TRUE(matches("struct A { struct B {}; }; A::B b;", Matcher));
+ EXPECT_TRUE(matches("struct A { struct B { struct C {}; }; }; A::B::C c;",
+ Matcher));
+ EXPECT_TRUE(notMatches("namespace A { struct B {}; } A::B b;", Matcher));
+}
+
+TEST(NNS, MatchesNamespaceDecls) {
+ NestedNameSpecifierMatcher Matcher = nestedNameSpecifier(
+ specifiesNamespace(hasName("ns")));
+ EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;", Matcher));
+ EXPECT_TRUE(notMatches("namespace xx { struct A {}; } xx::A a;", Matcher));
+ EXPECT_TRUE(notMatches("struct ns { struct A {}; }; ns::A a;", Matcher));
+}
+
+TEST(NNS, BindsNestedNameSpecifiers) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "namespace ns { struct E { struct B {}; }; } ns::E::B b;",
+ nestedNameSpecifier(specifiesType(asString("struct ns::E"))).bind("nns"),
+ new VerifyIdIsBoundTo<NestedNameSpecifier>("nns", "ns::struct E::")));
+}
+
+TEST(NNS, BindsNestedNameSpecifierLocs) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "namespace ns { struct B {}; } ns::B b;",
+ loc(nestedNameSpecifier()).bind("loc"),
+ new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("loc", 1)));
+}
+
+TEST(NNS, MatchesNestedNameSpecifierPrefixes) {
+ EXPECT_TRUE(matches(
+ "struct A { struct B { struct C {}; }; }; A::B::C c;",
+ nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A"))))));
+ EXPECT_TRUE(matches(
+ "struct A { struct B { struct C {}; }; }; A::B::C c;",
+ nestedNameSpecifierLoc(hasPrefix(
+ specifiesTypeLoc(loc(qualType(asString("struct A"))))))));
+}
+
+TEST(NNS, DescendantsOfNestedNameSpecifiers) {
+ std::string Fragment =
+ "namespace a { struct A { struct B { struct C {}; }; }; };"
+ "void f() { a::A::B::C c; }";
+ EXPECT_TRUE(matches(
+ Fragment,
+ nestedNameSpecifier(specifiesType(asString("struct a::A::B")),
+ hasDescendant(nestedNameSpecifier(
+ specifiesNamespace(hasName("a")))))));
+ EXPECT_TRUE(notMatches(
+ Fragment,
+ nestedNameSpecifier(specifiesType(asString("struct a::A::B")),
+ has(nestedNameSpecifier(
+ specifiesNamespace(hasName("a")))))));
+ EXPECT_TRUE(matches(
+ Fragment,
+ nestedNameSpecifier(specifiesType(asString("struct a::A")),
+ has(nestedNameSpecifier(
+ specifiesNamespace(hasName("a")))))));
+
+ // Not really useful because a NestedNameSpecifier can af at most one child,
+ // but to complete the interface.
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Fragment,
+ nestedNameSpecifier(specifiesType(asString("struct a::A::B")),
+ forEach(nestedNameSpecifier().bind("x"))),
+ new VerifyIdIsBoundTo<NestedNameSpecifier>("x", 1)));
+}
+
+TEST(NNS, NestedNameSpecifiersAsDescendants) {
+ std::string Fragment =
+ "namespace a { struct A { struct B { struct C {}; }; }; };"
+ "void f() { a::A::B::C c; }";
+ EXPECT_TRUE(matches(
+ Fragment,
+ decl(hasDescendant(nestedNameSpecifier(specifiesType(
+ asString("struct a::A")))))));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Fragment,
+ functionDecl(hasName("f"),
+ forEachDescendant(nestedNameSpecifier().bind("x"))),
+ // Nested names: a, a::A and a::A::B.
+ new VerifyIdIsBoundTo<NestedNameSpecifier>("x", 3)));
+}
+
+TEST(NNSLoc, DescendantsOfNestedNameSpecifierLocs) {
+ std::string Fragment =
+ "namespace a { struct A { struct B { struct C {}; }; }; };"
+ "void f() { a::A::B::C c; }";
+ EXPECT_TRUE(matches(
+ Fragment,
+ nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))),
+ hasDescendant(loc(nestedNameSpecifier(
+ specifiesNamespace(hasName("a"))))))));
+ EXPECT_TRUE(notMatches(
+ Fragment,
+ nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))),
+ has(loc(nestedNameSpecifier(
+ specifiesNamespace(hasName("a"))))))));
+ EXPECT_TRUE(matches(
+ Fragment,
+ nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A"))),
+ has(loc(nestedNameSpecifier(
+ specifiesNamespace(hasName("a"))))))));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Fragment,
+ nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))),
+ forEach(nestedNameSpecifierLoc().bind("x"))),
+ new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("x", 1)));
+}
+
+TEST(NNSLoc, NestedNameSpecifierLocsAsDescendants) {
+ std::string Fragment =
+ "namespace a { struct A { struct B { struct C {}; }; }; };"
+ "void f() { a::A::B::C c; }";
+ EXPECT_TRUE(matches(
+ Fragment,
+ decl(hasDescendant(loc(nestedNameSpecifier(specifiesType(
+ asString("struct a::A"))))))));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Fragment,
+ functionDecl(hasName("f"),
+ forEachDescendant(nestedNameSpecifierLoc().bind("x"))),
+ // Nested names: a, a::A and a::A::B.
+ new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("x", 3)));
+}
+
+template <typename T>
+class VerifyRecursiveMatch : public BoundNodesCallback {
+public:
+ explicit VerifyRecursiveMatch(StringRef Id,
+ const internal::Matcher<T> &InnerMatcher)
+ : Id(Id), InnerMatcher(InnerMatcher) {}
+
+ virtual bool run(const BoundNodes *Nodes) {
+ return false;
+ }
+
+ virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
+ const T *Node = Nodes->getNodeAs<T>(Id);
+ bool Found = false;
+ MatchFinder Finder;
+ Finder.addMatcher(InnerMatcher, new VerifyMatch(0, &Found));
+ Finder.findAll(*Node, *Context);
+ return Found;
+ }
+private:
+ std::string Id;
+ internal::Matcher<T> InnerMatcher;
+};
+
+TEST(MatchFinder, CanMatchDeclarationsRecursively) {
+ EXPECT_TRUE(matchAndVerifyResultTrue("class X { class Y {}; };",
+ recordDecl(hasName("::X")).bind("X"),
+ new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Y")))));
+ EXPECT_TRUE(matchAndVerifyResultFalse("class X { class Y {}; };",
+ recordDecl(hasName("::X")).bind("X"),
+ new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Z")))));
+}
+
+TEST(MatchFinder, CanMatchStatementsRecursively) {
+ EXPECT_TRUE(matchAndVerifyResultTrue("void f() { if (1) { for (;;) { } } }",
+ ifStmt().bind("if"),
+ new VerifyRecursiveMatch<clang::Stmt>("if", forStmt())));
+ EXPECT_TRUE(matchAndVerifyResultFalse("void f() { if (1) { for (;;) { } } }",
+ ifStmt().bind("if"),
+ new VerifyRecursiveMatch<clang::Stmt>("if", declStmt())));
+}
+
+class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
+public:
+ VerifyStartOfTranslationUnit() : Called(false) {}
+ virtual void run(const MatchFinder::MatchResult &Result) {
+ EXPECT_TRUE(Called);
+ }
+ virtual void onStartOfTranslationUnit() {
+ Called = true;
+ }
+ bool Called;
+};
+
+TEST(MatchFinder, InterceptsStartOfTranslationUnit) {
+ MatchFinder Finder;
+ VerifyStartOfTranslationUnit VerifyCallback;
+ Finder.addMatcher(decl(), &VerifyCallback);
+ OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+ ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
+ EXPECT_TRUE(VerifyCallback.Called);
}
} // end namespace ast_matchers
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index 64816f5..3b23ada 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -18,13 +18,14 @@ namespace clang {
namespace ast_matchers {
using clang::tooling::newFrontendActionFactory;
-using clang::tooling::runToolOnCode;
+using clang::tooling::runToolOnCodeWithArgs;
using clang::tooling::FrontendActionFactory;
class BoundNodesCallback {
public:
virtual ~BoundNodesCallback() {}
virtual bool run(const BoundNodes *BoundNodes) = 0;
+ virtual bool run(const BoundNodes *BoundNodes, ASTContext *Context) = 0;
};
// If 'FindResultVerifier' is not NULL, sets *Verified to the result of
@@ -37,7 +38,7 @@ public:
virtual void run(const MatchFinder::MatchResult &Result) {
if (FindResultReviewer != NULL) {
- *Verified = FindResultReviewer->run(&Result.Nodes);
+ *Verified |= FindResultReviewer->run(&Result.Nodes, Result.Context);
} else {
*Verified = true;
}
@@ -51,12 +52,15 @@ private:
template <typename T>
testing::AssertionResult matchesConditionally(const std::string &Code,
const T &AMatcher,
- bool ExpectMatch) {
+ bool ExpectMatch,
+ llvm::StringRef CompileArg) {
bool Found = false;
MatchFinder Finder;
Finder.addMatcher(AMatcher, new VerifyMatch(0, &Found));
OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
- if (!runToolOnCode(Factory->create(), Code)) {
+ // Some tests use typeof, which is a gnu extension.
+ std::vector<std::string> Args(1, CompileArg);
+ if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
}
if (!Found && ExpectMatch) {
@@ -71,13 +75,13 @@ testing::AssertionResult matchesConditionally(const std::string &Code,
template <typename T>
testing::AssertionResult matches(const std::string &Code, const T &AMatcher) {
- return matchesConditionally(Code, AMatcher, true);
+ return matchesConditionally(Code, AMatcher, true, "-std=c++11");
}
template <typename T>
testing::AssertionResult notMatches(const std::string &Code,
const T &AMatcher) {
- return matchesConditionally(Code, AMatcher, false);
+ return matchesConditionally(Code, AMatcher, false, "-std=c++11");
}
template <typename T>
@@ -91,7 +95,9 @@ matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
Finder.addMatcher(
AMatcher, new VerifyMatch(FindResultVerifier, &VerifiedResult));
OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
- if (!runToolOnCode(Factory->create(), Code)) {
+ // Some tests use typeof, which is a gnu extension.
+ std::vector<std::string> Args(1, "-std=gnu++98");
+ if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
}
if (!VerifiedResult && ExpectResult) {
diff --git a/unittests/ASTMatchers/Makefile b/unittests/ASTMatchers/Makefile
index d3e4aa37..9ca1006 100644
--- a/unittests/ASTMatchers/Makefile
+++ b/unittests/ASTMatchers/Makefile
@@ -13,7 +13,8 @@ TESTNAME = ASTMatchers
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
- clangRewrite.a clangParse.a clangSema.a clangAnalysis.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/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp
index de3b723..6f404b5 100644
--- a/unittests/Basic/SourceManagerTest.cpp
+++ b/unittests/Basic/SourceManagerTest.cpp
@@ -10,12 +10,15 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
@@ -32,10 +35,11 @@ protected:
SourceManagerTest()
: FileMgr(FileMgrOpts),
DiagID(new DiagnosticIDs()),
- Diags(DiagID, new IgnoringDiagConsumer()),
- SourceMgr(Diags, FileMgr) {
- TargetOpts.Triple = "x86_64-apple-darwin11.1.0";
- Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
+ Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr),
+ TargetOpts(new TargetOptions) {
+ TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
+ Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
FileSystemOptions FileMgrOpts;
@@ -44,7 +48,7 @@ protected:
DiagnosticsEngine Diags;
SourceManager SourceMgr;
LangOptions LangOpts;
- TargetOptions TargetOpts;
+ IntrusiveRefCntPtr<TargetOptions> TargetOpts;
IntrusiveRefCntPtr<TargetInfo> Target;
};
@@ -64,9 +68,9 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
- Preprocessor PP(Diags, LangOpts,
- Target.getPtr(),
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ &*Target);
+ Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/ 0,
/*OwnsHeaderSearch =*/false,
@@ -179,9 +183,9 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
SourceMgr.overrideFileContents(headerFile, headerBuf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
- Preprocessor PP(Diags, LangOpts,
- Target.getPtr(),
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ &*Target);
+ Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/ 0,
/*OwnsHeaderSearch =*/false,
@@ -276,9 +280,9 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
SourceMgr.overrideFileContents(headerFile, headerBuf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
- Preprocessor PP(Diags, LangOpts,
- Target.getPtr(),
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ &*Target);
+ Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/ 0,
/*OwnsHeaderSearch =*/false,
diff --git a/unittests/Frontend/Makefile b/unittests/Frontend/Makefile
index bfc3494..4b6f875 100644
--- a/unittests/Frontend/Makefile
+++ b/unittests/Frontend/Makefile
@@ -14,7 +14,8 @@ LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
- clangARCMigrate.a clangRewrite.a clangEdit.a \
+ clangARCMigrate.a clangRewriteCore.a \
+ clangRewriteFrontend.a clangEdit.a \
clangAnalysis.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Lex/CMakeLists.txt b/unittests/Lex/CMakeLists.txt
index 10c9361..03c8cd5 100644
--- a/unittests/Lex/CMakeLists.txt
+++ b/unittests/Lex/CMakeLists.txt
@@ -1,6 +1,7 @@
add_clang_unittest(LexTests
LexerTest.cpp
PreprocessingRecordTest.cpp
+ PPCallbacksTest.cpp
)
target_link_libraries(LexTests
diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp
index e43ad86..e95cd02 100644
--- a/unittests/Lex/LexerTest.cpp
+++ b/unittests/Lex/LexerTest.cpp
@@ -10,12 +10,15 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/Config/config.h"
#include "gtest/gtest.h"
@@ -31,10 +34,12 @@ protected:
LexerTest()
: FileMgr(FileMgrOpts),
DiagID(new DiagnosticIDs()),
- Diags(DiagID, new IgnoringDiagConsumer()),
- SourceMgr(Diags, FileMgr) {
- TargetOpts.Triple = "x86_64-apple-darwin11.1.0";
- Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
+ Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr),
+ TargetOpts(new TargetOptions)
+ {
+ TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
+ Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
FileSystemOptions FileMgrOpts;
@@ -43,7 +48,7 @@ protected:
DiagnosticsEngine Diags;
SourceManager SourceMgr;
LangOptions LangOpts;
- TargetOptions TargetOpts;
+ IntrusiveRefCntPtr<TargetOptions> TargetOpts;
IntrusiveRefCntPtr<TargetInfo> Target;
};
@@ -69,9 +74,9 @@ TEST_F(LexerTest, LexAPI) {
(void)SourceMgr.createMainFileIDForMemBuffer(buf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, Target.getPtr());
- Preprocessor PP(Diags, LangOpts,
- Target.getPtr(),
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ Target.getPtr());
+ Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/ 0,
/*OwnsHeaderSearch =*/false,
diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp
new file mode 100644
index 0000000..6e7efa9
--- /dev/null
+++ b/unittests/Lex/PPCallbacksTest.cpp
@@ -0,0 +1,246 @@
+//===- unittests/Lex/PPCallbacksTest.cpp - PPCallbacks tests ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/ModuleLoader.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/PathV2.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+using namespace clang;
+
+namespace {
+
+// Stub out module loading.
+class VoidModuleLoader : public ModuleLoader {
+ virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
+ return 0;
+ }
+};
+
+// Stub to collect data from InclusionDirective callbacks.
+class InclusionDirectiveCallbacks : public PPCallbacks {
+public:
+ void InclusionDirective(SourceLocation HashLoc,
+ const Token &IncludeTok,
+ StringRef FileName,
+ bool IsAngled,
+ CharSourceRange FilenameRange,
+ const FileEntry *File,
+ StringRef SearchPath,
+ StringRef RelativePath,
+ const Module *Imported) {
+ this->HashLoc = HashLoc;
+ this->IncludeTok = IncludeTok;
+ this->FileName = FileName.str();
+ this->IsAngled = IsAngled;
+ this->FilenameRange = FilenameRange;
+ this->File = File;
+ this->SearchPath = SearchPath.str();
+ this->RelativePath = RelativePath.str();
+ this->Imported = Imported;
+ }
+
+ SourceLocation HashLoc;
+ Token IncludeTok;
+ SmallString<16> FileName;
+ bool IsAngled;
+ CharSourceRange FilenameRange;
+ const FileEntry* File;
+ SmallString<16> SearchPath;
+ SmallString<16> RelativePath;
+ const Module* Imported;
+};
+
+// PPCallbacks test fixture.
+class PPCallbacksTest : public ::testing::Test {
+protected:
+ PPCallbacksTest()
+ : FileMgr(FileMgrOpts),
+ DiagID(new DiagnosticIDs()),
+ DiagOpts(new DiagnosticOptions()),
+ Diags(DiagID, DiagOpts.getPtr(), new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr) {
+ TargetOpts = new TargetOptions();
+ TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
+ Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
+ }
+
+ FileSystemOptions FileMgrOpts;
+ FileManager FileMgr;
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+ DiagnosticsEngine Diags;
+ SourceManager SourceMgr;
+ LangOptions LangOpts;
+ IntrusiveRefCntPtr<TargetOptions> TargetOpts;
+ IntrusiveRefCntPtr<TargetInfo> Target;
+
+ // Register a header path as a known file and add its location
+ // to search path.
+ void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath,
+ bool IsSystemHeader) {
+ // Tell FileMgr about header.
+ FileMgr.getVirtualFile(HeaderPath, 0, 0);
+
+ // Add header's parent path to search path.
+ StringRef SearchPath = path::parent_path(HeaderPath);
+ const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
+ DirectoryLookup DL(DE, SrcMgr::C_User, true, false);
+ HeaderInfo.AddSearchPath(DL, IsSystemHeader);
+ }
+
+ // Get the raw source string of the range.
+ StringRef GetSourceString(CharSourceRange Range) {
+ const char* B = SourceMgr.getCharacterData(Range.getBegin());
+ const char* E = SourceMgr.getCharacterData(Range.getEnd());
+
+ return StringRef(B, E - B);
+ }
+
+ // Run lexer over SourceText and collect FilenameRange from
+ // the InclusionDirective callback.
+ CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText,
+ const char* HeaderPath, bool SystemHeader) {
+ MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(SourceText);
+ (void)SourceMgr.createMainFileIDForMemBuffer(Buf);
+
+ VoidModuleLoader ModLoader;
+
+ IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
+ HeaderSearch HeaderInfo(HSOpts, FileMgr, Diags, LangOpts, Target.getPtr());
+ AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
+
+ IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions();
+ Preprocessor PP(PPOpts, Diags, LangOpts,
+ Target.getPtr(),
+ SourceMgr, HeaderInfo, ModLoader,
+ /*IILookup =*/ 0,
+ /*OwnsHeaderSearch =*/false,
+ /*DelayInitialization =*/ false);
+ InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
+ PP.addPPCallbacks(Callbacks); // Takes ownership.
+
+ // Lex source text.
+ PP.EnterMainSourceFile();
+
+ while (true) {
+ Token Tok;
+ PP.Lex(Tok);
+ if (Tok.is(tok::eof))
+ break;
+ }
+
+ // Callbacks have been executed at this point -- return filename range.
+ return Callbacks->FilenameRange;
+ }
+};
+
+TEST_F(PPCallbacksTest, QuotedFilename) {
+ const char* Source =
+ "#include \"quoted.h\"\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
+
+ ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, AngledFilename) {
+ const char* Source =
+ "#include <angled.h>\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/angled.h", true);
+
+ ASSERT_EQ("<angled.h>", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, QuotedInMacro) {
+ const char* Source =
+ "#define MACRO_QUOTED \"quoted.h\"\n"
+ "#include MACRO_QUOTED\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
+
+ ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, AngledInMacro) {
+ const char* Source =
+ "#define MACRO_ANGLED <angled.h>\n"
+ "#include MACRO_ANGLED\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/angled.h", true);
+
+ ASSERT_EQ("<angled.h>", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, StringizedMacroArgument) {
+ const char* Source =
+ "#define MACRO_STRINGIZED(x) #x\n"
+ "#include MACRO_STRINGIZED(quoted.h)\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
+
+ ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
+ const char* Source =
+ "#define MACRO_ANGLED <angled.h>\n"
+ "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
+ "#include MACRO_CONCAT(MACRO, ANGLED)\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/angled.h", false);
+
+ ASSERT_EQ("<angled.h>", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, TrigraphFilename) {
+ const char* Source =
+ "#include \"tri\?\?-graph.h\"\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
+
+ ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
+}
+
+TEST_F(PPCallbacksTest, TrigraphInMacro) {
+ const char* Source =
+ "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
+ "#include MACRO_TRIGRAPH\n";
+
+ CharSourceRange Range =
+ InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
+
+ ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
+}
+
+} // anonoymous namespace
diff --git a/unittests/Lex/PreprocessingRecordTest.cpp b/unittests/Lex/PreprocessingRecordTest.cpp
index 5b5d933..815081a 100644
--- a/unittests/Lex/PreprocessingRecordTest.cpp
+++ b/unittests/Lex/PreprocessingRecordTest.cpp
@@ -10,12 +10,15 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "llvm/Config/config.h"
@@ -32,10 +35,12 @@ protected:
PreprocessingRecordTest()
: FileMgr(FileMgrOpts),
DiagID(new DiagnosticIDs()),
- Diags(DiagID, new IgnoringDiagConsumer()),
- SourceMgr(Diags, FileMgr) {
- TargetOpts.Triple = "x86_64-apple-darwin11.1.0";
- Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
+ Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr),
+ TargetOpts(new TargetOptions)
+ {
+ TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
+ Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
}
FileSystemOptions FileMgrOpts;
@@ -44,7 +49,7 @@ protected:
DiagnosticsEngine Diags;
SourceManager SourceMgr;
LangOptions LangOpts;
- TargetOptions TargetOpts;
+ IntrusiveRefCntPtr<TargetOptions> TargetOpts;
IntrusiveRefCntPtr<TargetInfo> Target;
};
@@ -80,9 +85,9 @@ TEST_F(PreprocessingRecordTest, PPRecAPI) {
SourceMgr.createMainFileIDForMemBuffer(buf);
VoidModuleLoader ModLoader;
- HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, Target.getPtr());
- Preprocessor PP(Diags, LangOpts,
- Target.getPtr(),
+ HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
+ Target.getPtr());
+ Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts,Target.getPtr(),
SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/ 0,
/*OwnsHeaderSearch =*/false,
diff --git a/unittests/Tooling/CMakeLists.txt b/unittests/Tooling/CMakeLists.txt
index 4eaf339..bd7317f 100644
--- a/unittests/Tooling/CMakeLists.txt
+++ b/unittests/Tooling/CMakeLists.txt
@@ -18,5 +18,5 @@ add_clang_unittest(ToolingTests
target_link_libraries(ToolingTests
clangAST
clangTooling
- clangRewrite
+ clangRewriteCore
)
diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp
index 591d48d..5ed4240 100644
--- a/unittests/Tooling/CompilationDatabaseTest.cpp
+++ b/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -11,8 +11,10 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Frontend/FrontendAction.h"
-#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/FileMatchTrie.h"
+#include "clang/Tooling/JSONCompilationDatabase.h"
#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/PathV2.h"
#include "gtest/gtest.h"
namespace clang {
@@ -55,13 +57,16 @@ TEST(JSONCompilationDatabase, GetAllFiles) {
getAllFiles("[]", ErrorMessage)) << ErrorMessage;
std::vector<std::string> expected_files;
- expected_files.push_back("file1");
- expected_files.push_back("file2");
+ SmallString<16> PathStorage;
+ llvm::sys::path::native("//net/dir/file1", PathStorage);
+ expected_files.push_back(PathStorage.str());
+ llvm::sys::path::native("//net/dir/file2", PathStorage);
+ expected_files.push_back(PathStorage.str());
EXPECT_EQ(expected_files, getAllFiles(
- "[{\"directory\":\"dir\","
+ "[{\"directory\":\"//net/dir\","
"\"command\":\"command\","
"\"file\":\"file1\"},"
- " {\"directory\":\"dir\","
+ " {\"directory\":\"//net/dir\","
"\"command\":\"command\","
"\"file\":\"file2\"}]",
ErrorMessage)) << ErrorMessage;
@@ -81,6 +86,82 @@ static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName,
return Commands[0];
}
+struct FakeComparator : public PathComparator {
+ virtual ~FakeComparator() {}
+ virtual bool equivalent(StringRef FileA, StringRef FileB) const {
+ return FileA.equals_lower(FileB);
+ }
+};
+
+class FileMatchTrieTest : public ::testing::Test {
+protected:
+ FileMatchTrieTest() : Trie(new FakeComparator()) {}
+
+ StringRef find(StringRef Path) {
+ llvm::raw_string_ostream ES(Error);
+ return Trie.findEquivalent(Path, ES);
+ }
+
+ FileMatchTrie Trie;
+ std::string Error;
+};
+
+TEST_F(FileMatchTrieTest, InsertingRelativePath) {
+ Trie.insert("//net/path/file.cc");
+ Trie.insert("file.cc");
+ EXPECT_EQ("//net/path/file.cc", find("//net/path/file.cc"));
+}
+
+TEST_F(FileMatchTrieTest, MatchingRelativePath) {
+ EXPECT_EQ("", find("file.cc"));
+}
+
+TEST_F(FileMatchTrieTest, ReturnsBestResults) {
+ Trie.insert("//net/d/c/b.cc");
+ Trie.insert("//net/d/b/b.cc");
+ EXPECT_EQ("//net/d/b/b.cc", find("//net/d/b/b.cc"));
+}
+
+TEST_F(FileMatchTrieTest, HandlesSymlinks) {
+ Trie.insert("//net/AA/file.cc");
+ EXPECT_EQ("//net/AA/file.cc", find("//net/aa/file.cc"));
+}
+
+TEST_F(FileMatchTrieTest, ReportsSymlinkAmbiguity) {
+ Trie.insert("//net/Aa/file.cc");
+ Trie.insert("//net/aA/file.cc");
+ EXPECT_TRUE(find("//net/aa/file.cc").empty());
+ EXPECT_EQ("Path is ambiguous", Error);
+}
+
+TEST_F(FileMatchTrieTest, LongerMatchingSuffixPreferred) {
+ Trie.insert("//net/src/Aa/file.cc");
+ Trie.insert("//net/src/aA/file.cc");
+ Trie.insert("//net/SRC/aa/file.cc");
+ EXPECT_EQ("//net/SRC/aa/file.cc", find("//net/src/aa/file.cc"));
+}
+
+TEST_F(FileMatchTrieTest, EmptyTrie) {
+ EXPECT_TRUE(find("//net/some/path").empty());
+}
+
+TEST_F(FileMatchTrieTest, NoResult) {
+ Trie.insert("//net/somepath/otherfile.cc");
+ Trie.insert("//net/otherpath/somefile.cc");
+ EXPECT_EQ("", find("//net/somepath/somefile.cc"));
+}
+
+TEST_F(FileMatchTrieTest, RootElementDifferent) {
+ Trie.insert("//net/path/file.cc");
+ Trie.insert("//net/otherpath/file.cc");
+ EXPECT_EQ("//net/path/file.cc", find("//net/path/file.cc"));
+}
+
+TEST_F(FileMatchTrieTest, CannotResolveRelativePath) {
+ EXPECT_EQ("", find("relative-path.cc"));
+ EXPECT_EQ("Cannot resolve relative paths", Error);
+}
+
TEST(findCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
std::string ErrorMessage;
CompileCommand NotFound = findCompileArgsInJsonDatabase(
@@ -90,9 +171,9 @@ TEST(findCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
}
TEST(findCompileArgsInJsonDatabase, ReadsSingleEntry) {
- StringRef Directory("/some/directory");
- StringRef FileName("/path/to/a-file.cpp");
- StringRef Command("/path/to/compiler and some arguments");
+ StringRef Directory("//net/some/directory");
+ StringRef FileName("//net/path/to/a-file.cpp");
+ StringRef Command("//net/path/to/compiler and some arguments");
std::string ErrorMessage;
CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
FileName,
@@ -102,7 +183,8 @@ TEST(findCompileArgsInJsonDatabase, ReadsSingleEntry) {
ErrorMessage);
EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
ASSERT_EQ(4u, FoundCommand.CommandLine.size()) << ErrorMessage;
- EXPECT_EQ("/path/to/compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
+ EXPECT_EQ("//net/path/to/compiler",
+ FoundCommand.CommandLine[0]) << ErrorMessage;
EXPECT_EQ("and", FoundCommand.CommandLine[1]) << ErrorMessage;
EXPECT_EQ("some", FoundCommand.CommandLine[2]) << ErrorMessage;
EXPECT_EQ("arguments", FoundCommand.CommandLine[3]) << ErrorMessage;
@@ -118,9 +200,9 @@ TEST(findCompileArgsInJsonDatabase, ReadsSingleEntry) {
}
TEST(findCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) {
- StringRef Directory("/some/directory");
- StringRef FileName("/path/to/a-file.cpp");
- StringRef Command("\\\"/path to compiler\\\" \\\"and an argument\\\"");
+ StringRef Directory("//net/some/directory");
+ StringRef FileName("//net/path/to/a-file.cpp");
+ StringRef Command("\\\"//net/path to compiler\\\" \\\"and an argument\\\"");
std::string ErrorMessage;
CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
FileName,
@@ -129,13 +211,14 @@ TEST(findCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) {
"\"file\":\"" + FileName + "\"}]").str(),
ErrorMessage);
ASSERT_EQ(2u, FoundCommand.CommandLine.size());
- EXPECT_EQ("/path to compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
+ EXPECT_EQ("//net/path to compiler",
+ FoundCommand.CommandLine[0]) << ErrorMessage;
EXPECT_EQ("and an argument", FoundCommand.CommandLine[1]) << ErrorMessage;
}
TEST(findCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
- StringRef Directory("/some directory / with spaces");
- StringRef FileName("/path/to/a-file.cpp");
+ StringRef Directory("//net/some directory / with spaces");
+ StringRef FileName("//net/path/to/a-file.cpp");
StringRef Command("a command");
std::string ErrorMessage;
CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
@@ -148,7 +231,7 @@ TEST(findCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
}
TEST(findCompileArgsInJsonDatabase, FindsEntry) {
- StringRef Directory("directory");
+ StringRef Directory("//net/directory");
StringRef FileName("file");
StringRef Command("command");
std::string JsonDatabase = "[";
@@ -162,19 +245,19 @@ TEST(findCompileArgsInJsonDatabase, FindsEntry) {
JsonDatabase += "]";
std::string ErrorMessage;
CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
- "file4", JsonDatabase, ErrorMessage);
- EXPECT_EQ("directory4", FoundCommand.Directory) << ErrorMessage;
+ "//net/directory4/file4", JsonDatabase, ErrorMessage);
+ EXPECT_EQ("//net/directory4", FoundCommand.Directory) << ErrorMessage;
ASSERT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage;
EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
}
static std::vector<std::string> unescapeJsonCommandLine(StringRef Command) {
std::string JsonDatabase =
- ("[{\"directory\":\"\", \"file\":\"test\", \"command\": \"" +
+ ("[{\"directory\":\"//net/root\", \"file\":\"test\", \"command\": \"" +
Command + "\"}]").str();
std::string ErrorMessage;
CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
- "test", JsonDatabase, ErrorMessage);
+ "//net/root/test", JsonDatabase, ErrorMessage);
EXPECT_TRUE(ErrorMessage.empty()) << ErrorMessage;
return FoundCommand.CommandLine;
}
diff --git a/unittests/Tooling/Makefile b/unittests/Tooling/Makefile
index 5d2224d..5ed99fc 100644
--- a/unittests/Tooling/Makefile
+++ b/unittests/Tooling/Makefile
@@ -12,7 +12,8 @@ TESTNAME = Tooling
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
- clangParse.a clangRewrite.a clangSema.a clangAnalysis.a clangEdit.a \
+ clangParse.a clangRewriteCore.a clangRewriteFrontend.a \
+ clangSema.a clangAnalysis.a clangEdit.a \
clangAST.a clangASTMatchers.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp
index 4b53906..a68a869 100644
--- a/unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -385,6 +385,66 @@ TEST(RecursiveASTVisitor, VisitsImplicitCopyConstructors) {
"int main() { Simple s; Simple t(s); }\n"));
}
+/// \brief A visitor that optionally includes implicit code and matches
+/// CXXConstructExpr.
+///
+/// The name recorded for the match is the name of the class whose constructor
+/// is invoked by the CXXConstructExpr, not the name of the class whose
+/// constructor the CXXConstructExpr is contained in.
+class ConstructExprVisitor
+ : public ExpectedLocationVisitor<ConstructExprVisitor> {
+public:
+ ConstructExprVisitor() : ShouldVisitImplicitCode(false) {}
+
+ bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
+
+ void setShouldVisitImplicitCode(bool NewValue) {
+ ShouldVisitImplicitCode = NewValue;
+ }
+
+ bool VisitCXXConstructExpr(CXXConstructExpr* Expr) {
+ if (const CXXConstructorDecl* Ctor = Expr->getConstructor()) {
+ if (const CXXRecordDecl* Class = Ctor->getParent()) {
+ Match(Class->getName(), Expr->getLocation());
+ }
+ }
+ return true;
+ }
+
+ private:
+ bool ShouldVisitImplicitCode;
+};
+
+TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) {
+ ConstructExprVisitor Visitor;
+ Visitor.setShouldVisitImplicitCode(true);
+ Visitor.ExpectMatch("WithCtor", 2, 8);
+ // Simple has a constructor that implicitly initializes 'w'. Test
+ // that a visitor that visits implicit code visits that initialization.
+ // Note: Clang lazily instantiates implicit declarations, so we need
+ // to use them in order to force them to appear in the AST.
+ EXPECT_TRUE(Visitor.runOver(
+ "struct WithCtor { WithCtor(); }; \n"
+ "struct Simple { WithCtor w; }; \n"
+ "int main() { Simple s; }\n"));
+}
+
+// The same as CanVisitImplicitMemberInitializations, but checking that the
+// visits are omitted when the visitor does not include implicit code.
+TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) {
+ ConstructExprVisitor Visitor;
+ Visitor.setShouldVisitImplicitCode(false);
+ Visitor.DisallowMatch("WithCtor", 2, 8);
+ // Simple has a constructor that implicitly initializes 'w'. Test
+ // that a visitor that skips implicit code skips that initialization.
+ // Note: Clang lazily instantiates implicit declarations, so we need
+ // to use them in order to force them to appear in the AST.
+ EXPECT_TRUE(Visitor.runOver(
+ "struct WithCtor { WithCtor(); }; \n"
+ "struct Simple { WithCtor w; }; \n"
+ "int main() { Simple s; }\n"));
+}
+
TEST(RecursiveASTVisitor, VisitsExtension) {
DeclRefExprVisitor Visitor;
Visitor.ExpectMatch("s", 1, 24);
@@ -392,4 +452,12 @@ TEST(RecursiveASTVisitor, VisitsExtension) {
"int s = __extension__ (s);\n"));
}
+TEST(RecursiveASTVisitor, VisitsCompoundLiteralType) {
+ TypeLocVisitor Visitor;
+ Visitor.ExpectMatch("struct S", 1, 26);
+ EXPECT_TRUE(Visitor.runOver(
+ "int f() { return (struct S { int a; }){.a = 0}.a; }",
+ TypeLocVisitor::Lang_C));
+}
+
} // end namespace clang
diff --git a/unittests/Tooling/RefactoringCallbacksTest.cpp b/unittests/Tooling/RefactoringCallbacksTest.cpp
index 00eb193..4e30cfd 100644
--- a/unittests/Tooling/RefactoringCallbacksTest.cpp
+++ b/unittests/Tooling/RefactoringCallbacksTest.cpp
@@ -10,8 +10,8 @@
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/RefactoringCallbacks.h"
-#include "gtest/gtest.h"
#include "RewriterTestContext.h"
+#include "gtest/gtest.h"
namespace clang {
namespace tooling {
@@ -40,28 +40,28 @@ TEST(RefactoringCallbacksTest, ReplacesStmtsWithString) {
std::string Code = "void f() { int i = 1; }";
std::string Expected = "void f() { ; }";
ReplaceStmtWithText Callback("id", ";");
- expectRewritten(Code, Expected, id("id", declarationStatement()), Callback);
+ expectRewritten(Code, Expected, id("id", declStmt()), Callback);
}
TEST(RefactoringCallbacksTest, ReplacesStmtsInCalledMacros) {
std::string Code = "#define A void f() { int i = 1; }\nA";
std::string Expected = "#define A void f() { ; }\nA";
ReplaceStmtWithText Callback("id", ";");
- expectRewritten(Code, Expected, id("id", declarationStatement()), Callback);
+ expectRewritten(Code, Expected, id("id", declStmt()), Callback);
}
TEST(RefactoringCallbacksTest, IgnoresStmtsInUncalledMacros) {
std::string Code = "#define A void f() { int i = 1; }";
std::string Expected = "#define A void f() { int i = 1; }";
ReplaceStmtWithText Callback("id", ";");
- expectRewritten(Code, Expected, id("id", declarationStatement()), Callback);
+ expectRewritten(Code, Expected, id("id", declStmt()), Callback);
}
TEST(RefactoringCallbacksTest, ReplacesInteger) {
std::string Code = "void f() { int i = 1; }";
std::string Expected = "void f() { int i = 2; }";
ReplaceStmtWithText Callback("id", "2");
- expectRewritten(Code, Expected, id("id", expression(integerLiteral())),
+ expectRewritten(Code, Expected, id("id", expr(integerLiteral())),
Callback);
}
@@ -72,7 +72,7 @@ TEST(RefactoringCallbacksTest, ReplacesStmtWithStmt) {
expectRewritten(Code, Expected,
id("always-false", conditionalOperator(
hasCondition(boolLiteral(equals(false))),
- hasFalseExpression(id("should-be", expression())))),
+ hasFalseExpression(id("should-be", expr())))),
Callback);
}
@@ -82,8 +82,8 @@ TEST(RefactoringCallbacksTest, ReplacesIfStmt) {
ReplaceIfStmtWithItsBody Callback("id", true);
expectRewritten(Code, Expected,
id("id", ifStmt(
- hasCondition(implicitCast(hasSourceExpression(
- declarationReference(to(variable(hasName("a"))))))))),
+ hasCondition(implicitCastExpr(hasSourceExpression(
+ declRefExpr(to(varDecl(hasName("a"))))))))),
Callback);
}
diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp
index 8d96955..ff278bf 100644
--- a/unittests/Tooling/RefactoringTest.cpp
+++ b/unittests/Tooling/RefactoringTest.cpp
@@ -15,14 +15,14 @@
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
diff --git a/unittests/Tooling/RewriterTestContext.h b/unittests/Tooling/RewriterTestContext.h
index f68be6b..d790ac1 100644
--- a/unittests/Tooling/RewriterTestContext.h
+++ b/unittests/Tooling/RewriterTestContext.h
@@ -15,12 +15,12 @@
#define LLVM_CLANG_REWRITER_TEST_CONTEXT_H
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -35,8 +35,10 @@ namespace clang {
class RewriterTestContext {
public:
RewriterTestContext()
- : Diagnostics(llvm::IntrusiveRefCntPtr<DiagnosticIDs>()),
- DiagnosticPrinter(llvm::outs(), DiagnosticOptions()),
+ : DiagOpts(new DiagnosticOptions()),
+ Diagnostics(llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ &*DiagOpts),
+ DiagnosticPrinter(llvm::outs(), &*DiagOpts),
Files((FileSystemOptions())),
Sources(Diagnostics, Files),
Rewrite(Sources, Options) {
@@ -109,6 +111,7 @@ class RewriterTestContext {
return Files.getBufferForFile(Path, NULL)->getBuffer();
}
+ llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
DiagnosticsEngine Diagnostics;
TextDiagnosticPrinter DiagnosticPrinter;
FileManager Files;
diff --git a/unittests/Tooling/TestVisitor.h b/unittests/Tooling/TestVisitor.h
index d439d81..8333c24 100644
--- a/unittests/Tooling/TestVisitor.h
+++ b/unittests/Tooling/TestVisitor.h
@@ -6,14 +6,17 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This file defines a utility class for RecursiveASTVisitor related tests.
-//
+///
+/// \file
+/// \brief Defines utility templates for RecursiveASTVisitor related tests.
+///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TEST_VISITOR_H
#define LLVM_CLANG_TEST_VISITOR_H
+#include <vector>
+
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
@@ -29,7 +32,7 @@ namespace clang {
/// This is a drop-in replacement for RecursiveASTVisitor itself, with the
/// additional capability of running it over a snippet of code.
///
-/// Visits template instantiations by default.
+/// Visits template instantiations (but not implicit code) by default.
template <typename T>
class TestVisitor : public RecursiveASTVisitor<T> {
public:
@@ -37,9 +40,16 @@ public:
virtual ~TestVisitor() { }
+ enum Language { Lang_C, Lang_CXX };
+
/// \brief Runs the current AST visitor over the given code.
- bool runOver(StringRef Code) {
- return tooling::runToolOnCode(CreateTestAction(), Code);
+ bool runOver(StringRef Code, Language L = Lang_CXX) {
+ std::vector<std::string> Args;
+ switch (L) {
+ case Lang_C: Args.push_back("-std=c99"); break;
+ case Lang_CXX: Args.push_back("-std=c++98"); break;
+ }
+ return tooling::runToolOnCodeWithArgs(CreateTestAction(), Code, Args);
}
bool shouldVisitTemplateInstantiations() const {
@@ -81,63 +91,126 @@ protected:
ASTContext *Context;
};
-
-/// \brief A RecursiveASTVisitor for testing the RecursiveASTVisitor itself.
+/// \brief A RecursiveASTVisitor to check that certain matches are (or are
+/// not) observed during visitation.
///
-/// Allows simple creation of test visitors running matches on only a small
+/// This is a RecursiveASTVisitor for testing the RecursiveASTVisitor itself,
+/// and allows simple creation of test visitors running matches on only a small
/// subset of the Visit* methods.
template <typename T, template <typename> class Visitor = TestVisitor>
class ExpectedLocationVisitor : public Visitor<T> {
public:
- ExpectedLocationVisitor()
- : ExpectedLine(0), ExpectedColumn(0), Found(false) {}
-
- virtual ~ExpectedLocationVisitor() {
- EXPECT_TRUE(Found)
- << "Expected \"" << ExpectedMatch << "\" at " << ExpectedLine
- << ":" << ExpectedColumn << PartialMatches;
+ /// \brief Expect 'Match' *not* to occur at the given 'Line' and 'Column'.
+ ///
+ /// Any number of matches can be disallowed.
+ void DisallowMatch(Twine Match, unsigned Line, unsigned Column) {
+ DisallowedMatches.push_back(MatchCandidate(Match, Line, Column));
}
/// \brief Expect 'Match' to occur at the given 'Line' and 'Column'.
+ ///
+ /// Any number of expected matches can be set by calling this repeatedly.
+ /// Each is expected to be matched exactly once.
void ExpectMatch(Twine Match, unsigned Line, unsigned Column) {
- ExpectedMatch = Match.str();
- ExpectedLine = Line;
- ExpectedColumn = Column;
+ ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column));
+ }
+
+ /// \brief Checks that all expected matches have been found.
+ virtual ~ExpectedLocationVisitor() {
+ for (typename std::vector<ExpectedMatch>::const_iterator
+ It = ExpectedMatches.begin(), End = ExpectedMatches.end();
+ It != End; ++It) {
+ It->ExpectFound();
+ }
}
protected:
- /// \brief Convenience method to simplify writing test visitors.
- ///
- /// Sets 'Found' to true if 'Name' and 'Location' match the expected
- /// values. If only a partial match is found, record the information
- /// to produce nice error output when a test fails.
+ /// \brief Checks an actual match against expected and disallowed matches.
///
/// Implementations are required to call this with appropriate values
/// for 'Name' during visitation.
void Match(StringRef Name, SourceLocation Location) {
- FullSourceLoc FullLocation = this->Context->getFullLoc(Location);
- if (Name == ExpectedMatch &&
- FullLocation.isValid() &&
- FullLocation.getSpellingLineNumber() == ExpectedLine &&
- FullLocation.getSpellingColumnNumber() == ExpectedColumn) {
- EXPECT_TRUE(!Found);
- Found = true;
- } else if (Name == ExpectedMatch ||
- (FullLocation.isValid() &&
- FullLocation.getSpellingLineNumber() == ExpectedLine &&
- FullLocation.getSpellingColumnNumber() == ExpectedColumn)) {
- // If we did not match, record information about partial matches.
- llvm::raw_string_ostream Stream(PartialMatches);
- Stream << ", partial match: \"" << Name << "\" at ";
- Location.print(Stream, this->Context->getSourceManager());
+ const FullSourceLoc FullLocation = this->Context->getFullLoc(Location);
+
+ for (typename std::vector<MatchCandidate>::const_iterator
+ It = DisallowedMatches.begin(), End = DisallowedMatches.end();
+ It != End; ++It) {
+ EXPECT_FALSE(It->Matches(Name, FullLocation))
+ << "Matched disallowed " << *It;
+ }
+
+ for (typename std::vector<ExpectedMatch>::iterator
+ It = ExpectedMatches.begin(), End = ExpectedMatches.end();
+ It != End; ++It) {
+ It->UpdateFor(Name, FullLocation, this->Context->getSourceManager());
}
}
- std::string ExpectedMatch;
- unsigned ExpectedLine;
- unsigned ExpectedColumn;
- std::string PartialMatches;
- bool Found;
+ private:
+ struct MatchCandidate {
+ std::string ExpectedName;
+ unsigned LineNumber;
+ unsigned ColumnNumber;
+
+ MatchCandidate(Twine Name, unsigned LineNumber, unsigned ColumnNumber)
+ : ExpectedName(Name.str()), LineNumber(LineNumber),
+ ColumnNumber(ColumnNumber) {
+ }
+
+ bool Matches(StringRef Name, FullSourceLoc const &Location) const {
+ return MatchesName(Name) && MatchesLocation(Location);
+ }
+
+ bool PartiallyMatches(StringRef Name, FullSourceLoc const &Location) const {
+ return MatchesName(Name) || MatchesLocation(Location);
+ }
+
+ bool MatchesName(StringRef Name) const {
+ return Name == ExpectedName;
+ }
+
+ bool MatchesLocation(FullSourceLoc const &Location) const {
+ return Location.isValid() &&
+ Location.getSpellingLineNumber() == LineNumber &&
+ Location.getSpellingColumnNumber() == ColumnNumber;
+ }
+
+ friend std::ostream &operator<<(std::ostream &Stream,
+ MatchCandidate const &Match) {
+ return Stream << Match.ExpectedName
+ << " at " << Match.LineNumber << ":" << Match.ColumnNumber;
+ }
+ };
+
+ struct ExpectedMatch {
+ ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber)
+ : Candidate(Name, LineNumber, ColumnNumber), Found(false) {}
+
+ void UpdateFor(StringRef Name, FullSourceLoc Location, SourceManager &SM) {
+ if (Candidate.Matches(Name, Location)) {
+ EXPECT_TRUE(!Found);
+ Found = true;
+ } else if (!Found && Candidate.PartiallyMatches(Name, Location)) {
+ llvm::raw_string_ostream Stream(PartialMatches);
+ Stream << ", partial match: \"" << Name << "\" at ";
+ Location.print(Stream, SM);
+ }
+ }
+
+ void ExpectFound() const {
+ EXPECT_TRUE(Found)
+ << "Expected \"" << Candidate.ExpectedName
+ << "\" at " << Candidate.LineNumber
+ << ":" << Candidate.ColumnNumber << PartialMatches;
+ }
+
+ MatchCandidate Candidate;
+ std::string PartialMatches;
+ bool Found;
+ };
+
+ std::vector<MatchCandidate> DisallowedMatches;
+ std::vector<ExpectedMatch> ExpectedMatches;
};
}
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
index fb3af26..d40c613 100644
--- a/unittests/Tooling/ToolingTest.cpp
+++ b/unittests/Tooling/ToolingTest.cpp
@@ -130,5 +130,37 @@ TEST(ToolInvocation, TestMapVirtualFile) {
EXPECT_TRUE(Invocation.run());
}
+struct VerifyEndCallback : public EndOfSourceFileCallback {
+ VerifyEndCallback() : Called(0), Matched(false) {}
+ virtual void run() {
+ ++Called;
+ }
+ ASTConsumer *newASTConsumer() {
+ return new FindTopLevelDeclConsumer(&Matched);
+ }
+ unsigned Called;
+ bool Matched;
+};
+
+#if !defined(_WIN32)
+TEST(newFrontendActionFactory, InjectsEndOfSourceFileCallback) {
+ VerifyEndCallback EndCallback;
+
+ FixedCompilationDatabase Compilations("/", std::vector<std::string>());
+ std::vector<std::string> Sources;
+ Sources.push_back("/a.cc");
+ Sources.push_back("/b.cc");
+ ClangTool Tool(Compilations, Sources);
+
+ Tool.mapVirtualFile("/a.cc", "void a() {}");
+ Tool.mapVirtualFile("/b.cc", "void b() {}");
+
+ Tool.run(newFrontendActionFactory(&EndCallback, &EndCallback));
+
+ EXPECT_TRUE(EndCallback.Matched);
+ EXPECT_EQ(2u, EndCallback.Called);
+}
+#endif
+
} // end namespace tooling
} // end namespace clang
OpenPOWER on IntegriCloud