]> granicus.if.org Git - clang/commitdiff
[ASTMatchers] Add hasInClassInitializer traversal matcher for FieldDecl.
authorMalcolm Parsons <malcolm.parsons@gmail.com>
Sat, 24 Dec 2016 13:35:14 +0000 (13:35 +0000)
committerMalcolm Parsons <malcolm.parsons@gmail.com>
Sat, 24 Dec 2016 13:35:14 +0000 (13:35 +0000)
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
include/clang/ASTMatchers/ASTMatchers.h
lib/ASTMatchers/Dynamic/Registry.cpp
unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

index 7745480c44c9fd3fa1058359ce4175fc1b52939e..4ee953f1838e447b7da069941c8e6e1527c95097 100644 (file)
@@ -4751,6 +4751,22 @@ would only match the declaration for a.
 </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;
+    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&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.
index efa606262b90153353b501039be35432dc79f58c..6a5224febab5e532949c7ec52d074b31fda11964 100644 (file)
@@ -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) {
index b1309bcafe3a077cd68e04c525570f55f009687b..d1cab80c1a53059f1d29fab174c8108a0c475a53 100644 (file)
@@ -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);
index b7ffd75384f7aee84257b8595127547a26ea5b0d..6037127feb524d95d734a63be857f4ab444d6e6f 100644 (file)
@@ -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"))));