diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 6507433e33..770ec779b1 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -489,6 +489,14 @@ const internal::VariadicDynCastAllOfMatcher memberExpr; /// \endcode const internal::VariadicDynCastAllOfMatcher callExpr; +/// \brief Matches lambda expressions. +/// +/// Example matches [&](){return 5;} +/// \code +/// [&](){return 5;} +/// \endcode +const internal::VariadicDynCastAllOfMatcher lambdaExpr; + /// \brief Matches member call expressions. /// /// Example matches x.y() @@ -664,9 +672,19 @@ const internal::VariadicDynCastAllOfMatcher ifStmt; /// Example matches 'for (;;) {}' /// \code /// for (;;) {} +/// int i[] = {1, 2, 3}; for (auto a : i); /// \endcode const internal::VariadicDynCastAllOfMatcher forStmt; +/// \brief Matches range-based for statements. +/// +/// forRangeStmt() matches 'for (auto a : i)' +/// \code +/// int i[] = {1, 2, 3}; for (auto a : i); +/// for(int j = 0; j < 5; ++j); +/// \endcode +const internal::VariadicDynCastAllOfMatcher forRangeStmt; + /// \brief Matches the increment statement of a for loop. /// /// Example: @@ -884,6 +902,18 @@ const internal::VariadicDynCastAllOfMatcher< Stmt, IntegerLiteral> integerLiteral; +/// \brief Matches user defined literal operator call. +/// +/// Example match: "foo"_suffix +const internal::VariadicDynCastAllOfMatcher< + Stmt, + UserDefinedLiteral> userDefinedLiteral; + +/// \brief Matches nullptr literal. +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXNullPtrLiteralExpr> nullPtrLiteralExpr; + /// \brief Matches binary operator expressions. /// /// Example matches a || b diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index b49d082501..6698e4ecbc 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -805,6 +805,27 @@ TEST(Matcher, Call) { MethodOnYPointer)); } +TEST(Matcher, Lambda) { + EXPECT_TRUE(matches("auto f = [&] (int i) { return i; };", + lambdaExpr())); +} + +TEST(Matcher, ForRange) { + EXPECT_TRUE(matches("#include \n" + "void f() { for (auto &a : {1, 2, 3}); }", + 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; } }", @@ -1556,6 +1577,10 @@ 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())); } @@ -1981,6 +2006,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("#include \n" + "void f() { for (auto &a : {1, 2, 3}); }", + forStmt())); } TEST(For, ForLoopInternals) { @@ -2105,17 +2133,20 @@ TEST(Member, MatchesInMemberFunctionCall) { } TEST(Member, MatchesMemberAllocationFunction) { - EXPECT_TRUE(matches("namespace std { typedef typeof(sizeof(int)) size_t; }" - "class X { void *operator new(std::size_t); };", - methodDecl(ofClass(hasName("X"))))); + // 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"))))); - EXPECT_TRUE(matches( + // 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"))))); + methodDecl(ofClass(hasName("X"))), true, "-std=gnu++98")); } TEST(HasObjectExpression, DoesNotMatchMember) { diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h index 6d872e8ea9..01a7c51016 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.h +++ b/unittests/ASTMatchers/ASTMatchersTest.h @@ -51,13 +51,14 @@ private: template 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 Factory(newFrontendActionFactory(&Finder)); // Some tests use typeof, which is a gnu extension. - std::vector Args(1, "-std=gnu++98"); + std::vector Args(1, CompileArg); if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) { return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; } @@ -73,13 +74,13 @@ testing::AssertionResult matchesConditionally(const std::string &Code, template testing::AssertionResult matches(const std::string &Code, const T &AMatcher) { - return matchesConditionally(Code, AMatcher, true); + return matchesConditionally(Code, AMatcher, true, "-std=c++11"); } template testing::AssertionResult notMatches(const std::string &Code, const T &AMatcher) { - return matchesConditionally(Code, AMatcher, false); + return matchesConditionally(Code, AMatcher, false, "-std=c++11"); } template