Adds ctorInitializer and forEachConstructorInitializer matchers.
authorManuel Klimek <klimek@google.com>
Fri, 19 Jul 2013 11:50:54 +0000 (11:50 +0000)
committerManuel Klimek <klimek@google.com>
Fri, 19 Jul 2013 11:50:54 +0000 (11:50 +0000)
llvm-svn: 186668

clang/include/clang/ASTMatchers/ASTMatchers.h
clang/unittests/ASTMatchers/ASTMatchersTest.cpp

index 18bfe15..1414c4e 100644 (file)
@@ -241,6 +241,17 @@ const internal::VariadicDynCastAllOfMatcher<
   Decl,
   AccessSpecDecl> accessSpecDecl;
 
+/// \brief Matches constructor initializers.
+///
+/// Examples matches \c i(42).
+/// \code
+///   class C {
+///     C() : i(42) {}
+///     int i;
+///   };
+/// \endcode
+const internal::VariadicAllOfMatcher<CXXCtorInitializer> ctorInitializer;
+
 /// \brief Matches public C++ declarations.
 ///
 /// Given
@@ -3494,6 +3505,31 @@ AST_MATCHER_P(SwitchStmt, forEachSwitchCase, internal::Matcher<SwitchCase>,
   return Matched;
 }
 
+/// \brief Matches each constructor initializer in a constructor definition.
+///
+/// Given
+/// \code
+///   class A { A() : i(42), j(42) {} int i; int j; };
+/// \endcode
+/// constructorDecl(forEachConstructorInitializer(forField(decl().bind("x"))))
+///   will trigger two matches, binding for 'i' and 'j' respectively.
+AST_MATCHER_P(CXXConstructorDecl, forEachConstructorInitializer,
+              internal::Matcher<CXXCtorInitializer>, InnerMatcher) {
+  BoundNodesTreeBuilder Result;
+  bool Matched = false;
+  for (CXXConstructorDecl::init_const_iterator I = Node.init_begin(),
+                                               E = Node.init_end();
+       I != E; ++I) {
+    BoundNodesTreeBuilder InitBuilder(*Builder);
+    if (InnerMatcher.matches(**I, Finder, &InitBuilder)) {
+      Matched = true;
+      Result.addMatch(InitBuilder);
+    }
+  }
+  *Builder = Result;
+  return Matched;
+}
+
 /// \brief If the given case statement does not use the GNU case range
 /// extension, matches the constant given in the statement.
 ///
index 8df0274..b6d21e6 100644 (file)
@@ -2967,6 +2967,12 @@ TEST(SwitchCase, MatchesEachCase) {
       new VerifyIdIsBoundTo<CaseStmt>("x", 3)));
 }
 
+TEST(ForEachConstructorInitializer, MatchesInitializers) {
+  EXPECT_TRUE(matches(
+      "struct X { X() : i(42), j(42) {} int i, j; };",
+      constructorDecl(forEachConstructorInitializer(ctorInitializer()))));
+}
+
 TEST(ExceptionHandling, SimpleCases) {
   EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", catchStmt()));
   EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", tryStmt()));
@@ -3157,6 +3163,11 @@ TEST(LoopingMatchers, DoNotOverwritePreviousMatchResultOnFailure) {
       "class A {};",
       recordDecl(hasName("::A"), decl().bind("x"), unless(hasName("fooble"))),
       new VerifyIdIsBoundTo<Decl>("x", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      "class A { A() : s(), i(42) {} const char *s; int i; };",
+      constructorDecl(hasName("::A::A"), decl().bind("x"),
+                      forEachConstructorInitializer(forField(hasName("i")))),
+      new VerifyIdIsBoundTo<Decl>("x", 1)));
 }
 
 TEST(ForEachDescendant, BindsCorrectNodes) {