malcolm.parsons created this revision.
malcolm.parsons added reviewers: sbenza, bkramer, klimek.
malcolm.parsons added a subscriber: cfe-commits.

I needed to know whether a FieldDecl had an in-class
initializer for https://reviews.llvm.org/D26453. I used a narrowing matcher 
there, but a
traversal matcher might be generally useful.

VarDecl has a hasInitializer traversal matcher.
ForStmt has a withLoopInit traversal matcher.
CXXCtorInitializer has a withInitializer traversal matcher.
EnumConstantDecl doesn't have a traversal matcher for its initializer.
IfStmt doesn't have a traversal matcher for its initializer.


https://reviews.llvm.org/D28034

Files:
  docs/LibASTMatchersReference.html
  include/clang/ASTMatchers/ASTMatchers.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1404,6 +1404,16 @@
                       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"))));
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -232,6 +232,7 @@
   REGISTER_MATCHER(hasFalseExpression);
   REGISTER_MATCHER(hasGlobalStorage);
   REGISTER_MATCHER(hasImplicitDestinationType);
+  REGISTER_MATCHER(hasInClassInitializer);
   REGISTER_MATCHER(hasIncrement);
   REGISTER_MATCHER(hasIndex);
   REGISTER_MATCHER(hasInitializer);
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -533,7 +533,8 @@
   return Node.isBitField();
 }
 
-/// \brief Matches non-static data members that are bit-fields.
+/// \brief Matches non-static data members that are bit-fields of the specified
+/// bit width.
 ///
 /// Given
 /// \code
@@ -543,13 +544,31 @@
 ///     int c : 2;
 ///   };
 /// \endcode
-/// fieldDecl(isBitField())
+/// fieldDecl(hasBitWidth(2))
 ///   matches 'int a;' and 'int c;' but not 'int b;'.
 AST_MATCHER_P(FieldDecl, hasBitWidth, unsigned, Width) {
   return Node.isBitField() &&
          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;
+///   };
+/// \endcode
+/// fieldDecl(hasInClassInitializer(integerLiteral(equals(2))))
+///   matches 'int a;' but not 'int b;'.
+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) {
Index: docs/LibASTMatchersReference.html
===================================================================
--- docs/LibASTMatchersReference.html
+++ docs/LibASTMatchersReference.html
@@ -2430,15 +2430,16 @@
 
 
 <tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FieldDecl.html";>FieldDecl</a>&gt;</td><td class="name" onclick="toggle('hasBitWidth0')"><a name="hasBitWidth0Anchor">hasBitWidth</a></td><td>unsigned Width</td></tr>
-<tr><td colspan="4" class="doc" id="hasBitWidth0"><pre>Matches non-static data members that are bit-fields.
+<tr><td colspan="4" class="doc" id="hasBitWidth0"><pre>Matches non-static data members that are bit-fields of the specified
+bit width.
 
 Given
   class C {
     int a : 2;
     int b : 4;
     int c : 2;
   };
-fieldDecl(isBitField())
+fieldDecl(hasBitWidth(2))
   matches 'int a;' and 'int c;' but not 'int b;'.
 </pre></td></tr>
 
@@ -4750,6 +4751,19 @@
 </pre></td></tr>
 
 
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FieldDecl.html";>FieldDecl</a>&gt;</td><td class="name" onclick="toggle('hasInClassInitializer0')"><a name="hasInClassInitializer0Anchor">hasInClassInitializer</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html";>Expr</a>&gt; 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;
+  };
+fieldDecl(hasInClassInitializer(integerLiteral(equals(2))))
+  matches 'int a;' but not 'int b;'.
+</pre></td></tr>
+
+
 <tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html";>ForStmt</a>&gt;</td><td class="name" onclick="toggle('hasBody1')"><a name="hasBody1Anchor">hasBody</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html";>Stmt</a>&gt; 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.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to