From 8614176ac530460aaaa4e9f593fa173f12cb760d Mon Sep 17 00:00:00 2001 From: Malcolm Parsons <malcolm.parsons@gmail.com> Date: Sat, 24 Dec 2016 13:35:14 +0000 Subject: [PATCH] [ASTMatchers] Add hasInClassInitializer traversal matcher for FieldDecl. Summary: I needed to know whether a FieldDecl had an in-class initializer for D26453. I used a narrowing matcher there, but a traversal matcher might be generally useful. Reviewers: sbenza, bkramer, klimek, aaron.ballman Subscribers: aaron.ballman, Prazek, cfe-commits Differential Revision: https://reviews.llvm.org/D28034 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@290492 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LibASTMatchersReference.html | 16 ++++++++++++++ include/clang/ASTMatchers/ASTMatchers.h | 21 +++++++++++++++++++ lib/ASTMatchers/Dynamic/Registry.cpp | 1 + .../ASTMatchers/ASTMatchersNarrowingTest.cpp | 10 +++++++++ 4 files changed, 48 insertions(+) diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index 7745480c44c..4ee953f1838 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -4751,6 +4751,22 @@ would only match the declaration for a. </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FieldDecl.html">FieldDecl</a>></td><td class="name" onclick="toggle('hasInClassInitializer0')"><a name="hasInClassInitializer0Anchor">hasInClassInitializer</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasInClassInitializer0"><pre>Matches non-static data members that have an in-class initializer. + +Given + class C { + int a = 2; + int b = 3; + int c; + }; +fieldDecl(hasInClassInitializer(integerLiteral(equals(2)))) + matches 'int a;' but not 'int b;'. +fieldDecl(hasInClassInitializer(anything())) + matches 'int a;' and 'int b;' but not 'int c;'. +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>></td><td class="name" onclick="toggle('hasBody1')"><a name="hasBody1Anchor">hasBody</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasBody1"><pre>Matches a 'for', 'while', 'do while' statement or a function definition that has a given body. diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index efa606262b9..6a5224febab 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -551,6 +551,27 @@ AST_MATCHER_P(FieldDecl, hasBitWidth, unsigned, Width) { Node.getBitWidthValue(Finder->getASTContext()) == Width; } +/// \brief Matches non-static data members that have an in-class initializer. +/// +/// Given +/// \code +/// class C { +/// int a = 2; +/// int b = 3; +/// int c; +/// }; +/// \endcode +/// fieldDecl(hasInClassInitializer(integerLiteral(equals(2)))) +/// matches 'int a;' but not 'int b;'. +/// fieldDecl(hasInClassInitializer(anything())) +/// matches 'int a;' and 'int b;' but not 'int c;'. +AST_MATCHER_P(FieldDecl, hasInClassInitializer, internal::Matcher<Expr>, + InnerMatcher) { + const Expr *Initializer = Node.getInClassInitializer(); + return (Initializer != nullptr && + InnerMatcher.matches(*Initializer, Finder, Builder)); +} + /// \brief Matches a declaration that has been implicitly added /// by the compiler (eg. implicit default/copy constructors). AST_MATCHER(Decl, isImplicit) { diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index b1309bcafe3..d1cab80c1a5 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -232,6 +232,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasFalseExpression); REGISTER_MATCHER(hasGlobalStorage); REGISTER_MATCHER(hasImplicitDestinationType); + REGISTER_MATCHER(hasInClassInitializer); REGISTER_MATCHER(hasIncrement); REGISTER_MATCHER(hasIndex); REGISTER_MATCHER(hasInitializer); diff --git a/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp index b7ffd75384f..6037127feb5 100644 --- a/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -1404,6 +1404,16 @@ TEST(Member, BitFields) { fieldDecl(isBitField(), hasBitWidth(2), hasName("a")))); } +TEST(Member, InClassInitializer) { + EXPECT_TRUE( + matches("class C { int a = 2; int b; };", + fieldDecl(hasInClassInitializer(integerLiteral(equals(2))), + hasName("a")))); + EXPECT_TRUE( + notMatches("class C { int a = 2; int b; };", + fieldDecl(hasInClassInitializer(anything()), hasName("b")))); +} + TEST(Member, UnderstandsAccess) { EXPECT_TRUE(matches( "struct A { int i; };", fieldDecl(isPublic(), hasName("i")))); -- GitLab