fowles created this revision.
fowles added a reviewer: klimek.
fowles added a subscriber: cfe-commits.

Add an argumentsAre matcher


https://reviews.llvm.org/D28260

Files:
  include/clang/ASTMatchers/ASTMatchers.h
  unittests/ASTMatchers/ASTMatchersTraversalTest.cpp


Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -375,6 +375,14 @@
   EXPECT_TRUE(notMatches("void x(int) { int y; x(y); }", WrongIndex));
 }
 
+TEST(Matcher, ArgumentsAre) {
+  StatementMatcher Call = callExpr(argumentsAre(declRefExpr(), declRefExpr()));
+
+  EXPECT_TRUE(notMatches("void f(int x) { f(x); }", Call));
+  EXPECT_TRUE(matches("void f(int x, int y) { f(x, y); }", Call));
+  EXPECT_TRUE(notMatches("void f(int x, int y, int z) { f(x, y, z); }", Call));
+}
+
 TEST(Matcher, AnyArgument) {
   StatementMatcher CallArgumentY = callExpr(
     hasAnyArgument(
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -3055,6 +3055,34 @@
               *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder));
 }
 
+namespace internal {
+inline auto argumentsAreImpl(int n) -> decltype(argumentCountIs(n)) {
+  return argumentCountIs(n);
+}
+
+template <typename First, typename... Rest>
+auto argumentsAreImpl(int n, First &&first, Rest &&... rest)
+    -> decltype(allOf(hasArgument(n, std::forward<First>(first)),
+                      argumentsAreImpl(n + 1, std::forward<Rest>(rest)...))) {
+  return allOf(hasArgument(n, std::forward<First>(first)),
+               argumentsAreImpl(n + 1, std::forward<Rest>(rest)...));
+}
+} // end namespace internal
+
+/// \brief Matches all the arguments of a call expression or a constructor
+/// call expression.
+///
+/// Example matches the call to f2, but not f1 or f3.
+///     (matcher = callExpr(argumentsAre(declRefExpr(), declRefExpr())))
+/// \code
+///   void x(int a, int b, int c) { f1(a); f2(a, b); f3(a, b, c); }
+/// \endcode
+template <typename... T>
+auto argumentsAre(T &&... t)
+    -> decltype(internal::argumentsAreImpl(0, std::forward<T>(t)...)) {
+  return internal::argumentsAreImpl(0, std::forward<T>(t)...);
+}
+
 /// \brief Matches declaration statements that contain a specific number of
 /// declarations.
 ///


Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -375,6 +375,14 @@
   EXPECT_TRUE(notMatches("void x(int) { int y; x(y); }", WrongIndex));
 }
 
+TEST(Matcher, ArgumentsAre) {
+  StatementMatcher Call = callExpr(argumentsAre(declRefExpr(), declRefExpr()));
+
+  EXPECT_TRUE(notMatches("void f(int x) { f(x); }", Call));
+  EXPECT_TRUE(matches("void f(int x, int y) { f(x, y); }", Call));
+  EXPECT_TRUE(notMatches("void f(int x, int y, int z) { f(x, y, z); }", Call));
+}
+
 TEST(Matcher, AnyArgument) {
   StatementMatcher CallArgumentY = callExpr(
     hasAnyArgument(
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -3055,6 +3055,34 @@
               *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder));
 }
 
+namespace internal {
+inline auto argumentsAreImpl(int n) -> decltype(argumentCountIs(n)) {
+  return argumentCountIs(n);
+}
+
+template <typename First, typename... Rest>
+auto argumentsAreImpl(int n, First &&first, Rest &&... rest)
+    -> decltype(allOf(hasArgument(n, std::forward<First>(first)),
+                      argumentsAreImpl(n + 1, std::forward<Rest>(rest)...))) {
+  return allOf(hasArgument(n, std::forward<First>(first)),
+               argumentsAreImpl(n + 1, std::forward<Rest>(rest)...));
+}
+} // end namespace internal
+
+/// \brief Matches all the arguments of a call expression or a constructor
+/// call expression.
+///
+/// Example matches the call to f2, but not f1 or f3.
+///     (matcher = callExpr(argumentsAre(declRefExpr(), declRefExpr())))
+/// \code
+///   void x(int a, int b, int c) { f1(a); f2(a, b); f3(a, b, c); }
+/// \endcode
+template <typename... T>
+auto argumentsAre(T &&... t)
+    -> decltype(internal::argumentsAreImpl(0, std::forward<T>(t)...)) {
+  return internal::argumentsAreImpl(0, std::forward<T>(t)...);
+}
+
 /// \brief Matches declaration statements that contain a specific number of
 /// declarations.
 ///
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to