From b64b36bd35a2ead9464dfa8fea2655eaa62b2709 Mon Sep 17 00:00:00 2001 From: Jakub Kuderski <kubakuderski@gmail.com> Date: Fri, 5 May 2017 21:01:12 +0000 Subject: [PATCH] Add cxxStdInitializerListExpr AST matcher Summary: This adds a new ASTMatcher for CXXStdInitializerListExprs that matches C++ initializer list expressions. The primary motivation is to use it to fix [[ https://bugs.llvm.org/show_bug.cgi?id=32896 | PR32896 ]] (review here [[ https://reviews.llvm.org/D32767 | D32767 ]]). Reviewers: alexfh, Prazek, aaron.ballman Reviewed By: alexfh, aaron.ballman Subscribers: malcolm.parsons, cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D32810 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@302287 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LibASTMatchersReference.html | 17 ++++++++++++-- include/clang/ASTMatchers/ASTMatchers.h | 14 +++++++++++ lib/ASTMatchers/Dynamic/Registry.cpp | 1 + unittests/ASTMatchers/ASTMatchersNodeTest.cpp | 23 +++++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index 736e1dfcabc..c91b2a24902 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -924,6 +924,19 @@ in </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxStdInitializerListExpr0')"><a name="cxxStdInitializerListExpr0Anchor">cxxStdInitializerListExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXStdInitializerListExpr.html">CXXStdInitializerListExpr</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="cxxStdInitializerListExpr0"><pre>Matches C++ initializer list expressions. + +Given + std::vector<int> a({ 1, 2, 3 }); + std::vector<int> b = { 4, 5 }; + int c[] = { 6, 7 }; + std::pair<int, int> d = { 8, 9 }; +cxxStdInitializerListExpr() + matches "{ 1, 2, 3 }" and "{ 4, 5 }" +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxTemporaryObjectExpr0')"><a name="cxxTemporaryObjectExpr0Anchor">cxxTemporaryObjectExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXTemporaryObjectExpr.html">CXXTemporaryObjectExpr</a>>...</td></tr> <tr><td colspan="4" class="doc" id="cxxTemporaryObjectExpr0"><pre>Matches functional cast expressions having N != 1 arguments @@ -1160,7 +1173,7 @@ Example matches [&](){return 5;} <tr><td colspan="4" class="doc" id="materializeTemporaryExpr0"><pre>Matches nodes where temporaries are materialized. Example: Given - struct T {void func()}; + struct T {void func();}; T f(); void g(T); materializeTemporaryExpr() matches 'f()' in these statements @@ -5233,7 +5246,7 @@ Example matches y in x(y) <tr><td colspan="4" class="doc" id="hasReceiverType0"><pre>Matches on the receiver of an ObjectiveC Message expression. Example -matcher = objCMessageExpr(hasRecieverType(asString("UIWebView *"))); +matcher = objCMessageExpr(hasReceiverType(asString("UIWebView *"))); matches the [webView ...] message invocation. NSString *webViewJavaScript = ... UIWebView *webView = ... diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index f11469b8fc2..0ab8d5fe4fc 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -1223,6 +1223,20 @@ AST_MATCHER_P(InitListExpr, hasSyntacticForm, InnerMatcher.matches(*SyntForm, Finder, Builder)); } +/// \brief Matches C++ initializer list expressions. +/// +/// Given +/// \code +/// std::vector<int> a({ 1, 2, 3 }); +/// std::vector<int> b = { 4, 5 }; +/// int c[] = { 6, 7 }; +/// std::pair<int, int> d = { 8, 9 }; +/// \endcode +/// cxxStdInitializerListExpr() +/// matches "{ 1, 2, 3 }" and "{ 4, 5 }" +const internal::VariadicDynCastAllOfMatcher<Stmt, + CXXStdInitializerListExpr> cxxStdInitializerListExpr; + /// \brief Matches implicit initializers of init list expressions. /// /// Given diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index 6f935620888..26743d86f5e 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -153,6 +153,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(cxxRecordDecl); REGISTER_MATCHER(cxxReinterpretCastExpr); REGISTER_MATCHER(cxxStaticCastExpr); + REGISTER_MATCHER(cxxStdInitializerListExpr); REGISTER_MATCHER(cxxTemporaryObjectExpr); REGISTER_MATCHER(cxxThisExpr); REGISTER_MATCHER(cxxThrowExpr); diff --git a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp index 5c29334222d..dfaa441cd76 100644 --- a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -1020,6 +1020,29 @@ TEST(InitListExpression, MatchesInitListExpression) { matches("int i[1] = {42, [0] = 43};", integerLiteral(equals(42)))); } +TEST(CXXStdInitializerListExpression, MatchesCXXStdInitializerListExpression) { + const std::string code = "namespace std {" + "template <typename> class initializer_list {" + " public: initializer_list() noexcept {}" + "};" + "}" + "struct A {" + " A(std::initializer_list<int>) {}" + "};"; + EXPECT_TRUE(matches(code + "A a{0};", + cxxConstructExpr(has(cxxStdInitializerListExpr()), + hasDeclaration(cxxConstructorDecl( + ofClass(hasName("A"))))))); + EXPECT_TRUE(matches(code + "A a = {0};", + cxxConstructExpr(has(cxxStdInitializerListExpr()), + hasDeclaration(cxxConstructorDecl( + ofClass(hasName("A"))))))); + + EXPECT_TRUE(notMatches("int a[] = { 1, 2 };", cxxStdInitializerListExpr())); + EXPECT_TRUE(notMatches("struct B { int x, y; }; B b = { 5, 6 };", + cxxStdInitializerListExpr())); +} + TEST(UsingDeclaration, MatchesUsingDeclarations) { EXPECT_TRUE(matches("namespace X { int x; } using X::x;", usingDecl())); -- GitLab