[cfe-commits] r132374 - in /cfe/trunk: examples/Tooling/ examples/Tooling/RemoveCStrCalls/ include/clang/Tooling/ lib/Tooling/ test/Tooling/ unittests/ unittests/Tooling/

Manuel Klimek klimek at google.com
Tue May 31 16:49:32 PDT 2011


Author: klimek
Date: Tue May 31 18:49:32 2011
New Revision: 132374

URL: http://llvm.org/viewvc/llvm-project?rev=132374&view=rev
Log:
This patch implements an AST matching framework that allows to write
tools that match on the C++ ASTs. The main interface is in ASTMatchers.h,
an example implementation of a tool that removes redundant .c_str() calls
is in the example RemoveCStrCalls.cpp.

Various contributions:
Zhanyong Wan, Chandler Carruth, Marcin Kowalczyk, Wei Xu, James Dennett.

Added:
    cfe/trunk/examples/Tooling/RemoveCStrCalls/
    cfe/trunk/examples/Tooling/RemoveCStrCalls/CMakeLists.txt
    cfe/trunk/examples/Tooling/RemoveCStrCalls/RemoveCStrCalls.cpp
    cfe/trunk/examples/Tooling/replace.py   (with props)
    cfe/trunk/include/clang/Tooling/ASTMatchers.h
    cfe/trunk/include/clang/Tooling/VariadicFunction.h
    cfe/trunk/lib/Tooling/ASTMatchers.cpp
    cfe/trunk/test/Tooling/
    cfe/trunk/test/Tooling/remove-cstr-calls.cpp
    cfe/trunk/unittests/Tooling/ASTMatchersTest.cpp
Modified:
    cfe/trunk/examples/Tooling/CMakeLists.txt
    cfe/trunk/include/clang/Tooling/Tooling.h
    cfe/trunk/lib/Tooling/CMakeLists.txt
    cfe/trunk/lib/Tooling/Tooling.cpp
    cfe/trunk/unittests/CMakeLists.txt

Modified: cfe/trunk/examples/Tooling/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/Tooling/CMakeLists.txt?rev=132374&r1=132373&r2=132374&view=diff
==============================================================================
--- cfe/trunk/examples/Tooling/CMakeLists.txt (original)
+++ cfe/trunk/examples/Tooling/CMakeLists.txt Tue May 31 18:49:32 2011
@@ -4,3 +4,4 @@
   ClangCheck.cpp
   )
 
+add_subdirectory(RemoveCStrCalls)

Added: cfe/trunk/examples/Tooling/RemoveCStrCalls/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/Tooling/RemoveCStrCalls/CMakeLists.txt?rev=132374&view=auto
==============================================================================
--- cfe/trunk/examples/Tooling/RemoveCStrCalls/CMakeLists.txt (added)
+++ cfe/trunk/examples/Tooling/RemoveCStrCalls/CMakeLists.txt Tue May 31 18:49:32 2011
@@ -0,0 +1,5 @@
+set(LLVM_USED_LIBS clangTooling clangBasic clangAST)
+
+add_clang_executable(remove-cstr-calls
+  RemoveCStrCalls.cpp
+  )

Added: cfe/trunk/examples/Tooling/RemoveCStrCalls/RemoveCStrCalls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/Tooling/RemoveCStrCalls/RemoveCStrCalls.cpp?rev=132374&view=auto
==============================================================================
--- cfe/trunk/examples/Tooling/RemoveCStrCalls/RemoveCStrCalls.cpp (added)
+++ cfe/trunk/examples/Tooling/RemoveCStrCalls/RemoveCStrCalls.cpp Tue May 31 18:49:32 2011
@@ -0,0 +1,229 @@
+//===- examples/Tooling/RemoveCStrCalls.cpp - Redundant c_str call removal ===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements a tool that prints replacements that remove redundant
+//  calls of c_str() on strings.
+//
+//  Usage:
+//  remove-cstr-calls <cmake-output-dir> <file1> <file2> ...
+//
+//  Where <cmake-output-dir> is a CMake build directory in which a file named
+//  compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
+//  CMake to get this output).
+//
+//  <file1> ... specify the paths of files in the CMake source tree. This path
+//  is looked up in the compile command database. If the path of a file is
+//  absolute, it needs to point into CMake's source tree. If the path is
+//  relative, the current working directory needs to be in the CMake source
+//  tree and the file must be in a subdirectory of the current working
+//  directory. "./" prefixes in the relative files will be automatically
+//  removed, but the rest of a relative path must be a suffix of a path in
+//  the compile command line database.
+//
+//  For example, to use remove-cstr-calls on all files in a subtree of the
+//  source tree, use:
+//
+//    /path/in/subtree $ find . -name '*.cpp'|
+//        xargs remove-cstr-calls /path/to/source
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+
+using namespace clang::tooling::match;
+
+// FIXME: Pull out helper methods in here into more fitting places.
+
+// Returns the text that makes up 'node' in the source.
+// Returns an empty string if the text cannot be found.
+template <typename T>
+std::string GetText(const clang::SourceManager &SourceManager, const T &Node) {
+  clang::SourceLocation StartSpellingLocatino =
+      SourceManager.getSpellingLoc(Node.getLocStart());
+  clang::SourceLocation EndSpellingLocation =
+      SourceManager.getSpellingLoc(Node.getLocEnd());
+  if (!StartSpellingLocatino.isValid() || !EndSpellingLocation.isValid()) {
+    return std::string();
+  }
+  bool Invalid = true;
+  const char *Text =
+      SourceManager.getCharacterData(StartSpellingLocatino, &Invalid);
+  if (Invalid) {
+    return std::string();
+  }
+  std::pair<clang::FileID, unsigned> Start =
+      SourceManager.getDecomposedLoc(StartSpellingLocatino);
+  std::pair<clang::FileID, unsigned> End =
+      SourceManager.getDecomposedLoc(clang::Lexer::getLocForEndOfToken(
+          EndSpellingLocation, 0, SourceManager, clang::LangOptions()));
+  if (Start.first != End.first) {
+    // Start and end are in different files.
+    return std::string();
+  }
+  if (End.second < Start.second) {
+    // Shuffling text with macros may cause this.
+    return std::string();
+  }
+  return std::string(Text, End.second - Start.second);
+}
+
+// Returns the position of the spelling location of a node inside a file.
+// The format is:
+//     "<start_line>:<start_column>:<end_line>:<end_column>"
+template <typename T1>
+void PrintPosition(
+    llvm::raw_ostream &OS,
+    const clang::SourceManager &SourceManager, const T1 &Node) {
+  clang::SourceLocation StartSpellingLocation =
+      SourceManager.getSpellingLoc(Node.getLocStart());
+  clang::SourceLocation EndSpellingLocation =
+      SourceManager.getSpellingLoc(Node.getLocEnd());
+  clang::PresumedLoc Start =
+      SourceManager.getPresumedLoc(StartSpellingLocation);
+  clang::SourceLocation EndToken = clang::Lexer::getLocForEndOfToken(
+      EndSpellingLocation, 1, SourceManager, clang::LangOptions());
+  clang::PresumedLoc End = SourceManager.getPresumedLoc(EndToken);
+  OS << Start.getLine() << ":" << Start.getColumn() << ":"
+     << End.getLine() << ":" << End.getColumn();
+}
+
+class ReportPosition : public clang::tooling::MatchFinder::MatchCallback {
+ public:
+  virtual void Run(const clang::tooling::MatchFinder::MatchResult &Result) {
+    llvm::outs() << "Found!\n";
+  }
+};
+
+// Return true if expr needs to be put in parens when it is an
+// argument of a prefix unary operator, e.g. when it is a binary or
+// ternary operator syntactically.
+bool NeedParensAfterUnaryOperator(const clang::Expr &ExprNode) {
+  if (llvm::dyn_cast<clang::BinaryOperator>(&ExprNode) ||
+      llvm::dyn_cast<clang::ConditionalOperator>(&ExprNode)) {
+    return true;
+  }
+  if (const clang::CXXOperatorCallExpr *op =
+      llvm::dyn_cast<clang::CXXOperatorCallExpr>(&ExprNode)) {
+    return op->getNumArgs() == 2 &&
+        op->getOperator() != clang::OO_PlusPlus &&
+        op->getOperator() != clang::OO_MinusMinus &&
+        op->getOperator() != clang::OO_Call &&
+        op->getOperator() != clang::OO_Subscript;
+  }
+  return false;
+}
+
+// Format a pointer to an expression: prefix with '*' but simplify
+// when it already begins with '&'.  Return empty string on failure.
+std::string FormatDereference(const clang::SourceManager &SourceManager,
+                              const clang::Expr &ExprNode) {
+  if (const clang::UnaryOperator *Op =
+      llvm::dyn_cast<clang::UnaryOperator>(&ExprNode)) {
+    if (Op->getOpcode() == clang::UO_AddrOf) {
+      // Strip leading '&'.
+      return GetText(SourceManager, *Op->getSubExpr()->IgnoreParens());
+    }
+  }
+  const std::string Text = GetText(SourceManager, ExprNode);
+  if (Text.empty()) return std::string();
+  // Add leading '*'.
+  if (NeedParensAfterUnaryOperator(ExprNode)) {
+    return std::string("*(") + Text + ")";
+  }
+  return std::string("*") + Text;
+}
+
+class FixCStrCall : public clang::tooling::MatchFinder::MatchCallback {
+ public:
+  virtual void Run(const clang::tooling::MatchFinder::MatchResult &Result) {
+    const clang::CallExpr *Call =
+        Result.Nodes.GetStmtAs<clang::CallExpr>("call");
+    const clang::Expr *Arg =
+        Result.Nodes.GetStmtAs<clang::Expr>("arg");
+    const bool Arrow =
+        Result.Nodes.GetStmtAs<clang::MemberExpr>("member")->isArrow();
+    // Replace the "call" node with the "arg" node, prefixed with '*'
+    // if the call was using '->' rather than '.'.
+    const std::string ArgText = Arrow ?
+        FormatDereference(*Result.SourceManager, *Arg) :
+        GetText(*Result.SourceManager, *Arg);
+    if (ArgText.empty()) return;
+
+    llvm::outs() <<
+        Result.SourceManager->getBufferName(Call->getLocStart(), NULL) << ":";
+    PrintPosition(llvm::outs(), *Result.SourceManager, *Call);
+    llvm::outs() << ":" << ArgText << "\n";
+  }
+};
+
+const char *StringConstructor =
+    "::std::basic_string<char, std::char_traits<char>, std::allocator<char> >"
+    "::basic_string";
+
+const char *StringCStrMethod =
+    "::std::basic_string<char, std::char_traits<char>, std::allocator<char> >"
+    "::c_str";
+
+int main(int argc, char **argv) {
+  clang::tooling::ClangTool Tool(argc, argv);
+  clang::tooling::MatchFinder finder;
+  finder.AddMatcher(
+      ConstructorCall(
+          HasDeclaration(Method(HasName(StringConstructor))),
+          ArgumentCountIs(2),
+          // The first argument must have the form x.c_str() or p->c_str()
+          // where the method is string::c_str().  We can use the copy
+          // constructor of string instead (or the compiler might share
+          // the string object).
+          HasArgument(
+              0,
+              Id("call", Call(
+                  Callee(Id("member", MemberExpression())),
+                  Callee(Method(HasName(StringCStrMethod))),
+                  On(Id("arg", Expression()))))),
+          // The second argument is the alloc object which must not be
+          // present explicitly.
+          HasArgument(
+              1,
+              DefaultArgument())), new FixCStrCall);
+  finder.AddMatcher(
+      ConstructorCall(
+          // Implicit constructors of these classes are overloaded
+          // wrt. string types and they internally make a StringRef
+          // referring to the argument.  Passing a string directly to
+          // them is preferred to passing a char pointer.
+          HasDeclaration(Method(AnyOf(
+              HasName("::llvm::StringRef::StringRef"),
+              HasName("::llvm::Twine::Twine")))),
+          ArgumentCountIs(1),
+          // The only argument must have the form x.c_str() or p->c_str()
+          // where the method is string::c_str().  StringRef also has
+          // a constructor from string which is more efficient (avoids
+          // strlen), so we can construct StringRef from the string
+          // directly.
+          HasArgument(
+              0,
+              Id("call", Call(
+                  Callee(Id("member", MemberExpression())),
+                  Callee(Method(HasName(StringCStrMethod))),
+                  On(Id("arg", Expression())))))),
+      new FixCStrCall);
+  return Tool.Run(finder.NewFrontendActionFactory());
+}
+

Added: cfe/trunk/examples/Tooling/replace.py
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/Tooling/replace.py?rev=132374&view=auto
==============================================================================
--- cfe/trunk/examples/Tooling/replace.py (added)
+++ cfe/trunk/examples/Tooling/replace.py Tue May 31 18:49:32 2011
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+#===- replace.py - Applying code rewrites --------------------*- python -*--===#
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+#
+# This script applies the rewrites generated by replace-cstr-calls on a source
+# tree.
+#
+# Usage:
+#   ./replace.py < /path/to/replace-cstr-calls-output
+#
+#===------------------------------------------------------------------------===#
+
+import fileinput
+import re
+import sys
+
+for line in sys.stdin.readlines():
+  # The format is:
+  # <file>:<start_line>:<start_column>:<end_line>:<end_column>:<replacement>
+  # FIXME: This currently does not support files with colons, we'll need to
+  # figure out a format when we implement more refactoring support.
+  match = re.match(r'(.*):(\d+):(\d+):(\d+):(\d+):(.*)$', line)
+  if match is not None:
+    file_name = match.group(1)
+    start_line, start_column = int(match.group(2)), int(match.group(3))
+    end_line, end_column = int(match.group(4)), int(match.group(5))
+    replacement = match.group(6)
+    if start_line != end_line:
+      print ('Skipping match "%s": only single line ' +
+             'replacements are supported') % line.strip()
+      continue
+    try:
+      replace_file = fileinput.input(file_name, inplace=1)
+      for replace_line in replace_file:
+        # FIXME: Looping over the file for each replacement is both inefficient
+        # and incorrect if replacements add or remove lines.
+        if replace_file.lineno() == start_line:
+          sys.stdout.write(replace_line[:start_column-1] + replacement +
+                           replace_line[end_column:])
+        else:
+          sys.stdout.write(replace_line)
+    except OSError, e:
+      print 'Cannot open %s for editing' % file_name

Propchange: cfe/trunk/examples/Tooling/replace.py
------------------------------------------------------------------------------
    svn:executable = *

Added: cfe/trunk/include/clang/Tooling/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/ASTMatchers.h?rev=132374&view=auto
==============================================================================
--- cfe/trunk/include/clang/Tooling/ASTMatchers.h (added)
+++ cfe/trunk/include/clang/Tooling/ASTMatchers.h Tue May 31 18:49:32 2011
@@ -0,0 +1,1736 @@
+//===--- ASTMatchers.h - Structural query framework -------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements a framework of AST matchers that can be used to express
+//  structural queries on the AST representing C++ code.
+//
+//  The general idea is to construct a matcher expression that describes a
+//  subtree match on the AST. Next, a callback that is executed every time the
+//  expression matches is registered, and the matcher is run over the AST of
+//  some code. Matched subexpressions can be bound to string IDs and easily
+//  be accessed from the registered callback. The callback can than use the
+//  AST nodes that the subexpressions matched on to output information about
+//  the match or construct changes that can be applied to the code.
+//
+//  Example:
+//  class HandleMatch : public clang::tooling::MatchFinder::MatchCallback {
+//   public:
+//    virtual void Run(const clang::tooling::MatchFinder::MatchResult &Result) {
+//      const clang::CXXRecordDecl *Class =
+//          Result.Nodes.GetDeclAs<clang::CXXRecordDecl>("id");
+//      ...
+//    }
+//  };
+//
+//  int main(int argc, char **argv) {
+//    ClangTool Tool(argc, argv);
+//    MatchFinder finder;
+//    finder.AddMatcher(Id("id", Class(HasName("::a_namespace::AClass"))),
+//                      new HandleMatch);
+//    return Tool.Run(finder.NewFrontendActionFactory());
+//  }
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_AST_MATCHERS_H
+#define LLVM_CLANG_TOOLING_AST_MATCHERS_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Tooling/VariadicFunction.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/type_traits.h"
+#include <assert.h>
+#include <stdint.h>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+/// FIXME: Move into the llvm support library.
+template <bool> struct CompileAssert {};
+#define COMPILE_ASSERT(Expr, Msg) \
+  typedef CompileAssert<(bool(Expr))> Msg[bool(Expr) ? 1 : -1]
+
+namespace clang {
+
+class FrontendAction;
+class SourceManager;
+
+namespace tooling {
+
+class FrontendActionFactory;
+class BoundNodesBuilder;
+
+/// Contains a mapping from IDs to nodes bound to those IDs and provides
+/// convenient access to those nodes.
+class BoundNodes {
+ public:
+  BoundNodes() {}
+
+  /// Create BoundNodes from a pre-filled map of bindings.
+  BoundNodes(const std::map<std::string, const clang::Decl*> &DeclBindings,
+             const std::map<std::string, const clang::Stmt*> &StmtBindings)
+      : DeclBindings(DeclBindings), StmtBindings(StmtBindings) {}
+
+  /// Returns the node bound to the specified id if the id was bound to a node
+  /// and that node can be converted into the specified type. Returns NULL
+  /// otherwise.
+  /// FIXME: We'll need one of those for every base type.
+  template <typename T>
+  const T *GetDeclAs(const std::string &ID) const {
+    return GetNodeAs<T>(DeclBindings, ID);
+  }
+  template <typename T>
+  const T *GetStmtAs(const std::string &ID) const {
+    return GetNodeAs<T>(StmtBindings, ID);
+  }
+
+  /// Adds all bound nodes to bound_nodes_builder.
+  void CopyTo(BoundNodesBuilder *CopyToBuilder) const;
+
+ private:
+  template <typename T, typename MapT>
+  const T *GetNodeAs(const MapT &Bindings, const std::string &ID) const {
+    typename MapT::const_iterator It = Bindings.find(ID);
+    if (It == Bindings.end()) {
+      return NULL;
+    }
+    return llvm::dyn_cast<T>(It->second);
+  }
+
+  std::map<std::string, const clang::Decl*> DeclBindings;
+  std::map<std::string, const clang::Stmt*> StmtBindings;
+};  // class BoundNodes
+
+/// Creates BoundNodes objects.
+class BoundNodesBuilder {
+ public:
+  BoundNodesBuilder() {}
+
+  /// Add a binding from 'ID' to 'Node'.
+  /// FIXME: Add overloads for all AST base types.
+  void SetBinding(const std::string &ID, const clang::Decl *Node) {
+    DeclBindings[ID] = Node;
+  }
+  void SetBinding(const std::string &ID, const clang::Stmt *Node) {
+    StmtBindings[ID] = Node;
+  }
+
+  /// Returns a BoundNodes object containing all current bindings.
+  BoundNodes Build() const {
+    return BoundNodes(DeclBindings, StmtBindings);
+  }
+
+ private:
+  BoundNodesBuilder(const BoundNodesBuilder&);  // DO NOT IMPLEMENT
+  void operator=(const BoundNodesBuilder&);  // DO NOT IMPLEMENT
+
+  std::map<std::string, const clang::Decl*> DeclBindings;
+  std::map<std::string, const clang::Stmt*> StmtBindings;
+};
+
+inline void BoundNodes::CopyTo(BoundNodesBuilder *CopyToBuilder) const {
+  for (std::map<std::string, const clang::Decl*>::const_iterator
+           It = DeclBindings.begin(), End = DeclBindings.end();
+       It != End; ++It) {
+    CopyToBuilder->SetBinding(It->first, It->second);
+  }
+  /// FIXME: Pull out method.
+  for (std::map<std::string, const clang::Stmt*>::const_iterator
+           It = StmtBindings.begin(), End = StmtBindings.end();
+       It != End; ++It) {
+    CopyToBuilder->SetBinding(It->first, It->second);
+  }
+}
+
+class ASTMatchFinder;
+
+/// Generic interface for matchers on an AST node of type T. Implement
+/// this if your matcher may need to inspect the children or
+/// descendants of the node or bind matched nodes to names. If you are
+/// writing a simple matcher that only inspects properties of the
+/// current node and doesn't care about its children or descendants,
+/// implement SingleNodeMatcherInterface instead.
+template <typename T>
+class MatcherInterface : public llvm::RefCountedBaseVPTR {
+ public:
+  virtual ~MatcherInterface() {}
+
+  /// Returns true if 'Node' can be matched.
+  /// May bind 'Node' to an ID via 'Builder', or recurse into
+  /// the AST via 'Finder'.
+  virtual bool Matches(
+      const T &Node,
+      ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const = 0;
+};
+
+/// Interface for matchers that only evaluate properties on a single node.
+template <typename T>
+class SingleNodeMatcherInterface : public MatcherInterface<T> {
+ public:
+  /// Returns true if the matcher matches the provided node. A subclass
+  /// must implement this instead of Matches().
+  virtual bool MatchesNode(const T &Node) const = 0;
+
+ private:
+  /// Implements MatcherInterface::Matches.
+  virtual bool Matches(const T &Node,
+                       ASTMatchFinder * /* Finder */,
+                       BoundNodesBuilder * /*  Builder */) const {
+    return MatchesNode(Node);
+  }
+};
+
+/// Wrapper of a MatcherInterface<T> *that allows copying.
+///
+/// A Matcher<Base> can be used anywhere a Matcher<Derived> is
+/// required. This establishes an is-a relationship which is reverse
+/// to the AST hierarchy. In other words, Matcher<T> is contravariant
+/// with respect to T. The relationship is built via a type conversion
+/// operator rather than a type hierarchy to be able to templatize the
+/// type hierarchy instead of spelling it out.
+template <typename T>
+class Matcher {
+ public:
+  /// Takes ownership of the provided implementation pointer.
+  explicit Matcher(MatcherInterface<T> *Implementation)
+      : Implementation(Implementation) {}
+
+  /// Forwards the call to the underlying MatcherInterface<T> pointer.
+  bool Matches(
+      const T &Node,
+      ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const {
+    return Implementation->Matches(Node, Finder, Builder);
+  }
+
+  /// Implicitly converts this object to a Matcher<Derived>; requires
+  /// Derived to be derived from T.
+  template <typename Derived>
+  operator Matcher<Derived>() const {
+    return Matcher<Derived>(new ImplicitCastMatcher<Derived>(*this));
+  }
+
+  /// Returns an ID that uniquely identifies the matcher.
+  uint64_t GetID() const {
+    /// FIXME: Document the requirements this imposes on matcher
+    /// implementations (no new() implementation_ during a Matches()).
+    return reinterpret_cast<uint64_t>(Implementation.getPtr());
+  }
+
+ private:
+  /// Allows conversion from Matcher<T> to Matcher<Derived> if Derived
+  /// is derived from T.
+  template <typename Derived>
+  class ImplicitCastMatcher : public MatcherInterface<Derived> {
+   public:
+    explicit ImplicitCastMatcher(const Matcher<T> &From)
+        : From(From) {}
+
+    virtual bool Matches(
+        const Derived &Node,
+        ASTMatchFinder *Finder,
+        BoundNodesBuilder *Builder) const {
+      return From.Matches(Node, Finder, Builder);
+    }
+
+   private:
+    const Matcher<T> From;
+  };
+
+  llvm::IntrusiveRefCntPtr< MatcherInterface<T> > Implementation;
+};  // class Matcher
+
+/// A convenient helper for creating a Matcher<T> without specifying
+/// the template type argument.
+template <typename T>
+inline Matcher<T> MakeMatcher(MatcherInterface<T> *Implementation) {
+  return Matcher<T>(Implementation);
+}
+
+/// Matches declarations for QualType and CallExpr. Type argument
+/// DeclMatcherT is required by PolymorphicMatcherWithParam1 but not
+/// actually used.
+template <typename T, typename DeclMatcherT>
+class HasDeclarationMatcher : public MatcherInterface<T> {
+  COMPILE_ASSERT((llvm::is_same< DeclMatcherT, Matcher<clang::Decl> >::value),
+                 instantiated_with_wrong_types);
+ public:
+  explicit HasDeclarationMatcher(const Matcher<clang::Decl> &InnerMatcher)
+      : InnerMatcher(InnerMatcher) {}
+
+  virtual bool Matches(
+      const T &Node,
+      ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const {
+    return MatchesSpecialized(Node, Finder, Builder);
+  }
+
+ private:
+  /// Extracts the CXXRecordDecl of a QualType and returns whether the inner
+  /// matcher matches on it.
+  bool MatchesSpecialized(
+      const clang::QualType &Node, ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const {
+    /// FIXME: Add other ways to convert...
+    clang::CXXRecordDecl *NodeAsRecordDecl = Node->getAsCXXRecordDecl();
+    return NodeAsRecordDecl != NULL &&
+        InnerMatcher.Matches(*NodeAsRecordDecl, Finder, Builder);
+  }
+
+  /// Extracts the Decl of the callee of a CallExpr and returns whether the
+  /// inner matcher matches on it.
+  bool MatchesSpecialized(
+      const clang::CallExpr &Node, ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const {
+    const clang::Decl *NodeAsDecl = Node.getCalleeDecl();
+    return NodeAsDecl != NULL &&
+        InnerMatcher.Matches(*NodeAsDecl, Finder, Builder);
+  }
+
+  /// Extracts the Decl of the constructor call and returns whether the inner
+  /// matcher matches on it.
+  bool MatchesSpecialized(
+      const clang::CXXConstructExpr &Node, ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const {
+    const clang::Decl *NodeAsDecl = Node.getConstructor();
+    return NodeAsDecl != NULL &&
+        InnerMatcher.Matches(*NodeAsDecl, Finder, Builder);
+  }
+
+  const Matcher<clang::Decl> InnerMatcher;
+};
+
+/// IsBaseType<T>::value is true if T is a "base" type in the AST
+/// node class hierarchies (i.e. if T is Decl, Stmt, or QualType).
+template <typename T>
+struct IsBaseType {
+  static const bool value = (llvm::is_same<T, clang::Decl>::value ||
+                             llvm::is_same<T, clang::Stmt>::value ||
+                             llvm::is_same<T, clang::QualType>::value);
+};
+template <typename T>
+const bool IsBaseType<T>::value;
+
+/// Interface that can match any AST base node type and contains default
+/// implementations returning false.
+class UntypedBaseMatcher {
+ public:
+  virtual ~UntypedBaseMatcher() {}
+
+  virtual bool Matches(
+      const clang::Decl &DeclNode, ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const {
+    return false;
+  }
+  virtual bool Matches(
+      const clang::QualType &TypeNode, ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const {
+    return false;
+  }
+  virtual bool Matches(
+      const clang::Stmt &StmtNode, ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const {
+    return false;
+  }
+
+  /// Returns a unique ID for the matcher.
+  virtual uint64_t GetID() const = 0;
+};
+
+/// An UntypedBaseMatcher that overwrites the Matches(...) method for node
+/// type T. T must be an AST base type.
+template <typename T>
+class TypedBaseMatcher : public UntypedBaseMatcher {
+  COMPILE_ASSERT(IsBaseType<T>::value,
+                 typed_base_matcher_can_only_be_used_with_base_type);
+ public:
+  explicit TypedBaseMatcher(const Matcher<T> &InnerMatcher)
+      : InnerMatcher(InnerMatcher) {}
+
+  using UntypedBaseMatcher::Matches;
+  /// Implements UntypedBaseMatcher::Matches. Since T is guaranteed to
+  /// be a "base" AST node type, this method is guaranteed to override
+  /// one of the Matches() methods from UntypedBaseMatcher.
+  virtual bool Matches(const T &Node,
+                       ASTMatchFinder *Finder,
+                       BoundNodesBuilder *Builder) const {
+    return InnerMatcher.Matches(Node, Finder, Builder);
+  }
+
+  /// Implements UntypedBaseMatcher::GetID.
+  virtual uint64_t GetID() const {
+    return InnerMatcher.GetID();
+  }
+
+ private:
+  Matcher<T> InnerMatcher;
+};
+
+/// Interface that allows matchers to traverse the AST.
+/// This provides two entry methods for each base node type in the AST:
+/// - MatchesChildOf:
+///   Matches a matcher on every child node of the given node. Returns true
+///   if at least one child node could be matched.
+/// - MatchesDescendantOf:
+///   Matches a matcher on all descendant nodes of the given node. Returns true
+///   if at least one descendant matched.
+class ASTMatchFinder {
+ public:
+  /// Defines how we descend a level in the AST when we pass
+  /// through expressions.
+  enum TraversalMethod {
+    /// Will traverse any child nodes.
+    kAsIs,
+    /// Will not traverse implicit casts and parentheses.
+    kIgnoreImplicitCastsAndParentheses
+  };
+
+  virtual ~ASTMatchFinder() {}
+
+  /// Returns true if the given class is directly or indirectly derived
+  /// from a base type with the given name.  A class is considered to
+  /// be also derived from itself.
+  virtual bool ClassIsDerivedFrom(const clang::CXXRecordDecl *Declaration,
+                                  const std::string &BaseName) const = 0;
+
+  // FIXME: Implement for other base nodes.
+  virtual bool MatchesChildOf(const clang::Decl &DeclNode,
+                              const UntypedBaseMatcher &BaseMatcher,
+                              BoundNodesBuilder *Builder,
+                              TraversalMethod Traverse) = 0;
+  virtual bool MatchesChildOf(const clang::Stmt &StmtNode,
+                              const UntypedBaseMatcher &BaseMatcher,
+                              BoundNodesBuilder *Builder,
+                              TraversalMethod Traverse) = 0;
+
+  virtual bool MatchesDescendantOf(const clang::Decl &DeclNode,
+                                   const UntypedBaseMatcher &BaseMatcher,
+                                   BoundNodesBuilder *Builder) = 0;
+  virtual bool MatchesDescendantOf(const clang::Stmt &StmtNode,
+                                   const UntypedBaseMatcher &BaseMatcher,
+                                   BoundNodesBuilder *Builder) = 0;
+};
+
+/// Converts a Matcher<T> to a matcher of desired type To by "adapting"
+/// a To into a T. The ArgumentAdapterT argument specifies how the
+/// adaptation is done. For example:
+///
+///   ArgumentAdaptingMatcher<DynCastMatcher, T>(InnerMatcher);
+/// returns a matcher that can be used where a Matcher<To> is required, if
+/// To and T are in the same type hierarchy, and thus dyn_cast can be
+/// called to convert a To to a T.
+///
+/// FIXME: Make sure all our applications of this class actually require
+/// knowledge about the inner type. DynCastMatcher obviously does, but the
+/// Has *matchers require the inner type solely for COMPILE_ASSERT purposes.
+template <template <typename ToArg, typename FromArg> class ArgumentAdapterT,
+          typename T>
+class ArgumentAdaptingMatcher {
+ public:
+  explicit ArgumentAdaptingMatcher(const Matcher<T> &InnerMatcher)
+      : InnerMatcher(InnerMatcher) {}
+
+  template <typename To>
+  operator Matcher<To>() const {
+    return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher));
+  }
+
+ private:
+  const Matcher<T> InnerMatcher;
+};
+
+/// A PolymorphicMatcherWithParamN<MatcherT, P1, ..., PN> object can be
+/// created from N parameters p1, ..., pN (of type P1, ..., PN) and
+/// used as a Matcher<T> where a MatcherT<T, P1, ..., PN>(p1, ..., pN)
+/// can be constructed.
+///
+/// For example:
+/// - PolymorphicMatcherWithParam0<IsDefinitionMatcher>()
+///   creates an object that can be used as a Matcher<T> for any type T
+///   where an IsDefinitionMatcher<T>() can be constructed.
+/// - PolymorphicMatcherWithParam1<ValueEqualsMatcher, int>(42)
+///   creates an object that can be used as a Matcher<T> for any type T
+///   where a ValueEqualsMatcher<T, int>(42) can be constructed.
+template <template <typename T> class MatcherT>
+class PolymorphicMatcherWithParam0 {
+ public:
+  template <typename T>
+  operator Matcher<T>() const {
+    return Matcher<T>(new MatcherT<T>());
+  }
+};
+
+template <template <typename T, typename P1> class MatcherT,
+          typename P1>
+class PolymorphicMatcherWithParam1 {
+ public:
+  explicit PolymorphicMatcherWithParam1(const P1 &Param1)
+      : Param1(Param1) {}
+
+  template <typename T>
+  operator Matcher<T>() const {
+    return Matcher<T>(new MatcherT<T, P1>(Param1));
+  }
+
+ private:
+  const P1 Param1;
+};
+
+template <template <typename T, typename P1, typename P2> class MatcherT,
+          typename P1, typename P2>
+class PolymorphicMatcherWithParam2 {
+ public:
+  PolymorphicMatcherWithParam2(const P1 &Param1, const P2 &Param2)
+      : Param1(Param1), Param2(Param2) {}
+
+  template <typename T>
+  operator Matcher<T>() const {
+    return Matcher<T>(new MatcherT<T, P1, P2>(Param1, Param2));
+  }
+
+ private:
+  const P1 Param1;
+  const P2 Param2;
+};
+
+// FIXME: Alternatively we could also create a IsAMatcher or something
+// that checks that a dyn_cast is possible. This is purely needed for the
+// difference between calling for example:
+//   Class()
+// and
+//   Class(SomeMatcher)
+// In the second case we need the correct type we were dyn_cast'ed to in order
+// to get the right type for the inner matcher. In the first case we don't need
+// that, but we use the type conversion anyway and insert a TrueMatcher.
+template <typename T>
+class TrueMatcher : public SingleNodeMatcherInterface<T>  {
+ public:
+  virtual bool MatchesNode(const T &Node) const {
+    return true;
+  }
+};
+
+/// Provides a MatcherInterface<T> for a Matcher<To> that matches if T is
+/// dyn_cast'able into To and the given Matcher<To> matches on the dyn_cast'ed
+/// node.
+template <typename T, typename To>
+class DynCastMatcher : public MatcherInterface<T> {
+ public:
+  explicit DynCastMatcher(const Matcher<To> &InnerMatcher)
+      : InnerMatcher(InnerMatcher) {}
+
+  virtual bool Matches(const T &Node,
+                       ASTMatchFinder *Finder,
+                       BoundNodesBuilder *Builder) const {
+    const To *InnerMatchValue = llvm::dyn_cast<To>(&Node);
+    return InnerMatchValue != NULL &&
+        InnerMatcher.Matches(*InnerMatchValue, Finder, Builder);
+  }
+
+ private:
+  const Matcher<To> InnerMatcher;
+};
+
+/// Enables the user to pass a Matcher<clang::CXXMemberCallExpr> to Call().
+/// FIXME: Alternatives are using more specific methods than Call, like
+/// MemberCall, or not using VariadicFunction for Call and overloading it.
+template <>
+template <>
+inline Matcher<clang::CXXMemberCallExpr>::
+operator Matcher<clang::CallExpr>() const {
+  return MakeMatcher(
+      new DynCastMatcher<clang::CallExpr, clang::CXXMemberCallExpr>(*this));
+}
+
+/// Matcher<T> that wraps an inner Matcher<T> and binds the matched node to
+/// an ID if the inner matcher matches on the node.
+template <typename T>
+class IdMatcher : public MatcherInterface<T> {
+ public:
+  /// Creates an IdMatcher that binds to 'ID' if 'InnerMatcher' matches the node.
+  IdMatcher(const std::string &ID, const Matcher<T> &InnerMatcher)
+      : ID(ID), InnerMatcher(InnerMatcher) {}
+
+  virtual bool Matches(
+      const T &Node,
+      ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const {
+    bool Result = InnerMatcher.Matches(Node, Finder, Builder);
+    if (Result) {
+      Builder->SetBinding(ID, &Node);
+    }
+    return Result;
+  }
+
+ private:
+  const std::string ID;
+  const Matcher<T> InnerMatcher;
+};
+
+/// Matches nodes of type T that have child nodes of type ChildT for
+/// which a specified child matcher matches. ChildT must be an AST base
+/// type.
+template <typename T, typename ChildT>
+class HasMatcher : public MatcherInterface<T> {
+  COMPILE_ASSERT(IsBaseType<ChildT>::value, has_only_accepts_base_type_matcher);
+ public:
+  explicit HasMatcher(const Matcher<ChildT> &ChildMatcher)
+      : ChildMatcher(ChildMatcher) {}
+
+  virtual bool Matches(const T &Node,
+                       ASTMatchFinder *Finder,
+                       BoundNodesBuilder *Builder) const {
+    return Finder->MatchesChildOf(
+        Node, ChildMatcher, Builder,
+        ASTMatchFinder::kIgnoreImplicitCastsAndParentheses);
+  }
+
+ private:
+  const TypedBaseMatcher<ChildT> ChildMatcher;
+};
+
+/// Matches nodes of type T if the given Matcher<T> does not match.
+/// Type argument MatcherT is required by PolymorphicMatcherWithParam1
+/// but not actually used. It will always be instantiated with a type
+/// convertible to Matcher<T>.
+template <typename T, typename MatcherT>
+class NotMatcher : public MatcherInterface<T> {
+ public:
+  explicit NotMatcher(const Matcher<T> &InnerMatcher)
+      : InnerMatcher(InnerMatcher) {}
+
+  virtual bool Matches(
+      const T &Node,
+      ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const {
+    return !InnerMatcher.Matches(Node, Finder, Builder);
+  }
+
+ private:
+  const Matcher<T> InnerMatcher;
+};
+
+/// Matches nodes of type T for which both provided matchers
+/// match. Type arguments MatcherT1 and MatcherT2 are required by
+/// PolymorphicMatcherWithParam2 but not actually used. They will
+/// always be instantiated with types convertible to Matcher<T>.
+template <typename T, typename MatcherT1, typename MatcherT2>
+class AllOfMatcher : public MatcherInterface<T> {
+ public:
+  AllOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2)
+      : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {}
+
+  virtual bool Matches(
+      const T &Node,
+      ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const {
+    return InnerMatcher1.Matches(Node, Finder, Builder) &&
+           InnerMatcher2.Matches(Node, Finder, Builder);
+  }
+
+ private:
+  const Matcher<T> InnerMatcher1;
+  const Matcher<T> InnerMatcher2;
+};
+
+/// Matches nodes of type T for which at least one of the two provided
+/// matchers matches. Type arguments MatcherT1 and MatcherT2 are
+/// required by PolymorphicMatcherWithParam2 but not actually
+/// used. They will always be instantiated with types convertible to
+/// Matcher<T>.
+template <typename T, typename MatcherT1, typename MatcherT2>
+class AnyOfMatcher : public MatcherInterface<T> {
+ public:
+  AnyOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2)
+      : InnerMatcher1(InnerMatcher1), InnertMatcher2(InnerMatcher2) {}
+
+  virtual bool Matches(
+      const T &Node,
+      ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const {
+    return InnerMatcher1.Matches(Node, Finder, Builder) ||
+           InnertMatcher2.Matches(Node, Finder, Builder);
+  }
+
+ private:
+  const Matcher<T> InnerMatcher1;
+  const Matcher<T> InnertMatcher2;
+};
+
+/// Creates a Matcher<T> that matches if
+/// T is dyn_cast'able into InnerT and all inner matchers match.
+template<typename T, typename InnerT>
+Matcher<T> MakeDynCastAllOfComposite(
+    const Matcher<InnerT> *const InnerMatchers[], int Count) {
+  if (Count == 0) {
+    return ArgumentAdaptingMatcher<DynCastMatcher, InnerT>(
+        MakeMatcher(new TrueMatcher<InnerT>));
+  }
+  Matcher<InnerT> InnerMatcher = *InnerMatchers[Count-1];
+  for (int I = Count-2; I >= 0; --I) {
+    InnerMatcher = MakeMatcher(
+        new AllOfMatcher<InnerT, Matcher<InnerT>, Matcher<InnerT> >(
+            *InnerMatchers[I], InnerMatcher));
+  }
+  return ArgumentAdaptingMatcher<DynCastMatcher, InnerT>(InnerMatcher);
+}
+
+/// Matches nodes of type T that have at least one descendant node of
+/// type DescendantT for which the given inner matcher matches.
+/// DescendantT must be an AST base type.
+template <typename T, typename DescendantT>
+class HasDescendantMatcher : public MatcherInterface<T> {
+  COMPILE_ASSERT(IsBaseType<DescendantT>::value,
+                 has_descendant_only_accepts_base_type_matcher);
+ public:
+  explicit HasDescendantMatcher(const Matcher<DescendantT> &DescendantMatcher)
+      : DescendantMatcher(DescendantMatcher) {}
+
+  virtual bool Matches(
+      const T &Node,
+      ASTMatchFinder *Finder,
+      BoundNodesBuilder *Builder) const {
+    return Finder->MatchesDescendantOf(
+        Node, DescendantMatcher, Builder);
+  }
+
+ private:
+  const TypedBaseMatcher<DescendantT> DescendantMatcher;
+};
+
+/// Matches on nodes that have a getValue() method if getValue() equals the
+/// value the ValueEqualsMatcher was constructed with.
+template <typename T, typename ValueT>
+class ValueEqualsMatcher : public SingleNodeMatcherInterface<T> {
+  COMPILE_ASSERT((llvm::is_base_of<clang::CharacterLiteral, T>::value) ||
+                 (llvm::is_base_of<clang::CXXBoolLiteralExpr, T>::value) ||
+                 (llvm::is_base_of<clang::FloatingLiteral, T>::value) ||
+                 (llvm::is_base_of<clang::IntegerLiteral, T>::value),
+                 the_node_must_have_a_getValue_method);
+ public:
+  explicit ValueEqualsMatcher(const ValueT &ExpectedValue)
+      : ExpectedValue(ExpectedValue) {}
+
+  virtual bool MatchesNode(const T &Node) const {
+    return Node.getValue() == ExpectedValue;
+  }
+
+ private:
+  const ValueT ExpectedValue;
+};
+
+template <typename T>
+class IsDefinitionMatcher : public SingleNodeMatcherInterface<T> {
+  COMPILE_ASSERT((llvm::is_base_of<clang::TagDecl, T>::value) ||
+                 (llvm::is_base_of<clang::VarDecl, T>::value) ||
+                 (llvm::is_base_of<clang::FunctionDecl, T>::value),
+                 is_definition_requires_isThisDeclarationADefinition_method);
+ public:
+  virtual bool MatchesNode(const T &Node) const {
+    return Node.isThisDeclarationADefinition();
+  }
+};
+
+class IsArrowMatcher : public SingleNodeMatcherInterface<clang::MemberExpr> {
+ public:
+  virtual bool MatchesNode(const clang::MemberExpr &Node) const {
+    return Node.isArrow();
+  }
+};
+
+/// A VariadicDynCastAllOfMatcher<SourceT, TargetT> object is a
+/// variadic functor that takes a list of Matcher<TargetT> and returns
+/// a Matcher<SourceT> that dyn_casts its argument to TargetT.
+template <typename SourceT, typename TargetT>
+class VariadicDynCastAllOfMatcher
+    : public internal::VariadicFunction<
+        Matcher<SourceT>, Matcher<TargetT>,
+        MakeDynCastAllOfComposite<SourceT, TargetT> > {
+ public:
+  VariadicDynCastAllOfMatcher() {}
+};
+
+/// AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) { ... }
+///
+/// defines a single-parameter function named DefineMatcher() that returns a
+/// Matcher<Type> object. The code between the curly braces has access
+/// to the following variables:
+///
+///   Node:                  the AST node being matched; its type is Type.
+///   Param:                 the parameter passed to the function; its type
+///                          is ParamType.
+///   Finder:                an ASTMatchFinder*.
+///   Builder:               a BoundNodesBuilder*.
+///
+/// The code should return true if 'Node' matches.
+#define AST_MATCHER_P(Type, DefineMatcher, ParamType, Param)                  \
+  class matcher_internal_##DefineMatcher##Matcher                             \
+      : public MatcherInterface<Type> {                                       \
+   public:                                                                    \
+    explicit matcher_internal_##DefineMatcher##Matcher(                       \
+        const ParamType &A##Param) : Param(A##Param) {}                       \
+    virtual bool Matches(                                                     \
+        const Type &Node, ASTMatchFinder *Finder,                             \
+        BoundNodesBuilder *Builder) const;                                    \
+   private:                                                                   \
+    const ParamType Param;                                                    \
+  };                                                                          \
+  inline Matcher<Type> DefineMatcher(const ParamType &Param) {                \
+    return MakeMatcher(new matcher_internal_##DefineMatcher##Matcher(Param)); \
+  }                                                                           \
+  inline bool matcher_internal_##DefineMatcher##Matcher::Matches(             \
+      const Type &Node, ASTMatchFinder *Finder,                               \
+      BoundNodesBuilder *Builder) const
+
+/// AST_MATCHER_P2(Type, DefineMatcher, ParamType1, Param1, ParamType2, Param2)
+/// { ... }
+///
+/// defines a two-parameter function named DefineMatcher() that returns a
+/// Matcher<Type> object. The code between the curly braces has access
+/// to the following variables:
+///
+///   Node:                  the AST node being matched; its type is Type.
+///   Param1, Param2:        the parameters passed to the function; their types
+///                          are ParamType1 and ParamType2.
+///   Finder:                an ASTMatchFinder*.
+///   Builder:               a BoundNodesBuilder*.
+///
+/// The code should return true if 'Node' matches.
+#define AST_MATCHER_P2(                                                        \
+    Type, DefineMatcher, ParamType1, Param1, ParamType2, Param2)               \
+  class matcher_internal_##DefineMatcher##Matcher                              \
+      : public MatcherInterface<Type> {                                        \
+   public:                                                                     \
+    matcher_internal_##DefineMatcher##Matcher(                                 \
+        const ParamType1 &A##Param1, const ParamType2 &A##Param2)              \
+        : Param1(A##Param1), Param2(A##Param2) {}                              \
+    virtual bool Matches(                                                      \
+        const Type &Node, ASTMatchFinder *Finder,                              \
+        BoundNodesBuilder *Builder) const;                                     \
+   private:                                                                    \
+    const ParamType1 Param1;                                                   \
+    const ParamType2 Param2;                                                   \
+  };                                                                           \
+  inline Matcher<Type> DefineMatcher(                                          \
+      const ParamType1 &Param1, const ParamType2 &Param2) {                    \
+    return MakeMatcher(new matcher_internal_##DefineMatcher##Matcher(          \
+        Param1, Param2));                                                      \
+  }                                                                            \
+  inline bool matcher_internal_##DefineMatcher##Matcher::Matches(              \
+      const Type &Node, ASTMatchFinder *Finder,                                \
+      BoundNodesBuilder *Builder) const
+
+/// AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) { ... }
+///
+/// defines a single-parameter function named DefineMatcher() that is
+/// polymorphic in the return type. The variables are the same as for
+/// AST_MATCHER_P, with the addition of NodeType, which specifies the node type
+/// of the matcher Matcher<NodeType> returned by the function matcher().
+///
+/// FIXME: Pull out common code with above macro?
+#define AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param)             \
+  template <typename NodeType, typename ParamT>                                \
+  class matcher_internal_##DefineMatcher##Matcher                              \
+      : public MatcherInterface<NodeType> {                                    \
+   public:                                                                     \
+    explicit matcher_internal_##DefineMatcher##Matcher(                        \
+        const ParamType &A##Param) : Param(A##Param) {}                        \
+    virtual bool Matches(                                                      \
+        const NodeType &Node, ASTMatchFinder *Finder,                          \
+        BoundNodesBuilder *Builder) const;                                     \
+   private:                                                                    \
+    const ParamType Param;                                                     \
+  };                                                                           \
+  inline PolymorphicMatcherWithParam1<                                         \
+      matcher_internal_##DefineMatcher##Matcher,                               \
+      ParamType >                                                              \
+    DefineMatcher(const ParamType &Param) {                                    \
+    return PolymorphicMatcherWithParam1<                                       \
+        matcher_internal_##DefineMatcher##Matcher,                             \
+        ParamType >(Param);                                                    \
+  }                                                                            \
+  template <typename NodeType, typename ParamT>                                \
+  bool matcher_internal_##DefineMatcher##Matcher<NodeType, ParamT>::Matches(   \
+      const NodeType &Node, ASTMatchFinder *Finder,                            \
+      BoundNodesBuilder *Builder) const
+
+/// AST_POLYMORPHIC_MATCHER_P2(
+///     DefineMatcher, ParamType1, Param1, ParamType2, Param2) { ... }
+///
+/// defines a two-parameter function named matcher() that is polymorphic in
+/// the return type. The variables are the same as for AST_MATCHER_P2, with the
+/// addition of NodeType, which specifies the node type of the matcher
+/// Matcher<NodeType> returned by the function DefineMatcher().
+#define AST_POLYMORPHIC_MATCHER_P2(                                            \
+      DefineMatcher, ParamType1, Param1, ParamType2, Param2)                   \
+  template <typename NodeType, typename ParamT1, typename ParamT2>             \
+  class matcher_internal_##DefineMatcher##Matcher                              \
+      : public MatcherInterface<NodeType> {                                    \
+   public:                                                                     \
+    matcher_internal_##DefineMatcher##Matcher(                                 \
+        const ParamType1 &A##Param1, const ParamType2 &A##Param2)              \
+        : Param1(A##Param1), Param2(A##Param2) {}                              \
+    virtual bool Matches(                                                      \
+        const NodeType &Node, ASTMatchFinder *Finder,                          \
+        BoundNodesBuilder *Builder) const;                                     \
+   private:                                                                    \
+    const ParamType1 Param1;                                                   \
+    const ParamType2 Param2;                                                   \
+  };                                                                           \
+  inline PolymorphicMatcherWithParam2<                                         \
+      matcher_internal_##DefineMatcher##Matcher,                               \
+      ParamType1, ParamType2 >                                                 \
+    DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) {        \
+    return PolymorphicMatcherWithParam2<                                       \
+        matcher_internal_##DefineMatcher##Matcher,                             \
+        ParamType1, ParamType2 >(                                              \
+        Param1, Param2);                                                       \
+  }                                                                            \
+  template <typename NodeType, typename ParamT1, typename ParamT2>             \
+  bool matcher_internal_##DefineMatcher##Matcher<                              \
+      NodeType, ParamT1, ParamT2>::Matches(                                    \
+      const NodeType &Node, ASTMatchFinder *Finder,                            \
+      BoundNodesBuilder *Builder) const
+
+namespace match {
+
+typedef Matcher<clang::Decl> DeclarationMatcher;
+typedef Matcher<clang::QualType> TypeMatcher;
+typedef Matcher<clang::Stmt> StatementMatcher;
+
+/// Matches C++ class declarations.
+///
+/// Example matches X, Z
+///   class X;
+///   template<class T> class Z {};
+const VariadicDynCastAllOfMatcher<clang::Decl, clang::CXXRecordDecl> Class;
+
+/// Matches method declarations.
+///
+/// Example matches y
+///   class X { void y() };
+const VariadicDynCastAllOfMatcher<clang::Decl, clang::CXXMethodDecl> Method;
+
+/// Matches variable declarations.
+///
+/// Example matches a
+///   int a;
+const VariadicDynCastAllOfMatcher<clang::Decl, clang::VarDecl> Variable;
+
+/// Matches member expressions.
+///
+/// Given
+///   class Y {
+///     void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; }
+///     int a; static int b;
+///   };
+/// MemberExpression()
+///   matches this->x, x, y.x, a, this->b
+const VariadicDynCastAllOfMatcher<clang::Stmt, clang::MemberExpr>
+MemberExpression;
+
+/// Matches call expressions.
+///
+/// Example matches x.y()
+///   X x;
+///   x.y();
+const VariadicDynCastAllOfMatcher<clang::Stmt, clang::CallExpr> Call;
+
+/// Matches constructor call expressions (including implicit ones).
+///
+/// Example matches string(ptr, n) and ptr within arguments of f
+///     (matcher = ConstructorCall())
+///   void f(const string &a, const string &b);
+///   char *ptr;
+///   int n;
+///   f(string(ptr, n), ptr);
+const VariadicDynCastAllOfMatcher<clang::Stmt, clang::CXXConstructExpr>
+ConstructorCall;
+
+/// Matches the value of a default argument at the call site.
+///
+/// Example matches the CXXDefaultArgExpr placeholder inserted for the
+///     default value of the second parameter in the call expression f(42)
+///     (matcher = DefaultArgument())
+///   void f(int x, int y = 0);
+///   f(42);
+const VariadicDynCastAllOfMatcher<clang::Stmt, clang::CXXDefaultArgExpr>
+DefaultArgument;
+
+/// Matches overloaded operator calls.
+/// Note that if an operator isn't overloaded, it won't match.  Instead, use
+/// BinaryOperator matcher.
+/// Currently it does not match operators such as new delete.
+/// FIXME: figure out why these do not match?
+///
+/// Example matches both operator<<((o << b), c) and operator<<(o, b)
+///     (matcher = OverloadedOperatorCall())
+///   ostream &operator<< (ostream &out, int i) { };
+///   ostream &o; int b = 1, c = 1;
+///   o << b << c;
+const VariadicDynCastAllOfMatcher<clang::Stmt, clang::CXXOperatorCallExpr>
+OverloadedOperatorCall;
+
+/// Matches expressions.
+///
+/// Example matches x()
+///   void f() { x(); }
+const VariadicDynCastAllOfMatcher<clang::Stmt, clang::Expr> Expression;
+
+/// Matches expressions that refer to declarations.
+///
+/// Example matches x in if (x)
+///   bool x;
+///   if (x) {}
+const VariadicDynCastAllOfMatcher<clang::Stmt, clang::DeclRefExpr>
+DeclarationReference;
+
+/// Matches if statements.
+///
+/// Example matches 'if (x) {}'
+///   if (x) {}
+const VariadicDynCastAllOfMatcher<clang::Stmt, clang::IfStmt> If;
+
+/// Matches for statements.
+///
+/// Example matches 'for (;;) {}'
+///   for (;;) {}
+const VariadicDynCastAllOfMatcher<clang::Stmt, clang::ForStmt> For;
+
+/// Matches compound statements.
+///
+/// Example matches '{}' and '{{}}'in 'for (;;) {{}}'
+///   for (;;) {{}}
+const VariadicDynCastAllOfMatcher<clang::Stmt, clang::CompoundStmt>
+CompoundStatement;
+
+/// Matches bool literals.
+///
+/// Example matches true
+///   true
+const VariadicDynCastAllOfMatcher<clang::Expr, clang::CXXBoolLiteralExpr>
+BoolLiteral;
+
+/// Matches string literals (also matches wide string literals).
+///
+/// Example matches "abcd", L"abcd"
+///   char *s = "abcd"; wchar_t *ws = L"abcd"
+const VariadicDynCastAllOfMatcher<clang::Expr, clang::StringLiteral>
+StringLiteral;
+
+/// Matches character literals (also matches wchar_t).
+/// Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral),
+/// though.
+///
+/// Example matches 'a', L'a'
+///   char ch = 'a'; wchar_t chw = L'a';
+const VariadicDynCastAllOfMatcher<clang::Expr, clang::CharacterLiteral>
+CharacterLiteral;
+
+/// Matches integer literals of all sizes / encodings.
+/// Not matching character-encoded integers such as L'a'.
+///
+/// Example matches 1, 1L, 0x1, 1U
+const VariadicDynCastAllOfMatcher<clang::Expr, clang::IntegerLiteral>
+IntegerLiteral;
+
+/// Matches binary operator expressions.
+///
+/// Example matches a || b
+///   !(a || b)
+const VariadicDynCastAllOfMatcher<clang::Stmt, clang::BinaryOperator>
+BinaryOperator;
+
+/// Matches unary operator expressions.
+///
+/// Example matches !a
+///   !a || b
+const VariadicDynCastAllOfMatcher<clang::Stmt, clang::UnaryOperator>
+UnaryOperator;
+
+/// Matches conditional operator expressions.
+///
+/// Example matches a ? b : c
+///   (a ? b : c) + 42
+const VariadicDynCastAllOfMatcher<clang::Stmt, clang::ConditionalOperator>
+ConditionalOperator;
+
+template<typename C1, typename C2>
+PolymorphicMatcherWithParam2<AnyOfMatcher, C1, C2>
+AnyOf(const C1 &P1, const C2 &P2) {
+  return PolymorphicMatcherWithParam2< AnyOfMatcher, C1, C2 >(P1, P2);
+}
+
+template<typename C1, typename C2, typename C3>
+PolymorphicMatcherWithParam2<AnyOfMatcher, C1,
+    PolymorphicMatcherWithParam2<AnyOfMatcher, C2, C3> >
+AnyOf(const C1 &P1, const C2 &P2, const C3 &P3) {
+  return AnyOf(P1, AnyOf(P2, P3));
+}
+
+template<typename C1, typename C2, typename C3, typename C4>
+PolymorphicMatcherWithParam2<AnyOfMatcher, C1,
+    PolymorphicMatcherWithParam2<AnyOfMatcher, C2,
+        PolymorphicMatcherWithParam2<AnyOfMatcher, C3, C4> > >
+AnyOf(const C1 &P1, const C2 &P2, const C3 &P3, const C4 &P4) {
+  return AnyOf(P1, AnyOf(P2, AnyOf(P3, P4)));
+}
+
+template<typename C1, typename C2>
+PolymorphicMatcherWithParam2<AllOfMatcher, C1, C2>
+AllOf(const C1 &P1, const C2 &P2) {
+  return PolymorphicMatcherWithParam2<AllOfMatcher, C1, C2>(P1, P2);
+}
+
+/// Matches NamedDecl nodes that have the specified name. Supports specifying
+/// enclosing namespaces or classes by prefixing the name with '<enclosing>::'.
+/// Does not match typedefs of an underlying type with the given name.
+///
+/// Example matches X (name == "X")
+///   class X;
+///
+/// Example matches X (name is one of "::a::b::X", "a::b::X", "b::X", "X")
+/// namespace a { namespace b { class X; } }
+AST_MATCHER_P(clang::NamedDecl, HasName, std::string, Name) {
+  assert(!Name.empty());
+  const std::string FullNameString = "::" + Node.getQualifiedNameAsString();
+  const llvm::StringRef FullName = FullNameString;
+  const llvm::StringRef Pattern = Name;
+  if (Pattern.startswith("::")) {
+    return FullName == Pattern;
+  } else {
+    return FullName.endswith(("::" + Pattern).str());
+  }
+}
+
+/// Matches overloaded operator name given in strings without the "operator"
+/// prefix, such as "<<", for OverloadedOperatorCall's.
+///
+/// Example matches a << b
+///     (matcher == OverloadedOperatorCall(HasOverloadedOperatorName("<<")))
+///   a << b;
+///   c && d;  // assuming both operator<<
+///            // and operator&& are overloaded somewhere.
+AST_MATCHER_P(clang::CXXOperatorCallExpr,
+              HasOverloadedOperatorName, std::string, Name) {
+  return clang::getOperatorSpelling(Node.getOperator()) == Name;
+}
+
+/// Matches C++ classes that are directly or indirectly derived from
+/// the given base class. Note that a class is considered to be also
+/// derived from itself.  The parameter specified the name of the base
+/// type (either a class or a typedef), and does not allow structural
+/// matches for namespaces or template type parameters.
+///
+/// Example matches X, Y, Z, C (base == "X")
+///   class X;                // A class is considered to be derived from itself.
+///   class Y : public X {};  // directly derived
+///   class Z : public Y {};  // indirectly derived
+///   typedef X A;
+///   typedef A B;
+///   class C : public B {};  // derived from a typedef of X
+///
+/// In the following example, Bar matches IsDerivedFrom("X"):
+///   class Foo;
+///   typedef Foo X;
+///   class Bar : public Foo {};  // derived from a type that X is a typedef of
+AST_MATCHER_P(clang::CXXRecordDecl, IsDerivedFrom, std::string, Base) {
+  assert(!Base.empty());
+  return Finder->ClassIsDerivedFrom(&Node, Base);
+}
+
+/// Matches AST nodes that have child AST nodes that match the provided matcher.
+///
+/// Example matches X, Y (matcher = Class(Has(Class(HasName("X")))
+///   class X {};  // Matches X, because X::X is a class of name X inside X.
+///   class Y { class X {}; };
+///   class Z { class Y { class X {}; }; };  // Does not match Z.
+///
+/// ChildT must be an AST base type.
+template <typename ChildT>
+ArgumentAdaptingMatcher<HasMatcher, ChildT> Has(
+    const Matcher<ChildT> &ChildMatcher) {
+  return ArgumentAdaptingMatcher<HasMatcher, ChildT>(ChildMatcher);
+}
+
+/// Matches AST nodes that have descendant AST nodes that match the provided
+/// matcher.
+///
+/// Example matches X, Y, Z (matcher = Class(HasDescendant(Class(HasName("X")))))
+///   class X {};  // Matches X, because X::X is a class of name X inside X.
+///   class Y { class X {}; };
+///   class Z { class Y { class X {}; }; };
+///
+/// DescendantT must be an AST base type.
+template <typename DescendantT>
+ArgumentAdaptingMatcher<HasDescendantMatcher, DescendantT> HasDescendant(
+    const Matcher<DescendantT> &DescendantMatcher) {
+  return ArgumentAdaptingMatcher<HasDescendantMatcher, DescendantT>(
+      DescendantMatcher);
+}
+
+/// Matches if the provided matcher does not match.
+///
+/// Example matches Y (matcher = Class(Not(HasName("X"))))
+///   class X {};
+///   class Y {};
+template <typename M>
+PolymorphicMatcherWithParam1<NotMatcher, M> Not(const M &InnerMatcher) {
+  return PolymorphicMatcherWithParam1<NotMatcher, M>(InnerMatcher);
+}
+
+/// If the provided matcher matches a node, binds the node to 'id'.
+/// FIXME: Add example for accessing it.
+template <typename T>
+Matcher<T> Id(const std::string &ID, const Matcher<T> &InnerMatcher) {
+  return Matcher<T>(new IdMatcher<T>(ID, InnerMatcher));
+}
+
+/// Matches a type if the declaration of the type matches the given matcher.
+inline PolymorphicMatcherWithParam1< HasDeclarationMatcher,
+                                     Matcher<clang::Decl> >
+    HasDeclaration(const Matcher<clang::Decl> &InnerMatcher) {
+  return PolymorphicMatcherWithParam1< HasDeclarationMatcher,
+                                       Matcher<clang::Decl> >(InnerMatcher);
+}
+
+/// Matches on the implicit object argument of a member call expression.
+///
+/// Example matches y.x() (matcher = Call(On(HasType(Class(HasName("Y"))))))
+///   class Y { public: void x(); };
+///   void z() { Y y; y.x(); }",
+///
+/// FIXME: Overload to allow directly matching types?
+AST_MATCHER_P(
+    clang::CXXMemberCallExpr, On, Matcher<clang::Expr>, InnerMatcher) {
+  const clang::Expr *ExprNode = const_cast<clang::CXXMemberCallExpr&>(Node)
+      .getImplicitObjectArgument()
+      ->IgnoreParenImpCasts();
+  return (ExprNode != NULL &&
+          InnerMatcher.Matches(*ExprNode, Finder, Builder));
+}
+
+/// Matches if the call expression's callee expression matches.
+///
+/// Given
+///   class Y { void x() { this->x(); x(); Y y; y.x(); } };
+///   void f() { f(); }
+/// Call(Callee(Expression()))
+///   matches this->x(), x(), y.x(), f()
+/// with Callee(...)
+///   matching this->x, x, y.x, f respectively
+///
+/// Note: Callee cannot take the more general Matcher<clang::Expr> because
+/// this introduces ambiguous overloads with calls to Callee taking a
+/// Matcher<clang::Decl>, as the matcher hierarchy is purely implemented in
+/// terms of implicit casts.
+AST_MATCHER_P(clang::CallExpr, Callee, Matcher<clang::Stmt>, InnerMatcher) {
+  const clang::Expr *ExprNode = Node.getCallee();
+  return (ExprNode != NULL &&
+          InnerMatcher.Matches(*ExprNode, Finder, Builder));
+}
+
+/// Matches if the call expression's callee's declaration matches the given
+/// matcher.
+///
+/// Example matches y.x() (matcher = Call(Callee(Method(HasName("x")))))
+///   class Y { public: void x(); };
+///   void z() { Y y; y.x();
+inline Matcher<clang::CallExpr> Callee(
+    const Matcher<clang::Decl> &InnerMatcher) {
+  return Matcher<clang::CallExpr>(HasDeclaration(InnerMatcher));
+}
+
+/// Matches if the expression's or declaration's type matches a type matcher.
+///
+/// Example matches x (matcher = Expression(HasType(
+///                        HasDeclaration(Class(HasName("X"))))))
+///             and z (matcher = Variable(HasType(
+///                        HasDeclaration(Class(HasName("X"))))))
+///  class X {};
+///  void y(X &x) { x; X z; }
+AST_POLYMORPHIC_MATCHER_P(HasType, Matcher<clang::QualType>, InnerMatcher) {
+  COMPILE_ASSERT((llvm::is_base_of<clang::Expr, NodeType>::value ||
+                  llvm::is_base_of<clang::ValueDecl, NodeType>::value),
+                 instantiated_with_wrong_types);
+  return InnerMatcher.Matches(Node.getType(), Finder, Builder);
+}
+
+/// Overloaded to match the declaration of the expression's or value
+/// declaration's type.
+/// In case of a value declaration (for example a variable declaration),
+/// this resolves one layer of indirection. For example, in the value declaration
+/// "X x;", Class(HasName("X")) matches the declaration of X, while
+/// Variable(HasType(Class(HasName("X")))) matches the declaration of x."
+///
+/// Example matches x (matcher = Expression(HasType(Class(HasName("X")))))
+///             and z (matcher = Variable(HasType(Class(HasName("X")))))
+///  class X {};
+///  void y(X &x) { x; X z; }
+inline PolymorphicMatcherWithParam1<matcher_internal_HasTypeMatcher,
+                                    Matcher<clang::QualType> >
+HasType(const Matcher<clang::Decl> &InnerMatcher) {
+  return HasType(Matcher<clang::QualType>(HasDeclaration(InnerMatcher)));
+}
+
+/// Matches if the matched type is a pointer type and the pointee type matches
+/// the specified matcher.
+///
+/// Example matches y->x()
+///     (matcher = Call(On(HasType(PointsTo(Class(HasName("Y")))))))
+///   class Y { public: void x(); };
+///   void z() { Y *y; y->x(); }
+AST_MATCHER_P(
+    clang::QualType, PointsTo, Matcher<clang::QualType>, InnerMatcher) {
+  return (Node->isPointerType() &&
+          InnerMatcher.Matches(Node->getPointeeType(), Finder, Builder));
+}
+
+/// Overloaded to match the pointee type's declaration.
+inline Matcher<clang::QualType> PointsTo(
+    const Matcher<clang::Decl> &InnerMatcher) {
+  return PointsTo(Matcher<clang::QualType>(HasDeclaration(InnerMatcher)));
+}
+
+/// Matches if the matched type is a reference type and the referenced type
+/// matches the specified matcher.
+///
+/// Example matches X &x and const X &y
+///     (matcher = Variable(HasType(References(Class(HasName("X"))))))
+///   class X {
+///     void a(X b) {
+///       X &x = b;
+///       const X &y = b;
+///   };
+AST_MATCHER_P(
+    clang::QualType, References, Matcher<clang::QualType>, InnerMatcher) {
+  return (Node->isReferenceType() &&
+          InnerMatcher.Matches(Node->getPointeeType(), Finder, Builder));
+}
+
+/// Overloaded to match the referenced type's declaration.
+inline Matcher<clang::QualType> References(
+    const Matcher<clang::Decl> &InnerMatcher) {
+  return References(Matcher<clang::QualType>(HasDeclaration(InnerMatcher)));
+}
+
+AST_MATCHER_P(clang::CXXMemberCallExpr, OnImplicitObjectArgument,
+              Matcher<clang::Expr>, InnerMatcher) {
+  const clang::Expr *ExprNode =
+      const_cast<clang::CXXMemberCallExpr&>(Node).getImplicitObjectArgument();
+  return (ExprNode != NULL &&
+          InnerMatcher.Matches(*ExprNode, Finder, Builder));
+}
+
+/// Matches if the expression's type either matches the specified matcher, or
+/// is a pointer to a type that matches the InnerMatcher.
+inline Matcher<clang::CallExpr> ThisPointerType(
+    const Matcher<clang::QualType> &InnerMatcher) {
+  return OnImplicitObjectArgument(
+      AnyOf(HasType(InnerMatcher), HasType(PointsTo(InnerMatcher))));
+}
+
+/// Overloaded to match the type's declaration.
+inline Matcher<clang::CallExpr> ThisPointerType(
+    const Matcher<clang::Decl> &InnerMatcher) {
+  return OnImplicitObjectArgument(
+      AnyOf(HasType(InnerMatcher), HasType(PointsTo(InnerMatcher))));
+}
+
+/// Matches a DeclRefExpr that refers to a declaration that matches the specified
+/// matcher.
+///
+/// Example matches x in if(x)
+///     (matcher = DeclarationReference(To(Variable(HasName("x")))))
+///   bool x;
+///   if (x) {}
+AST_MATCHER_P(clang::DeclRefExpr, To, Matcher<clang::Decl>, InnerMatcher) {
+  const clang::Decl *DeclNode = Node.getDecl();
+  return (DeclNode != NULL &&
+          InnerMatcher.Matches(*DeclNode, Finder, Builder));
+}
+
+/// Matches a variable declaration that has an initializer expression that
+/// matches the given matcher.
+///
+/// Example matches x (matcher = Variable(HasInitializer(Call())))
+///   bool y() { return true; }
+///   bool x = y();
+AST_MATCHER_P(
+    clang::VarDecl, HasInitializer, Matcher<clang::Expr>, InnerMatcher) {
+  const clang::Expr *Initializer = Node.getAnyInitializer();
+  return (Initializer != NULL &&
+          InnerMatcher.Matches(*Initializer, Finder, Builder));
+}
+
+/// Checks that a call expression or a constructor call expression has
+/// a specific number of arguments (including absent default arguments).
+///
+/// Example matches f(0, 0) (matcher = Call(ArgumentCountIs(2)))
+///   void f(int x, int y);
+///   f(0, 0);
+AST_POLYMORPHIC_MATCHER_P(ArgumentCountIs, unsigned, N) {
+  COMPILE_ASSERT((llvm::is_base_of<clang::CallExpr, NodeType>::value ||
+                  llvm::is_base_of<clang::CXXConstructExpr, NodeType>::value),
+                 instantiated_with_wrong_types);
+  return Node.getNumArgs() == N;
+}
+
+/// Matches the n'th argument of a call expression or a constructor
+/// call expression.
+///
+/// Example matches y in x(y)
+///     (matcher = Call(HasArgument(0, DeclarationReference())))
+///   void x(int) { int y; x(y); }
+AST_POLYMORPHIC_MATCHER_P2(
+    HasArgument, unsigned, N, Matcher<clang::Expr>, InnerMatcher) {
+  COMPILE_ASSERT((llvm::is_base_of<clang::CallExpr, NodeType>::value ||
+                  llvm::is_base_of<clang::CXXConstructExpr, NodeType>::value),
+                 instantiated_with_wrong_types);
+  assert(N >= 0);
+  return (N < Node.getNumArgs() &&
+          InnerMatcher.Matches(
+              *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder));
+}
+
+/// Matches any argument of a call expression or a constructor call expression.
+///
+/// Given
+///   void x(int, int, int) { int y; x(1, y, 42); }
+/// Call(HasAnyArgument(DeclarationReference()))
+///   matches x(1, y, 42)
+/// with HasAnyArgument(...)
+///   matching y
+AST_POLYMORPHIC_MATCHER_P(HasAnyArgument, Matcher<clang::Expr>, InnerMatcher) {
+  COMPILE_ASSERT((llvm::is_base_of<clang::CallExpr, NodeType>::value ||
+                  llvm::is_base_of<clang::CXXConstructExpr, NodeType>::value),
+                  instantiated_with_wrong_types);
+  for (unsigned I = 0; I < Node.getNumArgs(); ++I) {
+    if (InnerMatcher.Matches(*Node.getArg(I)->IgnoreParenImpCasts(),
+                             Finder, Builder)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/// Matches the n'th parameter of a function declaration.
+///
+/// Given
+///   class X { void f(int x) {} };
+/// Method(HasParameter(0, HasType(Variable())))
+///   matches f(int x) {}
+/// with HasParameter(...)
+///   matching int x
+AST_MATCHER_P2(clang::FunctionDecl, HasParameter,
+               unsigned, N, Matcher<clang::ParmVarDecl>, InnerMatcher) {
+  assert(N >= 0);
+  return (N < Node.getNumParams() &&
+          InnerMatcher.Matches(
+              *Node.getParamDecl(N), Finder, Builder));
+}
+
+/// Matches any parameter of a function declaration.
+/// Does not match the 'this' parameter of a method.
+///
+/// Given
+///   class X { void f(int x, int y, int z) {} };
+/// Method(HasAnyParameter(HasName("y")))
+///   matches f(int x, int y, int z) {}
+/// with HasAnyParameter(...)
+///   matching int y
+AST_MATCHER_P(clang::FunctionDecl, HasAnyParameter,
+              Matcher<clang::ParmVarDecl>, InnerMatcher) {
+  for (unsigned I = 0; I < Node.getNumParams(); ++I) {
+    if (InnerMatcher.Matches(*Node.getParamDecl(I), Finder, Builder)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/// Matches the condition expression of an if statement or conditional operator.
+///
+/// Example matches true (matcher = HasCondition(BoolLiteral(Equals(true))))
+///   if (true) {}
+AST_POLYMORPHIC_MATCHER_P(HasCondition, Matcher<clang::Expr>, InnerMatcher) {
+  COMPILE_ASSERT((llvm::is_base_of<clang::IfStmt, NodeType>::value) ||
+                 (llvm::is_base_of<clang::ConditionalOperator,
+                                   NodeType>::value),
+                 has_condition_requires_if_statement_or_conditional_operator);
+  const clang::Expr *const Condition = Node.getCond();
+  return (Condition != NULL &&
+          InnerMatcher.Matches(*Condition, Finder, Builder));
+}
+
+/// Matches a 'for' statement that has a given body.
+///
+/// Given
+///   for (;;) {}
+/// HasBody(CompoundStatement())
+///   matches 'for (;;) {}'
+/// with CompoundStatement()
+///   matching '{}'
+AST_MATCHER_P(clang::ForStmt, HasBody, Matcher<clang::Stmt>, InnerMatcher) {
+  const clang::Stmt *const Statement = Node.getBody();
+  return (Statement != NULL &&
+          InnerMatcher.Matches(*Statement, Finder, Builder));
+}
+
+/// Matches compound statements where at least one substatement matches a
+/// given matcher.
+///
+/// Given
+///   { {}; 1+2; }
+/// HasAnySubstatement(CompoundStatement())
+///   matches '{ {}; 1+2; }'
+/// with CompoundStatement()
+///   matching '{}'
+AST_MATCHER_P(clang::CompoundStmt, HasAnySubstatement,
+              Matcher<clang::Stmt>, InnerMatcher) {
+  for (clang::CompoundStmt::const_body_iterator It = Node.body_begin();
+       It != Node.body_end();
+       ++It) {
+    if (InnerMatcher.Matches(**It, Finder, Builder)) return true;
+  }
+  return false;
+}
+
+/// Checks that a compound statement contains a specific number of child
+/// statements.
+///
+/// Example: Given
+///   { for (;;) {} }
+/// CompoundStatement(StatementCountIs(0)))
+///   matches '{}'
+///   but does not match the outer compound statement.
+AST_MATCHER_P(clang::CompoundStmt, StatementCountIs, unsigned, N) {
+  return Node.size() == N;
+}
+
+/// Matches literals that are equal to the given value.
+///
+/// Example matches true (matcher = BoolLiteral(Equals(true)))
+///   true
+template <typename ValueT>
+PolymorphicMatcherWithParam1<ValueEqualsMatcher, ValueT> Equals(
+    const ValueT &Value) {
+  return PolymorphicMatcherWithParam1<ValueEqualsMatcher, ValueT>(Value);
+}
+
+/// Matches the operator Name of operator expressions (binary or unary).
+///
+/// Example matches a || b (matcher = BinaryOperator(HasOperatorName("||")))
+///   !(a || b)
+AST_POLYMORPHIC_MATCHER_P(HasOperatorName, std::string, Name) {
+  COMPILE_ASSERT(
+      (llvm::is_base_of<clang::BinaryOperator, NodeType>::value) ||
+      (llvm::is_base_of<clang::UnaryOperator, NodeType>::value),
+      has_condition_requires_if_statement_or_conditional_operator);
+  return Name == Node.getOpcodeStr(Node.getOpcode());
+}
+
+/// Matches the left hand side of binary operator expressions.
+///
+/// Example matches a (matcher = BinaryOperator(HasLHS()))
+///   a || b
+AST_MATCHER_P(clang::BinaryOperator, HasLHS,
+              Matcher<clang::Expr>, InnerMatcher) {
+  clang::Expr *LeftHandSide = Node.getLHS();
+  return (LeftHandSide != NULL &&
+          InnerMatcher.Matches(*LeftHandSide, Finder, Builder));
+}
+
+/// Matches the right hand side of binary operator expressions.
+///
+/// Example matches b (matcher = BinaryOperator(HasRHS()))
+///   a || b
+AST_MATCHER_P(clang::BinaryOperator, HasRHS,
+              Matcher<clang::Expr>, InnerMatcher) {
+  clang::Expr *RightHandSide = Node.getRHS();
+  return (RightHandSide != NULL &&
+          InnerMatcher.Matches(*RightHandSide, Finder, Builder));
+}
+
+/// Matches if either the left hand side or the right hand side of a binary
+/// operator matches.
+inline Matcher<clang::BinaryOperator> HasEitherOperand(
+    const Matcher<clang::Expr> &InnerMatcher) {
+  return AnyOf(HasLHS(InnerMatcher), HasRHS(InnerMatcher));
+}
+
+/// Matches if the operand of a unary operator matches.
+///
+/// Example matches true (matcher = HasOperand(BoolLiteral(Equals(true))))
+///   !true
+AST_MATCHER_P(clang::UnaryOperator, HasUnaryOperand,
+              Matcher<clang::Expr>, InnerMatcher) {
+  clang::Expr *Operand = Node.getSubExpr();
+  return (Operand != NULL &&
+          InnerMatcher.Matches(*Operand, Finder, Builder));
+}
+
+/// Matches the true branch expression of a conditional operator.
+///
+/// Example matches a
+///   condition ? a : b
+AST_MATCHER_P(clang::ConditionalOperator, HasTrueExpression,
+              Matcher<clang::Expr>, InnerMatcher) {
+  clang::Expr *Expression = Node.getTrueExpr();
+  return (Expression != NULL &&
+          InnerMatcher.Matches(*Expression, Finder, Builder));
+}
+
+/// Matches the false branch expression of a conditional operator.
+///
+/// Example matches b
+///   condition ? a : b
+AST_MATCHER_P(clang::ConditionalOperator, HasFalseExpression,
+              Matcher<clang::Expr>, Matcher) {
+  clang::Expr *Expression = Node.getFalseExpr();
+  return (Expression != NULL &&
+          Matcher.Matches(*Expression, Finder, Builder));
+}
+
+/// Matches if a declaration has a body attached.
+///
+/// Example matches A, va, fa
+///   class A {};
+///   class B;  // Doesn't match, as it has no body.
+///   int va;
+///   extern int vb;  // Doesn't match, as it doesn't define the variable.
+///   void fa() {}
+///   void fb();  // Doesn't match, as it has no body.
+inline PolymorphicMatcherWithParam0<IsDefinitionMatcher> IsDefinition() {
+  return PolymorphicMatcherWithParam0<IsDefinitionMatcher>();
+}
+
+/// Matches the class declaration that the given method declaration belongs to.
+/// TODO(qrczak): Generalize this for other kinds of declarations.
+/// FIXME: What other kind of declarations would we need to generalize
+/// this to?
+///
+/// Example matches A() in the last line
+///     (matcher = ConstructorCall(HasDeclaration(Method(
+///         OfClass(HasName("A"))))))
+///   class A {
+///    public:
+///     A();
+///   };
+///   A a = A();
+AST_MATCHER_P(clang::CXXMethodDecl, OfClass,
+              Matcher<clang::CXXRecordDecl>, InnerMatcher) {
+  const clang::CXXRecordDecl *Parent = Node.getParent();
+  return (Parent != NULL &&
+          InnerMatcher.Matches(*Parent, Finder, Builder));
+}
+
+/// Matches member expressions that are called with '->' as opposed to '.'.
+/// Member calls on the implicit this pointer match as called with '->'.
+///
+/// Given
+///   class Y {
+///     void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; }
+///     int a;
+///     static int b;
+///   };
+/// MemberExpression(IsArrow())
+///   matches this->x, x, y.x, a, this->b
+inline Matcher<clang::MemberExpr> IsArrow() {
+  return MakeMatcher(new IsArrowMatcher());
+}
+
+}  // namespace match
+
+/// Runs over an AST and finds matches.
+/// FIXME: Define exactly what "one match" is.
+///
+/// Not intended to be subclassed.
+class MatchFinder {
+ public:
+  struct MatchResult {
+    BoundNodes Nodes;
+
+    ///@{
+    /// Utilities for interpreting the matched AST structures.
+    clang::ASTContext *Context;
+    clang::SourceManager *SourceManager;
+    ///@}
+  };
+
+  /// Called when the Match registered for it was successfully found in the AST.
+  class MatchCallback {
+   public:
+    virtual ~MatchCallback();
+    virtual void Run(const MatchResult &Result) = 0;
+  };
+
+  /// Called when parsing is finished. Intended for testing only.
+  class ParsingDoneTestCallback {
+   public:
+    virtual ~ParsingDoneTestCallback();
+    virtual void Run() = 0;
+  };
+
+  MatchFinder();
+  ~MatchFinder();
+
+  /// Adds a NodeMatcher to match when running over the AST.
+  /// Calls action with the BoundNodes on every match.
+  /// Adding more than one InnerMatcher allows finding different matches in a
+  /// single pass over the AST.
+  void AddMatcher(const Matcher<clang::Decl> &NodeMatch,
+                  MatchCallback *Action);
+  /// Adds a NodeMatcher to match when running over the AST.
+  /// Calls action with the BoundNodes on every match.
+  /// Adding more than one InnerMatcher allows finding different matches in a
+  /// single pass over the AST.
+  void AddMatcher(const Matcher<clang::QualType> &NodeMatch,
+                  MatchCallback *Action);
+  /// Adds a NodeMatcher to match when running over the AST.
+  /// Calls action with the BoundNodes on every match.
+  /// Adding more than one InnerMatcher allows finding different matches in a
+  /// single pass over the AST.
+  void AddMatcher(const Matcher<clang::Stmt> &NodeMatch,
+                  MatchCallback *Action);
+
+  /// Finds all matches in the given code and runs the corresponding triggers.
+  /// Returns true if the code parsed correctly.
+  bool FindAll(const std::string &Code);
+
+  /// Creates a clang FrontendAction factory that finds all matches.
+  FrontendActionFactory *NewFrontendActionFactory();
+
+  /// The provided closure is called after parsing is done, before the AST is
+  /// traversed. Useful for benchmarking.
+  /// Each call to FindAll(...) will call the closure once.
+  void RegisterTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone);
+
+ private:
+  clang::FrontendAction *NewVisitorAction();
+
+  /// The MatchCallback*'s will be called every time the UntypedBaseMatcher
+  /// matches on the AST.
+  std::vector< std::pair<const UntypedBaseMatcher*, MatchCallback*> > Triggers;
+
+  /// Called when parsing is done.
+  ParsingDoneTestCallback *ParsingDone;
+
+  friend class MatchFinderFrontendActionFactory;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_AST_MATCHERS_H

Modified: cfe/trunk/include/clang/Tooling/Tooling.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Tooling.h?rev=132374&r1=132373&r2=132374&view=diff
==============================================================================
--- cfe/trunk/include/clang/Tooling/Tooling.h (original)
+++ cfe/trunk/include/clang/Tooling/Tooling.h Tue May 31 18:49:32 2011
@@ -43,11 +43,11 @@
 /// \param Argv The command line arguments, including the path the binary
 /// was started with (Argv[0]).
 bool RunToolWithFlags(
-    clang::FrontendAction* ToolAction, int Argc, char *Argv[]);
+    clang::FrontendAction *ToolAction, int Argc, char *Argv[]);
 
 /// \brief Converts a vector<string> into a vector<char*> suitable to pass
 /// to main-style functions taking (int Argc, char *Argv[]).
-std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command);
+std::vector<char*> CommandLineToArgv(const std::vector<std::string> *Command);
 
 /// \brief Specifies the working directory and command of a compilation.
 struct CompileCommand {

Added: cfe/trunk/include/clang/Tooling/VariadicFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/VariadicFunction.h?rev=132374&view=auto
==============================================================================
--- cfe/trunk/include/clang/Tooling/VariadicFunction.h (added)
+++ cfe/trunk/include/clang/Tooling/VariadicFunction.h Tue May 31 18:49:32 2011
@@ -0,0 +1,1398 @@
+//===--- VariadicFunctions.h - Variadic Functions ---------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements compile-time type-safe variadic functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_VARIADIC_FUNCTION_H
+#define LLVM_CLANG_TOOLING_VARIADIC_FUNCTION_H
+
+#include <stddef.h>  // Defines NULL.
+
+namespace clang {
+namespace tooling {
+namespace internal {
+
+/// The VariadicFunction class template makes it easy to define
+/// type-safe variadic functions where all arguments have the same
+/// type.
+///
+/// Suppose we need a variadic function like this:
+///
+///   Result Foo(const Arg &a0, const Arg &a1, ..., const Arg &an);
+///
+/// Instead of many overloads of Foo(), we only need to define a helper
+/// function that takes an array of arguments:
+///
+///   Result FooImpl(const Arg *const args[], int count) {
+///     // 'count' is the number of values in the array; args[i] is a pointer
+///     // to the i-th argument passed to Foo().  Therefore, write *args[i]
+///     // to access the i-th argument.
+///     ...
+///   }
+///
+/// and then define Foo() like this:
+///
+///   const VariadicFunction<Result, Arg, FooImpl> Foo;
+///
+/// VariadicFunction takes care of defining the overloads of Foo().
+///
+/// Actually, Foo is a function object (i.e. functor) instead of a plain
+/// function.  This object is stateless and its constructor/destructor
+/// does nothing, so it's safe to call Foo(...) at any time.
+///
+/// Sometimes we need a variadic function to have some fixed leading
+/// arguments whose types may be different from that of the optional
+/// arguments.  For example:
+///
+///   bool FullMatch(const StringRef &s, const RE &regex,
+///                  const Arg &a0, ..., const Arg &an);
+///
+/// VariadicFunctionN is for such cases, where N is the number of fixed
+/// arguments.  It is like VariadicFunction, except that it takes N more
+/// template arguments for the types of the fixed arguments:
+///
+///   bool FullMatchImpl(const StringRef &s, const RE &regex,
+///                      const Arg *const args[], int count) { ... }
+///   const VariadicFunction2<bool, const StringRef&,
+///                           const RE&, Arg, FullMatchImpl>
+///       FullMatch;
+///
+/// Currently VariadicFunction and friends support up-to 3
+/// fixed leading arguments and up-to 32 optional arguments.
+template <typename Result, typename Arg,
+          Result (*Func)(const Arg *const [], int count)>
+class VariadicFunction {
+ public:
+  VariadicFunction() {}
+
+  Result operator()() const {
+    return Func(NULL, 0);
+  }
+
+  Result operator()(const Arg &a0) const {
+    const Arg *const args[] = { &a0 };
+    return Func(args, 1);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1) const {
+    const Arg *const args[] = { &a0, &a1 };
+    return Func(args, 2);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2) const {
+    const Arg *const args[] = { &a0, &a1, &a2 };
+    return Func(args, 3);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3 };
+    return Func(args, 4);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4 };
+    return Func(args, 5);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5 };
+    return Func(args, 6);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6 };
+    return Func(args, 7);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7 };
+    return Func(args, 8);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8 };
+    return Func(args, 9);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9 };
+    return Func(args, 10);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10 };
+    return Func(args, 11);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11 };
+    return Func(args, 12);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12 };
+    return Func(args, 13);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13 };
+    return Func(args, 14);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14 };
+    return Func(args, 15);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15 };
+    return Func(args, 16);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16 };
+    return Func(args, 17);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17 };
+    return Func(args, 18);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18 };
+    return Func(args, 19);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19 };
+    return Func(args, 20);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19,
+      const Arg &a20) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19,
+        &a20 };
+    return Func(args, 21);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19,
+      const Arg &a20, const Arg &a21) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21 };
+    return Func(args, 22);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19,
+      const Arg &a20, const Arg &a21, const Arg &a22) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22 };
+    return Func(args, 23);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19,
+      const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23 };
+    return Func(args, 24);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19,
+      const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23,
+      const Arg &a24) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24 };
+    return Func(args, 25);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19,
+      const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23,
+      const Arg &a24, const Arg &a25) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25 };
+    return Func(args, 26);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19,
+      const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23,
+      const Arg &a24, const Arg &a25, const Arg &a26) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26 };
+    return Func(args, 27);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19,
+      const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23,
+      const Arg &a24, const Arg &a25, const Arg &a26, const Arg &a27) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27 };
+    return Func(args, 28);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19,
+      const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23,
+      const Arg &a24, const Arg &a25, const Arg &a26, const Arg &a27,
+      const Arg &a28) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28 };
+    return Func(args, 29);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19,
+      const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23,
+      const Arg &a24, const Arg &a25, const Arg &a26, const Arg &a27,
+      const Arg &a28, const Arg &a29) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29 };
+    return Func(args, 30);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19,
+      const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23,
+      const Arg &a24, const Arg &a25, const Arg &a26, const Arg &a27,
+      const Arg &a28, const Arg &a29, const Arg &a30) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30 };
+    return Func(args, 31);
+  }
+
+  Result operator()(const Arg &a0, const Arg &a1, const Arg &a2, const Arg &a3,
+      const Arg &a4, const Arg &a5, const Arg &a6, const Arg &a7,
+      const Arg &a8, const Arg &a9, const Arg &a10, const Arg &a11,
+      const Arg &a12, const Arg &a13, const Arg &a14, const Arg &a15,
+      const Arg &a16, const Arg &a17, const Arg &a18, const Arg &a19,
+      const Arg &a20, const Arg &a21, const Arg &a22, const Arg &a23,
+      const Arg &a24, const Arg &a25, const Arg &a26, const Arg &a27,
+      const Arg &a28, const Arg &a29, const Arg &a30, const Arg &a31) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30, &a31 };
+    return Func(args, 32);
+  }
+};
+
+template <typename Result, typename Param0, typename Arg,
+          Result (*Func)(Param0, const Arg *const [], int count)>
+class VariadicFunction1 {
+ public:
+  VariadicFunction1() {}
+
+  Result operator()(Param0 p0) const {
+    return Func(p0, NULL, 0);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0) const {
+    const Arg *const args[] = { &a0 };
+    return Func(p0, args, 1);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1) const {
+    const Arg *const args[] = { &a0, &a1 };
+    return Func(p0, args, 2);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1,
+      const Arg &a2) const {
+    const Arg *const args[] = { &a0, &a1, &a2 };
+    return Func(p0, args, 3);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3 };
+    return Func(p0, args, 4);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4 };
+    return Func(p0, args, 5);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5 };
+    return Func(p0, args, 6);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6 };
+    return Func(p0, args, 7);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7 };
+    return Func(p0, args, 8);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8 };
+    return Func(p0, args, 9);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9 };
+    return Func(p0, args, 10);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10 };
+    return Func(p0, args, 11);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11 };
+    return Func(p0, args, 12);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12 };
+    return Func(p0, args, 13);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13 };
+    return Func(p0, args, 14);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14 };
+    return Func(p0, args, 15);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15 };
+    return Func(p0, args, 16);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16 };
+    return Func(p0, args, 17);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17 };
+    return Func(p0, args, 18);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18 };
+    return Func(p0, args, 19);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18,
+      const Arg &a19) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19 };
+    return Func(p0, args, 20);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18,
+      const Arg &a19, const Arg &a20) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19,
+        &a20 };
+    return Func(p0, args, 21);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18,
+      const Arg &a19, const Arg &a20, const Arg &a21) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21 };
+    return Func(p0, args, 22);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18,
+      const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22 };
+    return Func(p0, args, 23);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18,
+      const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22,
+      const Arg &a23) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23 };
+    return Func(p0, args, 24);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18,
+      const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22,
+      const Arg &a23, const Arg &a24) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24 };
+    return Func(p0, args, 25);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18,
+      const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22,
+      const Arg &a23, const Arg &a24, const Arg &a25) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25 };
+    return Func(p0, args, 26);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18,
+      const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22,
+      const Arg &a23, const Arg &a24, const Arg &a25, const Arg &a26) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26 };
+    return Func(p0, args, 27);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18,
+      const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22,
+      const Arg &a23, const Arg &a24, const Arg &a25, const Arg &a26,
+      const Arg &a27) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27 };
+    return Func(p0, args, 28);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18,
+      const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22,
+      const Arg &a23, const Arg &a24, const Arg &a25, const Arg &a26,
+      const Arg &a27, const Arg &a28) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28 };
+    return Func(p0, args, 29);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18,
+      const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22,
+      const Arg &a23, const Arg &a24, const Arg &a25, const Arg &a26,
+      const Arg &a27, const Arg &a28, const Arg &a29) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29 };
+    return Func(p0, args, 30);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18,
+      const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22,
+      const Arg &a23, const Arg &a24, const Arg &a25, const Arg &a26,
+      const Arg &a27, const Arg &a28, const Arg &a29, const Arg &a30) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30 };
+    return Func(p0, args, 31);
+  }
+
+  Result operator()(Param0 p0, const Arg &a0, const Arg &a1, const Arg &a2,
+      const Arg &a3, const Arg &a4, const Arg &a5, const Arg &a6,
+      const Arg &a7, const Arg &a8, const Arg &a9, const Arg &a10,
+      const Arg &a11, const Arg &a12, const Arg &a13, const Arg &a14,
+      const Arg &a15, const Arg &a16, const Arg &a17, const Arg &a18,
+      const Arg &a19, const Arg &a20, const Arg &a21, const Arg &a22,
+      const Arg &a23, const Arg &a24, const Arg &a25, const Arg &a26,
+      const Arg &a27, const Arg &a28, const Arg &a29, const Arg &a30,
+      const Arg &a31) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30, &a31 };
+    return Func(p0, args, 32);
+  }
+};
+
+template <typename Result, typename Param0, typename Param1, typename Arg,
+          Result (*Func)(Param0, Param1, const Arg *const [], int count)>
+class VariadicFunction2 {
+ public:
+  VariadicFunction2() {}
+
+  Result operator()(Param0 p0, Param1 p1) const {
+    return Func(p0, p1, NULL, 0);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0) const {
+    const Arg *const args[] = { &a0 };
+    return Func(p0, p1, args, 1);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1) const {
+    const Arg *const args[] = { &a0, &a1 };
+    return Func(p0, p1, args, 2);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2) const {
+    const Arg *const args[] = { &a0, &a1, &a2 };
+    return Func(p0, p1, args, 3);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3 };
+    return Func(p0, p1, args, 4);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4 };
+    return Func(p0, p1, args, 5);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5 };
+    return Func(p0, p1, args, 6);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6 };
+    return Func(p0, p1, args, 7);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7 };
+    return Func(p0, p1, args, 8);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8 };
+    return Func(p0, p1, args, 9);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9 };
+    return Func(p0, p1, args, 10);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10 };
+    return Func(p0, p1, args, 11);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11 };
+    return Func(p0, p1, args, 12);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12 };
+    return Func(p0, p1, args, 13);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13 };
+    return Func(p0, p1, args, 14);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14 };
+    return Func(p0, p1, args, 15);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15 };
+    return Func(p0, p1, args, 16);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16 };
+    return Func(p0, p1, args, 17);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17 };
+    return Func(p0, p1, args, 18);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18 };
+    return Func(p0, p1, args, 19);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18, const Arg &a19) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19 };
+    return Func(p0, p1, args, 20);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18, const Arg &a19, const Arg &a20) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19,
+        &a20 };
+    return Func(p0, p1, args, 21);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21 };
+    return Func(p0, p1, args, 22);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21,
+      const Arg &a22) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22 };
+    return Func(p0, p1, args, 23);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21,
+      const Arg &a22, const Arg &a23) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23 };
+    return Func(p0, p1, args, 24);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21,
+      const Arg &a22, const Arg &a23, const Arg &a24) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24 };
+    return Func(p0, p1, args, 25);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21,
+      const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25 };
+    return Func(p0, p1, args, 26);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21,
+      const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25,
+      const Arg &a26) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26 };
+    return Func(p0, p1, args, 27);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21,
+      const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25,
+      const Arg &a26, const Arg &a27) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27 };
+    return Func(p0, p1, args, 28);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21,
+      const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25,
+      const Arg &a26, const Arg &a27, const Arg &a28) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28 };
+    return Func(p0, p1, args, 29);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21,
+      const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25,
+      const Arg &a26, const Arg &a27, const Arg &a28, const Arg &a29) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29 };
+    return Func(p0, p1, args, 30);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21,
+      const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25,
+      const Arg &a26, const Arg &a27, const Arg &a28, const Arg &a29,
+      const Arg &a30) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30 };
+    return Func(p0, p1, args, 31);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, const Arg &a0, const Arg &a1,
+      const Arg &a2, const Arg &a3, const Arg &a4, const Arg &a5,
+      const Arg &a6, const Arg &a7, const Arg &a8, const Arg &a9,
+      const Arg &a10, const Arg &a11, const Arg &a12, const Arg &a13,
+      const Arg &a14, const Arg &a15, const Arg &a16, const Arg &a17,
+      const Arg &a18, const Arg &a19, const Arg &a20, const Arg &a21,
+      const Arg &a22, const Arg &a23, const Arg &a24, const Arg &a25,
+      const Arg &a26, const Arg &a27, const Arg &a28, const Arg &a29,
+      const Arg &a30, const Arg &a31) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30, &a31 };
+    return Func(p0, p1, args, 32);
+  }
+};
+
+template <typename Result, typename Param0, typename Param1, typename Param2,
+    typename Arg,
+          Result (*Func)(Param0, Param1, Param2, const Arg *const [],
+              int count)>
+class VariadicFunction3 {
+ public:
+  VariadicFunction3() {}
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2) const {
+    return Func(p0, p1, p2, NULL, 0);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0) const {
+    const Arg *const args[] = { &a0 };
+    return Func(p0, p1, p2, args, 1);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1) const {
+    const Arg *const args[] = { &a0, &a1 };
+    return Func(p0, p1, p2, args, 2);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2) const {
+    const Arg *const args[] = { &a0, &a1, &a2 };
+    return Func(p0, p1, p2, args, 3);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3 };
+    return Func(p0, p1, p2, args, 4);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4 };
+    return Func(p0, p1, p2, args, 5);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5 };
+    return Func(p0, p1, p2, args, 6);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6 };
+    return Func(p0, p1, p2, args, 7);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7 };
+    return Func(p0, p1, p2, args, 8);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8 };
+    return Func(p0, p1, p2, args, 9);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9 };
+    return Func(p0, p1, p2, args, 10);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10 };
+    return Func(p0, p1, p2, args, 11);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11 };
+    return Func(p0, p1, p2, args, 12);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12 };
+    return Func(p0, p1, p2, args, 13);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13 };
+    return Func(p0, p1, p2, args, 14);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14 };
+    return Func(p0, p1, p2, args, 15);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15 };
+    return Func(p0, p1, p2, args, 16);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16 };
+    return Func(p0, p1, p2, args, 17);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17 };
+    return Func(p0, p1, p2, args, 18);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18 };
+    return Func(p0, p1, p2, args, 19);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18, const Arg &a19) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19 };
+    return Func(p0, p1, p2, args, 20);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19,
+        &a20 };
+    return Func(p0, p1, p2, args, 21);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20,
+      const Arg &a21) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21 };
+    return Func(p0, p1, p2, args, 22);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20,
+      const Arg &a21, const Arg &a22) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22 };
+    return Func(p0, p1, p2, args, 23);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20,
+      const Arg &a21, const Arg &a22, const Arg &a23) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23 };
+    return Func(p0, p1, p2, args, 24);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20,
+      const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24 };
+    return Func(p0, p1, p2, args, 25);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20,
+      const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24,
+      const Arg &a25) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25 };
+    return Func(p0, p1, p2, args, 26);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20,
+      const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24,
+      const Arg &a25, const Arg &a26) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26 };
+    return Func(p0, p1, p2, args, 27);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20,
+      const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24,
+      const Arg &a25, const Arg &a26, const Arg &a27) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27 };
+    return Func(p0, p1, p2, args, 28);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20,
+      const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24,
+      const Arg &a25, const Arg &a26, const Arg &a27, const Arg &a28) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28 };
+    return Func(p0, p1, p2, args, 29);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20,
+      const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24,
+      const Arg &a25, const Arg &a26, const Arg &a27, const Arg &a28,
+      const Arg &a29) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29 };
+    return Func(p0, p1, p2, args, 30);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20,
+      const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24,
+      const Arg &a25, const Arg &a26, const Arg &a27, const Arg &a28,
+      const Arg &a29, const Arg &a30) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30 };
+    return Func(p0, p1, p2, args, 31);
+  }
+
+  Result operator()(Param0 p0, Param1 p1, Param2 p2, const Arg &a0,
+      const Arg &a1, const Arg &a2, const Arg &a3, const Arg &a4,
+      const Arg &a5, const Arg &a6, const Arg &a7, const Arg &a8,
+      const Arg &a9, const Arg &a10, const Arg &a11, const Arg &a12,
+      const Arg &a13, const Arg &a14, const Arg &a15, const Arg &a16,
+      const Arg &a17, const Arg &a18, const Arg &a19, const Arg &a20,
+      const Arg &a21, const Arg &a22, const Arg &a23, const Arg &a24,
+      const Arg &a25, const Arg &a26, const Arg &a27, const Arg &a28,
+      const Arg &a29, const Arg &a30, const Arg &a31) const {
+    const Arg *const args[] = { &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8,
+        &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16, &a17, &a18, &a19, &a20,
+        &a21, &a22, &a23, &a24, &a25, &a26, &a27, &a28, &a29, &a30, &a31 };
+    return Func(p0, p1, p2, args, 32);
+  }
+};
+
+} // end namespace internal
+} // end namespace tooling
+} // end namespace clang
+
+#endif  // LLVM_CLANG_TOOLING_VARIADIC_FUNCTION_H

Added: cfe/trunk/lib/Tooling/ASTMatchers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/ASTMatchers.cpp?rev=132374&view=auto
==============================================================================
--- cfe/trunk/lib/Tooling/ASTMatchers.cpp (added)
+++ cfe/trunk/lib/Tooling/ASTMatchers.cpp Tue May 31 18:49:32 2011
@@ -0,0 +1,564 @@
+//===--- ASTMatchers.cpp - Structural query framework ---------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements a framework of AST matchers that can be used to express
+//  structural queries on C++ code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Tooling/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/DenseMap.h"
+#include <assert.h>
+#include <stddef.h>
+#include <set>
+#include <utility>
+
+namespace clang {
+namespace tooling {
+
+// Returns the value that 'a_map' maps 'key' to, or NULL if 'key' is
+// not in 'a_map'.
+template <typename Map>
+static const typename Map::mapped_type *Find(
+    const Map &AMap, const typename Map::key_type &Key) {
+  typename Map::const_iterator It = AMap.find(Key);
+  return It == AMap.end() ? NULL : &It->second;
+}
+
+// We use memoization to avoid running the same matcher on the same
+// AST node twice.  This pair is the key for looking up match
+// result.  It consists of an ID of the MatcherInterface (for
+// identifying the matcher) and a pointer to the AST node.
+typedef std::pair<uint64_t, const void*> UntypedMatchInput;
+
+// Used to store the result of a match and possibly bound nodes.
+struct MemoizedMatchResult {
+  bool ResultOfMatch;
+  BoundNodes Nodes;
+};
+
+// A RecursiveASTVisitor that traverses all children or all descendants of
+// a node.
+class MatchChildASTVisitor
+    : public clang::RecursiveASTVisitor<MatchChildASTVisitor> {
+ public:
+  typedef clang::RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
+
+  // Creates an AST visitor that matches 'matcher' on all children or
+  // descendants of a traversed node. max_depth is the maximum depth
+  // to traverse: use 1 for matching the children and INT_MAX for
+  // matching the descendants.
+  MatchChildASTVisitor(const UntypedBaseMatcher *BaseMatcher,
+                       ASTMatchFinder *Finder,
+                       BoundNodesBuilder *Builder,
+                       int MaxDepth,
+                       ASTMatchFinder::TraversalMethod Traversal)
+      : BaseMatcher(BaseMatcher),
+        Finder(Finder),
+        Builder(Builder),
+        CurrentDepth(-1),
+        MaxDepth(MaxDepth),
+        Traversal(Traversal),
+        Matches(false) {}
+
+  // Returns true if a match is found in the subtree rooted at the
+  // given AST node. This is done via a set of mutually recursive
+  // functions. Here's how the recursion is done (the  *wildcard can
+  // actually be Decl, Stmt, or Type):
+  //
+  //   - Traverse(node) calls BaseTraverse(node) when it needs
+  //     to visit the descendants of node.
+  //   - BaseTraverse(node) then calls (via VisitorBase::Traverse*(node))
+  //     Traverse*(c) for each child c of 'node'.
+  //   - Traverse*(c) in turn calls Traverse(c), completing the
+  //     recursion.
+  template <typename T>
+  bool FindMatch(const T &Node) {
+    Reset();
+    Traverse(Node);
+    return Matches;
+  }
+
+  // The following are overriding methods from the base visitor class.
+  // They are public only to allow CRTP to work. They are *not *part
+  // of the public API of this class.
+  bool TraverseDecl(clang::Decl *DeclNode) {
+    return (DeclNode == NULL) || Traverse(*DeclNode);
+  }
+  bool TraverseStmt(clang::Stmt *StmtNode) {
+    const clang::Stmt *StmtToTraverse = StmtNode;
+    if (Traversal ==
+        ASTMatchFinder::kIgnoreImplicitCastsAndParentheses) {
+      const clang::Expr *ExprNode = dyn_cast_or_null<clang::Expr>(StmtNode);
+      if (ExprNode != NULL) {
+        StmtToTraverse = ExprNode->IgnoreParenImpCasts();
+      }
+    }
+    return (StmtToTraverse == NULL) || Traverse(*StmtToTraverse);
+  }
+  bool TraverseType(clang::QualType TypeNode) {
+    return Traverse(TypeNode);
+  }
+
+  bool shouldVisitTemplateInstantiations() const { return true; }
+
+ private:
+  // Resets the state of this object.
+  void Reset() {
+    Matches = false;
+    CurrentDepth = -1;
+  }
+
+  // Forwards the call to the corresponding Traverse*() method in the
+  // base visitor class.
+  bool BaseTraverse(const clang::Decl &DeclNode) {
+    return VisitorBase::TraverseDecl(const_cast<clang::Decl*>(&DeclNode));
+  }
+  bool BaseTraverse(const clang::Stmt &StmtNode) {
+    return VisitorBase::TraverseStmt(const_cast<clang::Stmt*>(&StmtNode));
+  }
+  bool BaseTraverse(clang::QualType TypeNode) {
+    return VisitorBase::TraverseType(TypeNode);
+  }
+
+  // Traverses the subtree rooted at 'node'; returns true if the
+  // traversal should continue after this function returns; also sets
+  // matched_ to true if a match is found during the traversal.
+  template <typename T>
+  bool Traverse(const T &Node) {
+    COMPILE_ASSERT(IsBaseType<T>::value,
+                   traverse_can_only_be_instantiated_with_base_type);
+    ++CurrentDepth;
+    bool ShouldContinue;
+    if (CurrentDepth == 0) {
+      // We don't want to match the root node, so just recurse.
+      ShouldContinue = BaseTraverse(Node);
+    } else if (BaseMatcher->Matches(Node, Finder, Builder)) {
+      Matches = true;
+      ShouldContinue = false;  // Abort as soon as a match is found.
+    } else if (CurrentDepth < MaxDepth) {
+      // The current node doesn't match, and we haven't reached the
+      // maximum depth yet, so recurse.
+      ShouldContinue = BaseTraverse(Node);
+    } else {
+      // The current node doesn't match, and we have reached the
+      // maximum depth, so don't recurse (but continue the traversal
+      // such that other nodes at the current level can be visited).
+      ShouldContinue = true;
+    }
+    --CurrentDepth;
+    return ShouldContinue;
+  }
+
+  const UntypedBaseMatcher *const BaseMatcher;
+  ASTMatchFinder *const Finder;
+  BoundNodesBuilder *const Builder;
+  int CurrentDepth;
+  const int MaxDepth;
+  const ASTMatchFinder::TraversalMethod Traversal;
+  bool Matches;
+};
+
+// Controls the outermost traversal of the AST and allows to match multiple
+// matchers.
+class MatchASTVisitor : public clang::RecursiveASTVisitor<MatchASTVisitor>,
+                        public ASTMatchFinder {
+ public:
+  MatchASTVisitor(std::vector< std::pair<const UntypedBaseMatcher*,
+                               MatchFinder::MatchCallback*> > *Triggers,
+                  clang::SourceManager *VisitorSourceManager,
+                  clang::LangOptions *LanguageOptions)
+     : Triggers(Triggers),
+       VisitorSourceManager(VisitorSourceManager),
+       LanguageOptions(LanguageOptions),
+       ActiveASTContext(NULL) {
+    assert(VisitorSourceManager != NULL);
+    assert(LanguageOptions != NULL);
+    // FIXME: add rewriter_(*source_manager, *language_options)
+  }
+
+  void set_active_ast_context(clang::ASTContext *NewActiveASTContext) {
+    ActiveASTContext = NewActiveASTContext;
+  }
+
+  // The following Visit*() and Traverse*() functions "override"
+  // methods in RecursiveASTVisitor.
+
+  bool VisitTypedefDecl(clang::TypedefDecl *DeclNode) {
+    // When we see 'typedef A B', we add name 'B' to the set of names
+    // A's canonical type maps to.  This is necessary for implementing
+    // IsDerivedFrom(x) properly, where x can be the name of the base
+    // class or any of its aliases.
+    //
+    // In general, the is-alias-of (as defined by typedefs) relation
+    // is tree-shaped, as you can typedef a type more than once.  For
+    // example,
+    //
+    //   typedef A B;
+    //   typedef A C;
+    //   typedef C D;
+    //   typedef C E;
+    //
+    // gives you
+    //
+    //   A
+    //   |- B
+    //   `- C
+    //      |- D
+    //      `- E
+    //
+    // It is wrong to assume that the relation is a chain.  A correct
+    // implementation of IsDerivedFrom() needs to recognize that B and
+    // E are aliases, even though neither is a typedef of the other.
+    // Therefore, we cannot simply walk through one typedef chain to
+    // find out whether the type name matches.
+    const clang::Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
+    const clang::Type *CanonicalType =  // root of the typedef tree
+        ActiveASTContext->getCanonicalType(TypeNode);
+    TypeToUnqualifiedAliases[CanonicalType].insert(
+        DeclNode->getName().str());
+    return true;
+  }
+
+  bool TraverseDecl(clang::Decl *DeclNode);
+  bool TraverseStmt(clang::Stmt *StmtNode);
+  bool TraverseType(clang::QualType TypeNode);
+  bool TraverseTypeLoc(clang::TypeLoc TypeNode);
+
+  // Matches children or descendants of 'Node' with 'BaseMatcher'.
+  template <typename T>
+  bool MemoizedMatchesRecursively(
+      const T &Node, const UntypedBaseMatcher &BaseMatcher,
+      BoundNodesBuilder *Builder, int MaxDepth,
+      TraversalMethod Traversal) {
+    COMPILE_ASSERT((llvm::is_same<T, clang::Decl>::value) ||
+                   (llvm::is_same<T, clang::Stmt>::value),
+                   type_does_not_support_memoization);
+    const UntypedMatchInput input(BaseMatcher.GetID(), &Node);
+    std::pair <MemoizationMap::iterator, bool>
+        InsertResult = ResultCache.insert(
+            std::make_pair(input, MemoizedMatchResult()));
+    if (InsertResult.second) {
+      BoundNodesBuilder DescendantBoundNodesBuilder;
+      InsertResult.first->second.ResultOfMatch =
+          MatchesRecursively(Node, BaseMatcher, &DescendantBoundNodesBuilder,
+                             MaxDepth, Traversal);
+      InsertResult.first->second.Nodes =
+          DescendantBoundNodesBuilder.Build();
+    }
+    InsertResult.first->second.Nodes.CopyTo(Builder);
+    return InsertResult.first->second.ResultOfMatch;
+  }
+
+  // Matches children or descendants of 'Node' with 'BaseMatcher'.
+  template <typename T>
+  bool MatchesRecursively(
+      const T &Node, const UntypedBaseMatcher &BaseMatcher,
+      BoundNodesBuilder *Builder, int MaxDepth,
+      TraversalMethod Traversal) {
+    MatchChildASTVisitor Visitor(
+        &BaseMatcher, this, Builder, MaxDepth, Traversal);
+    return Visitor.FindMatch(Node);
+  }
+
+  virtual bool ClassIsDerivedFrom(const clang::CXXRecordDecl *Declaration,
+                                  const std::string &BaseName) const;
+
+  // Implements ASTMatchFinder::MatchesChildOf.
+  virtual bool MatchesChildOf(const clang::Decl &DeclNode,
+                              const UntypedBaseMatcher &BaseMatcher,
+                              BoundNodesBuilder *Builder,
+                              TraversalMethod Traversal) {
+    return MatchesRecursively(
+        DeclNode, BaseMatcher, Builder, 1, Traversal);
+  }
+  virtual bool MatchesChildOf(const clang::Stmt &StmtNode,
+                              const UntypedBaseMatcher &BaseMatcher,
+                              BoundNodesBuilder *Builder,
+                              TraversalMethod Traversal) {
+    return MatchesRecursively(
+        StmtNode, BaseMatcher, Builder, 1, Traversal);
+  }
+
+  // Implements ASTMatchFinder::MatchesDescendantOf.
+  virtual bool MatchesDescendantOf(const clang::Decl &DeclNode,
+                                   const UntypedBaseMatcher &BaseMatcher,
+                                   BoundNodesBuilder *Builder) {
+    return MemoizedMatchesRecursively(
+        DeclNode, BaseMatcher, Builder, INT_MAX, kAsIs);
+  }
+  virtual bool MatchesDescendantOf(const clang::Stmt &StmtNode,
+                                   const UntypedBaseMatcher &BaseMatcher,
+                                   BoundNodesBuilder *Builder) {
+    return MemoizedMatchesRecursively(
+        StmtNode, BaseMatcher, Builder, INT_MAX, kAsIs);
+  }
+
+  bool shouldVisitTemplateInstantiations() const { return true; }
+
+ private:
+  // Returns true if 'TypeNode' is also known by the name 'Name'.  In other
+  // words, there is a type (including typedef) with the name 'Name'
+  // that is equal to 'TypeNode'.
+  bool TypeHasAlias(
+      const clang::Type *TypeNode, const std::string &Name) const {
+    const clang::Type *const CanonicalType =
+        ActiveASTContext->getCanonicalType(TypeNode);
+    const std::set<std::string> *UnqualifiedAlias =
+        Find(TypeToUnqualifiedAliases, CanonicalType);
+    return UnqualifiedAlias != NULL && UnqualifiedAlias->count(Name) > 0;
+  }
+
+  // Matches all registered matchers on the given node and calls the
+  // result callback for every node that matches.
+  template <typename T>
+  void Match(const T &node) {
+    for (std::vector< std::pair<const UntypedBaseMatcher*,
+                      MatchFinder::MatchCallback*> >::const_iterator
+             It = Triggers->begin(), End = Triggers->end();
+         It != End; ++It) {
+      BoundNodesBuilder Builder;
+      if (It->first->Matches(node, this, &Builder)) {
+        MatchFinder::MatchResult Result;
+        Result.Nodes = Builder.Build();
+        Result.Context = ActiveASTContext;
+        Result.SourceManager = VisitorSourceManager;
+        It->second->Run(Result);
+      }
+    }
+  }
+
+  std::vector< std::pair<const UntypedBaseMatcher*,
+               MatchFinder::MatchCallback*> > *const Triggers;
+  clang::SourceManager *const VisitorSourceManager;
+  clang::LangOptions *const LanguageOptions;
+  clang::ASTContext *ActiveASTContext;
+
+  // Maps a canonical type to the names of its typedefs.
+  llvm::DenseMap<const clang::Type*, std::set<std::string> >
+      TypeToUnqualifiedAliases;
+
+  // Maps (matcher, node) -> the match result for memoization.
+  typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap;
+  MemoizationMap ResultCache;
+};
+
+// Returns true if the given class is directly or indirectly derived
+// from a base type with the given name.  A class is considered to be
+// also derived from itself.
+bool MatchASTVisitor::ClassIsDerivedFrom(
+    const clang::CXXRecordDecl *Declaration,
+    const std::string &BaseName) const {
+  if (std::string(Declaration->getName()) == BaseName) {
+    return true;
+  }
+  if (!Declaration->hasDefinition()) {
+    return false;
+  }
+  typedef clang::CXXRecordDecl::base_class_const_iterator BaseIterator;
+  for (BaseIterator It = Declaration->bases_begin(),
+           End = Declaration->bases_end(); It != End; ++It) {
+    const clang::Type *TypeNode = It->getType().getTypePtr();
+
+    if (TypeHasAlias(TypeNode, BaseName))
+      return true;
+
+    // clang::Type::getAs<...>() drills through typedefs.
+    if (TypeNode->getAs<clang::DependentNameType>() != NULL ||
+        TypeNode->getAs<clang::TemplateTypeParmType>() != NULL) {
+      // Dependent names and template TypeNode parameters will be matched when
+      // the template is instantiated.
+      continue;
+    }
+    clang::CXXRecordDecl *ClassDecl = NULL;
+    clang::TemplateSpecializationType const *TemplateType =
+      TypeNode->getAs<clang::TemplateSpecializationType>();
+    if (TemplateType != NULL) {
+      if (TemplateType->getTemplateName().isDependent()) {
+        // Dependent template specializations will be matched when the
+        // template is instantiated.
+        continue;
+      }
+      // For template specialization types which are specializing a template
+      // declaration which is an explicit or partial specialization of another
+      // template declaration, getAsCXXRecordDecl() returns the corresponding
+      // ClassTemplateSpecializationDecl.
+      //
+      // For template specialization types which are specializing a template
+      // declaration which is neither an explicit nor partial specialization of
+      // another template declaration, getAsCXXRecordDecl() returns NULL and
+      // we get the CXXRecordDecl of the templated declaration.
+      clang::CXXRecordDecl *SpecializationDecl =
+          TemplateType->getAsCXXRecordDecl();
+      if (SpecializationDecl != NULL) {
+        ClassDecl = SpecializationDecl;
+      } else {
+        ClassDecl = llvm::dyn_cast<clang::CXXRecordDecl>(
+            TemplateType->getTemplateName()
+                .getAsTemplateDecl()->getTemplatedDecl());
+      }
+    } else {
+      ClassDecl = TypeNode->getAsCXXRecordDecl();
+    }
+    assert(ClassDecl != NULL);
+    assert(ClassDecl != Declaration);
+    if (ClassIsDerivedFrom(ClassDecl, BaseName)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool MatchASTVisitor::TraverseDecl(clang::Decl *DeclNode) {
+  if (DeclNode == NULL) {
+    return true;
+  }
+  Match(*DeclNode);
+  return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
+}
+
+bool MatchASTVisitor::TraverseStmt(clang::Stmt *StmtNode) {
+  if (StmtNode == NULL) {
+    return true;
+  }
+  Match(*StmtNode);
+  return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode);
+}
+
+bool MatchASTVisitor::TraverseType(clang::QualType TypeNode) {
+  Match(TypeNode);
+  return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);
+}
+
+bool MatchASTVisitor::TraverseTypeLoc(clang::TypeLoc TypeLoc) {
+  return clang::RecursiveASTVisitor<MatchASTVisitor>::
+      TraverseType(TypeLoc.getType());
+}
+
+class MatchASTConsumer : public clang::ASTConsumer {
+ public:
+  MatchASTConsumer(std::vector< std::pair<const UntypedBaseMatcher*,
+                                MatchFinder::MatchCallback*> > *Triggers,
+                   MatchFinder::ParsingDoneTestCallback *ParsingDone,
+                   clang::SourceManager *ConsumerSourceManager,
+                   clang::LangOptions *LanaguageOptions)
+      : Visitor(Triggers, ConsumerSourceManager, LanaguageOptions),
+        ParsingDone(ParsingDone) {}
+
+ private:
+  virtual void HandleTranslationUnit(
+      clang::ASTContext &Context) {  // NOLINT: external API uses refs
+    if (ParsingDone != NULL) {
+      ParsingDone->Run();
+    }
+    Visitor.set_active_ast_context(&Context);
+    Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+    Visitor.set_active_ast_context(NULL);
+  }
+
+  MatchASTVisitor Visitor;
+  MatchFinder::ParsingDoneTestCallback *ParsingDone;
+};
+
+class MatchASTAction : public clang::ASTFrontendAction {
+ public:
+  explicit MatchASTAction(
+      std::vector< std::pair<const UntypedBaseMatcher*,
+                   MatchFinder::MatchCallback*> > *Triggers,
+      MatchFinder::ParsingDoneTestCallback *ParsingDone)
+      : Triggers(Triggers),
+        ParsingDone(ParsingDone) {}
+
+ private:
+  clang::ASTConsumer *CreateASTConsumer(
+      clang::CompilerInstance &Compiler,
+      llvm::StringRef) {
+    return new MatchASTConsumer(Triggers,
+                                ParsingDone,
+                                &Compiler.getSourceManager(),
+                                &Compiler.getLangOpts());
+  }
+
+  std::vector< std::pair<const UntypedBaseMatcher*,
+               MatchFinder::MatchCallback*> > *const Triggers;
+  MatchFinder::ParsingDoneTestCallback *ParsingDone;
+};
+
+MatchFinder::MatchCallback::~MatchCallback() {}
+MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
+
+MatchFinder::MatchFinder() : ParsingDone(NULL) {}
+
+MatchFinder::~MatchFinder() {
+  for (std::vector< std::pair<const UntypedBaseMatcher*,
+                    MatchFinder::MatchCallback*> >::const_iterator
+           It = Triggers.begin(), End = Triggers.end();
+       It != End; ++It) {
+    delete It->first;
+    delete It->second;
+  }
+}
+
+void MatchFinder::AddMatcher(const Matcher<clang::Decl> &NodeMatch,
+                             MatchCallback *Action) {
+  Triggers.push_back(std::make_pair(
+      new TypedBaseMatcher<clang::Decl>(NodeMatch), Action));
+}
+
+void MatchFinder::AddMatcher(const Matcher<clang::QualType> &NodeMatch,
+                             MatchCallback *Action) {
+  Triggers.push_back(std::make_pair(
+      new TypedBaseMatcher<clang::QualType>(NodeMatch), Action));
+}
+
+void MatchFinder::AddMatcher(const Matcher<clang::Stmt> &NodeMatch,
+                             MatchCallback *Action) {
+  Triggers.push_back(std::make_pair(
+      new TypedBaseMatcher<clang::Stmt>(NodeMatch), Action));
+}
+
+bool MatchFinder::FindAll(const std::string &Code) {
+  return RunSyntaxOnlyToolOnCode(
+      new MatchASTAction(&Triggers, ParsingDone), Code);
+}
+
+clang::FrontendAction *MatchFinder::NewVisitorAction() {
+  return new MatchASTAction(&Triggers, ParsingDone);
+}
+
+class MatchFinderFrontendActionFactory : public FrontendActionFactory {
+ public:
+  explicit MatchFinderFrontendActionFactory(MatchFinder *Finder)
+      : Finder(Finder) {}
+
+  virtual clang::FrontendAction *New() {
+    return Finder->NewVisitorAction();
+  }
+
+ private:
+  MatchFinder *const Finder;
+};
+
+FrontendActionFactory *MatchFinder::NewFrontendActionFactory() {
+  return new MatchFinderFrontendActionFactory(this);
+}
+
+void MatchFinder::RegisterTestCallbackAfterParsing(
+    MatchFinder::ParsingDoneTestCallback *NewParsingDone) {
+  ParsingDone = NewParsingDone;
+}
+
+} // end namespace tooling
+} // end namespace clang

Modified: cfe/trunk/lib/Tooling/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/CMakeLists.txt?rev=132374&r1=132373&r2=132374&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/CMakeLists.txt (original)
+++ cfe/trunk/lib/Tooling/CMakeLists.txt Tue May 31 18:49:32 2011
@@ -1,6 +1,7 @@
 SET(LLVM_USED_LIBS clangBasic clangFrontend clangAST)
 
 add_clang_library(clangTooling
+  ASTMatchers.cpp
   JsonCompileCommandLineDatabase.cpp
   Tooling.cpp
   )

Modified: cfe/trunk/lib/Tooling/Tooling.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Tooling.cpp?rev=132374&r1=132373&r2=132374&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/Tooling.cpp (original)
+++ cfe/trunk/lib/Tooling/Tooling.cpp Tue May 31 18:49:32 2011
@@ -1,4 +1,4 @@
-//===--- Tooling.cpp - Running clang standalone tools --------------------===//
+//===--- Tooling.cpp - Running clang standalone tools ---------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -44,7 +44,7 @@
 //   - it must contain at least a program path,
 //   - argv[0], ..., and argv[argc - 1] mustn't be NULL, and
 //   - argv[argc] must be NULL.
-void ValidateArgv(int argc, char* argv[]) {
+void ValidateArgv(int argc, char *argv[]) {
   if (argc < 1) {
     fprintf(stderr, "ERROR: argc is %d.  It must be >= 1.\n", argc);
     abort();
@@ -69,7 +69,7 @@
 // code that sets up a compiler to run tools on it, and we should refactor
 // it to be based on the same framework.
 
-static clang::Diagnostic* NewTextDiagnostics() {
+static clang::Diagnostic *NewTextDiagnostics() {
   llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(
       new clang::DiagnosticIDs());
   clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter(
@@ -81,15 +81,15 @@
 static int StaticSymbol;
 
 /// \brief Builds a clang driver initialized for running clang tools.
-static clang::driver::Driver* NewDriver(clang::Diagnostic* Diagnostics,
-                                        const char* BinaryName) {
+static clang::driver::Driver *NewDriver(clang::Diagnostic *Diagnostics,
+                                        const char *BinaryName) {
   // This just needs to be some symbol in the binary.
-  void* const SymbolAddr = &StaticSymbol;
+  void *const SymbolAddr = &StaticSymbol;
   const llvm::sys::Path ExePath =
       llvm::sys::Path::GetMainExecutable(BinaryName, SymbolAddr);
 
   const std::string DefaultOutputName = "a.out";
-  clang::driver::Driver* CompilerDriver = new clang::driver::Driver(
+  clang::driver::Driver *CompilerDriver = new clang::driver::Driver(
       ExePath.str(), llvm::sys::getHostTriple(),
       DefaultOutputName, false, false, *Diagnostics);
   CompilerDriver->setTitle("clang_based_tool");
@@ -98,8 +98,8 @@
 
 /// \brief Retrieves the clang CC1 specific flags out of the compilation's jobs.
 /// Returns NULL on error.
-static const clang::driver::ArgStringList* GetCC1Arguments(
-    clang::Diagnostic* Diagnostics, clang::driver::Compilation* Compilation) {
+static const clang::driver::ArgStringList *GetCC1Arguments(
+    clang::Diagnostic *Diagnostics, clang::driver::Compilation *Compilation) {
   // We expect to get back exactly one Command job, if we didn't something
   // failed. Extract that job from the Compilation.
   const clang::driver::JobList &Jobs = Compilation->getJobs();
@@ -124,10 +124,10 @@
 }
 
 /// \brief Returns a clang build invocation initialized from the CC1 flags.
-static clang::CompilerInvocation* NewInvocation(
-    clang::Diagnostic* Diagnostics,
-    const clang::driver::ArgStringList& CC1Args) {
-  clang::CompilerInvocation* Invocation = new clang::CompilerInvocation;
+static clang::CompilerInvocation *NewInvocation(
+    clang::Diagnostic *Diagnostics,
+    const clang::driver::ArgStringList &CC1Args) {
+  clang::CompilerInvocation *Invocation = new clang::CompilerInvocation;
   clang::CompilerInvocation::CreateFromArgs(
       *Invocation, CC1Args.data(), CC1Args.data() + CC1Args.size(),
       *Diagnostics);
@@ -137,11 +137,11 @@
 
 /// \brief Runs the specified clang tool action and returns whether it executed
 /// successfully.
-static bool RunInvocation(const char* BinaryName,
-                          clang::driver::Compilation* Compilation,
-                          clang::CompilerInvocation* Invocation,
-                          const clang::driver::ArgStringList& CC1Args,
-                          clang::FrontendAction* ToolAction) {
+static bool RunInvocation(const char *BinaryName,
+                          clang::driver::Compilation *Compilation,
+                          clang::CompilerInvocation *Invocation,
+                          const clang::driver::ArgStringList &CC1Args,
+                          clang::FrontendAction *ToolAction) {
   llvm::OwningPtr<clang::FrontendAction> ScopedToolAction(ToolAction);
   // Show the invocation, with -v.
   if (Invocation->getHeaderSearchOpts().Verbose) {
@@ -164,7 +164,7 @@
   if (Compiler.getHeaderSearchOpts().UseBuiltinIncludes &&
       Compiler.getHeaderSearchOpts().ResourceDir.empty()) {
     // This just needs to be some symbol in the binary.
-    void* const SymbolAddr = &StaticSymbol;
+    void *const SymbolAddr = &StaticSymbol;
     Compiler.getHeaderSearchOpts().ResourceDir =
         clang::CompilerInvocation::GetResourcesPath(BinaryName, SymbolAddr);
   }
@@ -175,7 +175,7 @@
 
 /// \brief Converts a string vector representing a Command line into a C
 /// string vector representing the Argv (including the trailing NULL).
-std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command) {
+std::vector<char*> CommandLineToArgv(const std::vector<std::string> *Command) {
   std::vector<char*> Result(Command->size() + 1);
   for (std::vector<char*>::size_type I = 0; I < Command->size(); ++I) {
     Result[I] = const_cast<char*>((*Command)[I].c_str());
@@ -185,14 +185,14 @@
 }
 
 bool RunToolWithFlags(
-    clang::FrontendAction* ToolAction, int Args, char* Argv[]) {
+    clang::FrontendAction *ToolAction, int Args, char *Argv[]) {
   ValidateArgv(Args, Argv);
   const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics());
   const llvm::OwningPtr<clang::driver::Driver> Driver(
       NewDriver(Diagnostics.get(), Argv[0]));
   const llvm::OwningPtr<clang::driver::Compilation> Compilation(
       Driver->BuildCompilation(llvm::ArrayRef<const char*>(Argv, Args)));
-  const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments(
+  const clang::driver::ArgStringList *const CC1Args = GetCC1Arguments(
       Diagnostics.get(), Compilation.get());
   if (CC1Args == NULL) {
     return false;
@@ -208,11 +208,11 @@
 /// \param FileContents A mapping from file name to source code. For each
 /// entry a virtual file mapping will be created when running the tool.
 bool RunToolWithFlagsOnCode(
-    const std::vector<std::string>& CommandLine,
-    const std::map<std::string, std::string>& FileContents,
-    clang::FrontendAction* ToolAction) {
+    const std::vector<std::string> &CommandLine,
+    const std::map<std::string, std::string> &FileContents,
+    clang::FrontendAction *ToolAction) {
   const std::vector<char*> Argv = CommandLineToArgv(&CommandLine);
-  const char* const BinaryName = Argv[0];
+  const char *const BinaryName = Argv[0];
 
   const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics());
   const llvm::OwningPtr<clang::driver::Driver> Driver(
@@ -224,7 +224,7 @@
   const llvm::OwningPtr<clang::driver::Compilation> Compilation(
       Driver->BuildCompilation(llvm::ArrayRef<const char*>(&Argv[0],
                                                            Argv.size() - 1)));
-  const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments(
+  const clang::driver::ArgStringList *const CC1Args = GetCC1Arguments(
       Diagnostics.get(), Compilation.get());
   if (CC1Args == NULL) {
     return false;
@@ -236,7 +236,7 @@
            It = FileContents.begin(), End = FileContents.end();
        It != End; ++It) {
     // Inject the code as the given file name into the preprocessor options.
-    const llvm::MemoryBuffer* Input =
+    const llvm::MemoryBuffer *Input =
         llvm::MemoryBuffer::getMemBuffer(It->second.c_str());
     Invocation->getPreprocessorOpts().addRemappedFile(It->first.c_str(), Input);
   }
@@ -247,8 +247,8 @@
 
 bool RunSyntaxOnlyToolOnCode(
     clang::FrontendAction *ToolAction, llvm::StringRef Code) {
-  const char* const FileName = "input.cc";
-  const char* const CommandLine[] = {
+  const char *const FileName = "input.cc";
+  const char *const CommandLine[] = {
       "clang-tool", "-fsyntax-only", FileName
   };
   std::map<std::string, std::string> FileContents;

Added: cfe/trunk/test/Tooling/remove-cstr-calls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Tooling/remove-cstr-calls.cpp?rev=132374&view=auto
==============================================================================
--- cfe/trunk/test/Tooling/remove-cstr-calls.cpp (added)
+++ cfe/trunk/test/Tooling/remove-cstr-calls.cpp Tue May 31 18:49:32 2011
@@ -0,0 +1,20 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo '[{"directory":".","command":"clang++ '$(llvm-config --cppflags all)' -c %s","file":"%s"}]' > %t/compile_commands.json
+// RUN: remove-cstr-calls %t %s | FileCheck %s
+
+#include <string>
+
+namespace llvm { struct StringRef { StringRef(const char *p); }; }
+
+void f1(const std::string &s) {
+  f1(s.c_str());  // CHECK:remove-cstr-calls.cpp:11:6:11:14:s
+}
+void f2(const llvm::StringRef r) {
+  std::string s;
+  f2(s.c_str());  // CHECK:remove-cstr-calls.cpp:15:6:15:14:s
+}
+void f3(const llvm::StringRef &r) {
+  std::string s;
+  f3(s.c_str());  // CHECK:remove-cstr-calls.cpp:19:6:19:14:s
+}

Modified: cfe/trunk/unittests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/CMakeLists.txt?rev=132374&r1=132373&r2=132374&view=diff
==============================================================================
--- cfe/trunk/unittests/CMakeLists.txt (original)
+++ cfe/trunk/unittests/CMakeLists.txt Tue May 31 18:49:32 2011
@@ -69,3 +69,8 @@
   Tooling/JsonCompileCommandLineDatabaseTest.cpp
   USED_LIBS gtest gtest_main clangTooling
  )
+
+add_clang_unittest(ASTMatchersTest
+  Tooling/ASTMatchersTest.cpp
+  USED_LIBS gtest gtest_main clangTooling
+  )

Added: cfe/trunk/unittests/Tooling/ASTMatchersTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/ASTMatchersTest.cpp?rev=132374&view=auto
==============================================================================
--- cfe/trunk/unittests/Tooling/ASTMatchersTest.cpp (added)
+++ cfe/trunk/unittests/Tooling/ASTMatchersTest.cpp Tue May 31 18:49:32 2011
@@ -0,0 +1,1602 @@
+//===- unittest/Tooling/ASTMatchersTest.cpp - AST matcher unit tests ------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/ASTMatchers.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tooling {
+
+using match::AnyOf;
+using match::AllOf;
+using match::ArgumentCountIs;
+using match::BinaryOperator;
+using match::BoolLiteral;
+using match::StringLiteral;
+using match::IntegerLiteral;
+using match::CharacterLiteral;
+using match::Call;
+using match::Callee;
+using match::Class;
+using match::CompoundStatement;
+using match::ConstructorCall;
+using match::DeclarationMatcher;
+using match::DefaultArgument;
+using match::ConditionalOperator;
+using match::DeclarationReference;
+using match::Expression;
+using match::Equals;
+using match::For;
+using match::Has;
+using match::HasAnyArgument;
+using match::HasAnyParameter;
+using match::HasAnySubstatement;
+using match::HasArgument;
+using match::HasBody;
+using match::HasCondition;
+using match::HasDeclaration;
+using match::HasDescendant;
+using match::HasEitherOperand;
+using match::HasFalseExpression;
+using match::HasInitializer;
+using match::HasLHS;
+using match::HasName;
+using match::HasUnaryOperand;
+using match::HasOperatorName;
+using match::HasOverloadedOperatorName;
+using match::HasParameter;
+using match::HasRHS;
+using match::HasTrueExpression;
+using match::HasType;
+using match::Id;
+using match::If;
+using match::IsArrow;
+using match::IsDefinition;
+using match::IsDerivedFrom;
+using match::MemberExpression;
+using match::Method;
+using match::Not;
+using match::OfClass;
+using match::On;
+using match::OverloadedOperatorCall;
+using match::PointsTo;
+using match::References;
+using match::StatementCountIs;
+using match::StatementMatcher;
+using match::ThisPointerType;
+using match::To;
+using match::TypeMatcher;
+using match::UnaryOperator;
+using match::Variable;
+
+class BoundNodesCallback {
+ public:
+  virtual ~BoundNodesCallback() {}
+  virtual bool Run(const BoundNodes *BoundNodes) = 0;
+};
+
+// If 'FindResultVerifier' is not NULL, sets *Verified to the result of
+// running 'FindResultVerifier' with the bound nodes as argument.
+// If 'FindResultVerifier' is NULL, sets *Verified to true when Run is called.
+class VerifyMatch : public MatchFinder::MatchCallback {
+ public:
+  VerifyMatch(BoundNodesCallback *FindResultVerifier, bool *Verified)
+      : Verified(Verified), FindResultReviewer(FindResultVerifier) {}
+
+  virtual void Run(const MatchFinder::MatchResult &Result) {
+    if (FindResultReviewer != NULL) {
+      *Verified = FindResultReviewer->Run(&Result.Nodes);
+    } else {
+      *Verified = true;
+    }
+  }
+
+ private:
+  bool *const Verified;
+  BoundNodesCallback *const FindResultReviewer;
+};
+
+template <typename T>
+testing::AssertionResult MatchesConditionally(
+    const std::string &Code, const T &AMatcher, bool ExpectMatch) {
+  bool Found = false;
+  MatchFinder Finder;
+  Finder.AddMatcher(AMatcher, new VerifyMatch(NULL, &Found));
+  if (!Finder.FindAll(Code)) {
+    return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+  }
+  if (!Found && ExpectMatch) {
+    return testing::AssertionFailure()
+        << "Could not find match in \"" << Code << "\"";
+  } else if (Found && !ExpectMatch) {
+    return testing::AssertionFailure()
+        << "Found unexpected match in \"" << Code << "\"";
+  }
+  return testing::AssertionSuccess();
+}
+
+template <typename T>
+testing::AssertionResult Matches(const std::string &Code, const T &AMatcher) {
+  return MatchesConditionally(Code, AMatcher, true);
+}
+
+template <typename T>
+testing::AssertionResult NotMatches(
+    const std::string &Code, const T &AMatcher) {
+  return MatchesConditionally(Code, AMatcher, false);
+}
+
+template <typename T>
+testing::AssertionResult MatchAndVerifyResultConditionally(
+    const std::string &Code, const T &AMatcher,
+    BoundNodesCallback *FindResultVerifier, bool ExpectResult) {
+  llvm::OwningPtr<BoundNodesCallback> ScopedVerifier(FindResultVerifier);
+  bool VerifiedResult = false;
+  MatchFinder Finder;
+  Finder.AddMatcher(
+      AMatcher, new VerifyMatch(FindResultVerifier, &VerifiedResult));
+  if (!Finder.FindAll(Code)) {
+    return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+  }
+  if (!VerifiedResult && ExpectResult) {
+    return testing::AssertionFailure()
+        << "Could not verify result in \"" << Code << "\"";
+  } else if (VerifiedResult && !ExpectResult) {
+    return testing::AssertionFailure()
+        << "Verified unexpected result in \"" << Code << "\"";
+  }
+  return testing::AssertionSuccess();
+}
+
+// FIXME: Find better names for these functions (or document what they
+// do more precisely).
+template <typename T>
+testing::AssertionResult MatchAndVerifyResultTrue(
+    const std::string &Code, const T &AMatcher,
+    BoundNodesCallback *FindResultVerifier) {
+  return MatchAndVerifyResultConditionally(
+      Code, AMatcher, FindResultVerifier, true);
+}
+
+template <typename T>
+testing::AssertionResult MatchAndVerifyResultFalse(
+    const std::string &Code, const T &AMatcher,
+    BoundNodesCallback *FindResultVerifier) {
+  return MatchAndVerifyResultConditionally(
+      Code, AMatcher, FindResultVerifier, false);
+}
+
+TEST(HasNameDeathTest, DiesOnEmptyName) {
+  ASSERT_DEBUG_DEATH({
+      DeclarationMatcher HasEmptyName = Class(HasName(""));
+      EXPECT_TRUE(NotMatches("class X {};", HasEmptyName));
+    }, "");
+}
+
+TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) {
+  ASSERT_DEBUG_DEATH({
+      DeclarationMatcher IsDerivedFromEmpty = Class(IsDerivedFrom(""));
+      EXPECT_TRUE(NotMatches("class X {};", IsDerivedFromEmpty));
+    }, "");
+}
+
+TEST(DeclarationMatcher, MatchClass) {
+  DeclarationMatcher ClassMatcher(Class());
+  // Even for an empty string there are classes in the AST.
+  EXPECT_TRUE(Matches("", ClassMatcher));
+
+  DeclarationMatcher ClassX = Class(Class(HasName("X")));
+  EXPECT_TRUE(Matches("class X;", ClassX));
+  EXPECT_TRUE(Matches("class X {};", ClassX));
+  EXPECT_TRUE(Matches("template<class T> class X {};", ClassX));
+  EXPECT_TRUE(NotMatches("", ClassX));
+}
+
+TEST(DeclarationMatcher, ClassIsDerived) {
+  DeclarationMatcher IsDerivedFromX = Class(IsDerivedFrom("X"));
+
+  EXPECT_TRUE(Matches("class X {}; class Y : public X {};", IsDerivedFromX));
+  EXPECT_TRUE(Matches("class X {}; class Y : public X {};", IsDerivedFromX));
+  EXPECT_TRUE(Matches("class X {};", IsDerivedFromX));
+  EXPECT_TRUE(Matches("class X;", IsDerivedFromX));
+  EXPECT_TRUE(NotMatches("class Y;", IsDerivedFromX));
+  EXPECT_TRUE(NotMatches("", IsDerivedFromX));
+
+  DeclarationMatcher ZIsDerivedFromX =
+      Class(HasName("Z"), IsDerivedFrom("X"));
+  EXPECT_TRUE(
+      Matches("class X {}; class Y : public X {}; class Z : public Y {};",
+              ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("class X {};"
+              "template<class T> class Y : public X {};"
+              "class Z : public Y<int> {};", ZIsDerivedFromX));
+  EXPECT_TRUE(Matches("class X {}; template<class T> class Z : public X {};",
+                      ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("template<class T> class X {}; "
+              "template<class T> class Z : public X<T> {};",
+              ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("template<class T, class U=T> class X {}; "
+              "template<class T> class Z : public X<T> {};",
+              ZIsDerivedFromX));
+  EXPECT_TRUE(
+      NotMatches("template<class X> class A { class Z : public X {}; };",
+                 ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("template<class X> class A { public: class Z : public X {}; }; "
+              "class X{}; void y() { A<X>::Z z; }", ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("template <class T> class X {}; "
+              "template<class Y> class A { class Z : public X<Y> {}; };",
+              ZIsDerivedFromX));
+  EXPECT_TRUE(
+      NotMatches("template<template<class T> class X> class A { "
+                 "  class Z : public X<int> {}; };", ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("template<template<class T> class X> class A { "
+              "  public: class Z : public X<int> {}; }; "
+              "template<class T> class X {}; void y() { A<X>::Z z; }",
+              ZIsDerivedFromX));
+  EXPECT_TRUE(
+      NotMatches("template<class X> class A { class Z : public X::D {}; };",
+                 ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("template<class X> class A { public: "
+              "  class Z : public X::D {}; }; "
+              "class Y { public: class X {}; typedef X D; }; "
+              "void y() { A<Y>::Z z; }", ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("class X {}; typedef X Y; class Z : public Y {};",
+              ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("template<class T> class Y { typedef typename T::U X; "
+              "  class Z : public X {}; };", ZIsDerivedFromX));
+  EXPECT_TRUE(Matches("class X {}; class Z : public ::X {};",
+                      ZIsDerivedFromX));
+  EXPECT_TRUE(
+      NotMatches("template<class T> class X {}; "
+                "template<class T> class A { class Z : public X<T>::D {}; };",
+                ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("template<class T> class X { public: typedef X<T> D; }; "
+              "template<class T> class A { public: "
+              "  class Z : public X<T>::D {}; }; void y() { A<int>::Z z; }",
+              ZIsDerivedFromX));
+  EXPECT_TRUE(
+      NotMatches("template<class X> class A { class Z : public X::D::E {}; };",
+                 ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("class X {}; typedef X V; typedef V W; class Z : public W {};",
+              ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("class X {}; class Y : public X {}; "
+              "typedef Y V; typedef V W; class Z : public W {};",
+              ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("template<class T, class U> class X {}; "
+              "template<class T> class A { class Z : public X<T, int> {}; };",
+              ZIsDerivedFromX));
+  EXPECT_TRUE(
+      NotMatches("template<class X> class D { typedef X A; typedef A B; "
+                 "  typedef B C; class Z : public C {}; };",
+                 ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("class X {}; typedef X A; typedef A B; "
+              "class Z : public B {};", ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("class X {}; typedef X A; typedef A B; typedef B C; "
+              "class Z : public C {};", ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("class U {}; typedef U X; typedef X V; "
+              "class Z : public V {};", ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("class Base {}; typedef Base X; "
+              "class Z : public Base {};", ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("class Base {}; typedef Base Base2; typedef Base2 X; "
+              "class Z : public Base {};", ZIsDerivedFromX));
+  EXPECT_TRUE(
+      NotMatches("class Base {}; class Base2 {}; typedef Base2 X; "
+                 "class Z : public Base {};", ZIsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("class A {}; typedef A X; typedef A Y; "
+              "class Z : public Y {};", ZIsDerivedFromX));
+  EXPECT_TRUE(
+      NotMatches("template <typename T> class Z;"
+                 "template <> class Z<void> {};"
+                 "template <typename T> class Z : public Z<void> {};",
+                 IsDerivedFromX));
+  EXPECT_TRUE(
+      Matches("template <typename T> class X;"
+              "template <> class X<void> {};"
+              "template <typename T> class X : public X<void> {};",
+              IsDerivedFromX));
+  EXPECT_TRUE(Matches(
+      "class X {};"
+      "template <typename T> class Z;"
+      "template <> class Z<void> {};"
+      "template <typename T> class Z : public Z<void>, public X {};",
+      ZIsDerivedFromX));
+
+  // FIXME: Once we have better matchers for template type matching,
+  // get rid of the Variable(...) matching and match the right template
+  // declarations directly.
+  const char *RecursiveTemplateOneParameter =
+      "class Base1 {}; class Base2 {};"
+      "template <typename T> class Z;"
+      "template <> class Z<void> : public Base1 {};"
+      "template <> class Z<int> : public Base2 {};"
+      "template <> class Z<float> : public Z<void> {};"
+      "template <> class Z<double> : public Z<int> {};"
+      "template <typename T> class Z : public Z<float>, public Z<double> {};"
+      "void f() { Z<float> z_float; Z<double> z_double; Z<char> z_char; }";
+  EXPECT_TRUE(Matches(
+      RecursiveTemplateOneParameter,
+      Variable(HasName("z_float"),
+               HasInitializer(HasType(Class(IsDerivedFrom("Base1")))))));
+  EXPECT_TRUE(NotMatches(
+      RecursiveTemplateOneParameter,
+      Variable(
+          HasName("z_float"),
+          HasInitializer(HasType(Class(IsDerivedFrom("Base2")))))));
+  EXPECT_TRUE(Matches(
+      RecursiveTemplateOneParameter,
+      Variable(
+          HasName("z_char"),
+          HasInitializer(HasType(Class(IsDerivedFrom("Base1"),
+                                       IsDerivedFrom("Base2")))))));
+
+  const char *RecursiveTemplateTwoParameters =
+      "class Base1 {}; class Base2 {};"
+      "template <typename T1, typename T2> class Z;"
+      "template <typename T> class Z<void, T> : public Base1 {};"
+      "template <typename T> class Z<int, T> : public Base2 {};"
+      "template <typename T> class Z<float, T> : public Z<void, T> {};"
+      "template <typename T> class Z<double, T> : public Z<int, T> {};"
+      "template <typename T1, typename T2> class Z : "
+      "    public Z<float, T2>, public Z<double, T2> {};"
+      "void f() { Z<float, void> z_float; Z<double, void> z_double; "
+      "           Z<char, void> z_char; }";
+  EXPECT_TRUE(Matches(
+      RecursiveTemplateTwoParameters,
+      Variable(
+          HasName("z_float"),
+          HasInitializer(HasType(Class(IsDerivedFrom("Base1")))))));
+  EXPECT_TRUE(NotMatches(
+      RecursiveTemplateTwoParameters,
+      Variable(
+          HasName("z_float"),
+          HasInitializer(HasType(Class(IsDerivedFrom("Base2")))))));
+  EXPECT_TRUE(Matches(
+      RecursiveTemplateTwoParameters,
+      Variable(
+          HasName("z_char"),
+          HasInitializer(HasType(Class(IsDerivedFrom("Base1"),
+                                       IsDerivedFrom("Base2")))))));
+}
+
+TEST(DeclarationMatcher, MatchAnyOf) {
+  DeclarationMatcher YOrZDerivedFromX =
+      Class(AnyOf(HasName("Y"), AllOf(IsDerivedFrom("X"), HasName("Z"))));
+
+  EXPECT_TRUE(
+      Matches("class X {}; class Z : public X {};", YOrZDerivedFromX));
+  EXPECT_TRUE(Matches("class Y {};", YOrZDerivedFromX));
+  EXPECT_TRUE(
+      NotMatches("class X {}; class W : public X {};", YOrZDerivedFromX));
+  EXPECT_TRUE(NotMatches("class Z {};", YOrZDerivedFromX));
+
+  DeclarationMatcher XOrYOrZOrU =
+      Class(AnyOf(HasName("X"), HasName("Y"), HasName("Z"), HasName("U")));
+
+  EXPECT_TRUE(Matches("class X {};", XOrYOrZOrU));
+  EXPECT_TRUE(Matches("class Y {};", XOrYOrZOrU));
+  EXPECT_TRUE(Matches("class Z {};", XOrYOrZOrU));
+  EXPECT_TRUE(Matches("class U {};", XOrYOrZOrU));
+  EXPECT_TRUE(NotMatches("class A {};", XOrYOrZOrU));
+}
+
+TEST(DeclarationMatcher, MatchHas) {
+  DeclarationMatcher HasClassX = Class(Has(Class(HasName("X"))));
+
+  EXPECT_TRUE(Matches("class Y { class X {}; };", HasClassX));
+  EXPECT_TRUE(Matches("class X {};", HasClassX));
+
+  DeclarationMatcher YHasClassX =
+      Class(HasName("Y"), Has(Class(HasName("X"))));
+  EXPECT_TRUE(Matches("class Y { class X {}; };", YHasClassX));
+  EXPECT_TRUE(NotMatches("class X {};", YHasClassX));
+  EXPECT_TRUE(
+      NotMatches("class Y { class Z { class X {}; }; };", YHasClassX));
+}
+
+TEST(DeclarationMatcher, MatchHasRecursiveAllOf) {
+  DeclarationMatcher Recursive =
+      Class(
+          Has(Class(
+              Has(Class(
+                  HasName("X"))),
+              Has(Class(
+                  HasName("Y"))),
+              HasName("Z"))),
+          Has(Class(
+              Has(Class(
+                  HasName("A"))),
+              Has(Class(
+                  HasName("B"))),
+              HasName("C"))),
+          HasName("F"));
+
+  EXPECT_TRUE(Matches(
+      "class F {"
+      "  class Z {"
+      "    class X {};"
+      "    class Y {};"
+      "  };"
+      "  class C {"
+      "    class A {};"
+      "    class B {};"
+      "  };"
+      "};", Recursive));
+
+  EXPECT_TRUE(Matches(
+      "class F {"
+      "  class Z {"
+      "    class A {};"
+      "    class X {};"
+      "    class Y {};"
+      "  };"
+      "  class C {"
+      "    class X {};"
+      "    class A {};"
+      "    class B {};"
+      "  };"
+      "};", Recursive));
+
+  EXPECT_TRUE(Matches(
+      "class O1 {"
+      "  class O2 {"
+      "    class F {"
+      "      class Z {"
+      "        class A {};"
+      "        class X {};"
+      "        class Y {};"
+      "      };"
+      "      class C {"
+      "        class X {};"
+      "        class A {};"
+      "        class B {};"
+      "      };"
+      "    };"
+      "  };"
+      "};", Recursive));
+}
+
+TEST(DeclarationMatcher, MatchHasRecursiveAnyOf) {
+  DeclarationMatcher Recursive =
+      Class(
+          AnyOf(
+              Has(Class(
+                  AnyOf(
+                      Has(Class(
+                          HasName("X"))),
+                      Has(Class(
+                          HasName("Y"))),
+                      HasName("Z")))),
+              Has(Class(
+                  AnyOf(
+                      HasName("C"),
+                      Has(Class(
+                          HasName("A"))),
+                      Has(Class(
+                          HasName("B")))))),
+              HasName("F")));
+
+  EXPECT_TRUE(Matches("class F {};", Recursive));
+  EXPECT_TRUE(Matches("class Z {};", Recursive));
+  EXPECT_TRUE(Matches("class C {};", Recursive));
+  EXPECT_TRUE(Matches("class M { class N { class X {}; }; };", Recursive));
+  EXPECT_TRUE(Matches("class M { class N { class B {}; }; };", Recursive));
+  EXPECT_TRUE(
+      Matches("class O1 { class O2 {"
+              "  class M { class N { class B {}; }; }; "
+              "}; };", Recursive));
+}
+
+TEST(DeclarationMatcher, MatchNot) {
+  DeclarationMatcher NotClassX =
+      Class(
+          IsDerivedFrom("Y"),
+          Not(HasName("Y")),
+          Not(HasName("X")));
+  EXPECT_TRUE(NotMatches("", NotClassX));
+  EXPECT_TRUE(NotMatches("class Y {};", NotClassX));
+  EXPECT_TRUE(Matches("class Y {}; class Z : public Y {};", NotClassX));
+  EXPECT_TRUE(NotMatches("class Y {}; class X : public Y {};", NotClassX));
+  EXPECT_TRUE(
+      NotMatches("class Y {}; class Z {}; class X : public Y {};",
+                 NotClassX));
+
+  DeclarationMatcher ClassXHasNotClassY =
+      Class(
+          HasName("X"),
+          Has(Class(HasName("Z"))),
+          Not(
+              Has(Class(HasName("Y")))));
+  EXPECT_TRUE(Matches("class X { class Z {}; };", ClassXHasNotClassY));
+  EXPECT_TRUE(NotMatches("class X { class Y {}; class Z {}; };",
+                         ClassXHasNotClassY));
+}
+
+TEST(DeclarationMatcher, HasDescendant) {
+  DeclarationMatcher ZDescendantClassX =
+      Class(
+          HasDescendant(Class(HasName("X"))),
+          HasName("Z"));
+  EXPECT_TRUE(Matches("class Z { class X {}; };", ZDescendantClassX));
+  EXPECT_TRUE(
+      Matches("class Z { class Y { class X {}; }; };", ZDescendantClassX));
+  EXPECT_TRUE(
+      Matches("class Z { class A { class Y { class X {}; }; }; };",
+              ZDescendantClassX));
+  EXPECT_TRUE(
+      Matches("class Z { class A { class B { class Y { class X {}; }; }; }; };",
+              ZDescendantClassX));
+  EXPECT_TRUE(NotMatches("class Z {};", ZDescendantClassX));
+
+  DeclarationMatcher ZDescendantClassXHasClassY =
+      Class(
+          HasDescendant(Class(Has(Class(HasName("Y"))),
+                              HasName("X"))),
+          HasName("Z"));
+  EXPECT_TRUE(Matches("class Z { class X { class Y {}; }; };",
+              ZDescendantClassXHasClassY));
+  EXPECT_TRUE(
+      Matches("class Z { class A { class B { class X { class Y {}; }; }; }; };",
+              ZDescendantClassXHasClassY));
+  EXPECT_TRUE(NotMatches(
+      "class Z {"
+      "  class A {"
+      "    class B {"
+      "      class X {"
+      "        class C {"
+      "          class Y {};"
+      "        };"
+      "      };"
+      "    }; "
+      "  };"
+      "};", ZDescendantClassXHasClassY));
+
+  DeclarationMatcher ZDescendantClassXDescendantClassY =
+      Class(
+          HasDescendant(Class(HasDescendant(Class(HasName("Y"))),
+                              HasName("X"))),
+          HasName("Z"));
+  EXPECT_TRUE(
+      Matches("class Z { class A { class X { class B { class Y {}; }; }; }; };",
+              ZDescendantClassXDescendantClassY));
+  EXPECT_TRUE(Matches(
+      "class Z {"
+      "  class A {"
+      "    class X {"
+      "      class B {"
+      "        class Y {};"
+      "      };"
+      "      class Y {};"
+      "    };"
+      "  };"
+      "};", ZDescendantClassXDescendantClassY));
+}
+
+TEST(StatementMatcher, Has) {
+  StatementMatcher HasVariableI =
+      Expression(
+          HasType(PointsTo(Class(HasName("X")))),
+          Has(DeclarationReference(To(Variable(HasName("i"))))));
+
+  EXPECT_TRUE(Matches(
+      "class X; X *x(int); void c() { int i; x(i); }", HasVariableI));
+  EXPECT_TRUE(NotMatches(
+      "class X; X *x(int); void c() { int i; x(42); }", HasVariableI));
+}
+
+TEST(StatementMatcher, HasDescendant) {
+  StatementMatcher HasDescendantVariableI =
+      Expression(
+          HasType(PointsTo(Class(HasName("X")))),
+          HasDescendant(DeclarationReference(To(Variable(HasName("i"))))));
+
+  EXPECT_TRUE(Matches(
+      "class X; X *x(bool); bool b(int); void c() { int i; x(b(i)); }",
+      HasDescendantVariableI));
+  EXPECT_TRUE(NotMatches(
+      "class X; X *x(bool); bool b(int); void c() { int i; x(b(42)); }",
+      HasDescendantVariableI));
+}
+
+TEST(TypeMatcher, MatchesClassType) {
+  TypeMatcher TypeA = HasDeclaration(Class(HasName("A")));
+
+  EXPECT_TRUE(Matches("class A { public: A *a; };", TypeA));
+  EXPECT_TRUE(NotMatches("class A {};", TypeA));
+
+  TypeMatcher TypeDerivedFromA = HasDeclaration(Class(IsDerivedFrom("A")));
+
+  EXPECT_TRUE(Matches("class A {}; class B : public A { public: B *b; };",
+              TypeDerivedFromA));
+  EXPECT_TRUE(NotMatches("class A {};", TypeA));
+
+  TypeMatcher TypeAHasClassB = HasDeclaration(
+      Class(HasName("A"), Has(Class(HasName("B")))));
+
+  EXPECT_TRUE(
+      Matches("class A { public: A *a; class B {}; };", TypeAHasClassB));
+}
+
+// Returns whether 'bound_nodes' contain a Decl for bound to 'id', which
+// can be dynamically casted to T.
+template <typename T>
+class VerifyIdIsBoundToDecl : public BoundNodesCallback {
+ public:
+  explicit VerifyIdIsBoundToDecl(const std::string &Id) : Id(Id) {}
+  virtual bool Run(const BoundNodes *Nodes) {
+    const T *Node = Nodes->GetDeclAs<T>(Id);
+    return Node != NULL;
+  }
+
+ private:
+  const std::string Id;
+};
+template <typename T>
+class VerifyIdIsBoundToStmt : public BoundNodesCallback {
+ public:
+  explicit VerifyIdIsBoundToStmt(const std::string &Id) : Id(Id) {}
+  virtual bool Run(const BoundNodes *Nodes) {
+    const T *Node = Nodes->GetStmtAs<T>(Id);
+    return Node != NULL;
+  }
+ private:
+  const std::string Id;
+};
+
+TEST(Matcher, BindMatchedNodes) {
+  DeclarationMatcher ClassX = Has(Id("x", Class(HasName("X"))));
+
+  EXPECT_TRUE(MatchAndVerifyResultTrue("class X {};",
+      ClassX, new VerifyIdIsBoundToDecl<clang::CXXRecordDecl>("x")));
+
+  EXPECT_TRUE(MatchAndVerifyResultFalse("class X {};",
+      ClassX, new VerifyIdIsBoundToDecl<clang::CXXRecordDecl>("other-id")));
+
+  TypeMatcher TypeAHasClassB = HasDeclaration(
+      Class(HasName("A"), Has(Id("b", Class(HasName("B"))))));
+
+  EXPECT_TRUE(MatchAndVerifyResultTrue("class A { public: A *a; class B {}; };",
+      TypeAHasClassB,
+      new VerifyIdIsBoundToDecl<clang::Decl>("b")));
+
+  StatementMatcher MethodX = Id("x", Call(Callee(Method(HasName("x")))));
+
+  EXPECT_TRUE(MatchAndVerifyResultTrue("class A { void x() { x(); } };",
+      MethodX,
+      new VerifyIdIsBoundToStmt<clang::CXXMemberCallExpr>("x")));
+}
+
+TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
+  TypeMatcher ClassX = HasDeclaration(Class(HasName("X")));
+  EXPECT_TRUE(
+      Matches("class X {}; void y(X &x) { x; }", Expression(HasType(ClassX))));
+  EXPECT_TRUE(
+      NotMatches("class X {}; void y(X *x) { x; }",
+                 Expression(HasType(ClassX))));
+  EXPECT_TRUE(
+      Matches("class X {}; void y(X *x) { x; }",
+              Expression(HasType(PointsTo(ClassX)))));
+}
+
+TEST(HasType, TakesQualTypeMatcherAndMatchesValueDecl) {
+  TypeMatcher ClassX = HasDeclaration(Class(HasName("X")));
+  EXPECT_TRUE(
+      Matches("class X {}; void y() { X x; }", Variable(HasType(ClassX))));
+  EXPECT_TRUE(
+      NotMatches("class X {}; void y() { X *x; }", Variable(HasType(ClassX))));
+  EXPECT_TRUE(
+      Matches("class X {}; void y() { X *x; }",
+              Variable(HasType(PointsTo(ClassX)))));
+}
+
+TEST(HasType, TakesDeclMatcherAndMatchesExpr) {
+  DeclarationMatcher ClassX = Class(HasName("X"));
+  EXPECT_TRUE(
+      Matches("class X {}; void y(X &x) { x; }", Expression(HasType(ClassX))));
+  EXPECT_TRUE(
+      NotMatches("class X {}; void y(X *x) { x; }",
+                 Expression(HasType(ClassX))));
+}
+
+TEST(HasType, TakesDeclMatcherAndMatchesValueDecl) {
+  DeclarationMatcher ClassX = Class(HasName("X"));
+  EXPECT_TRUE(
+      Matches("class X {}; void y() { X x; }", Variable(HasType(ClassX))));
+  EXPECT_TRUE(
+      NotMatches("class X {}; void y() { X *x; }", Variable(HasType(ClassX))));
+}
+
+TEST(Matcher, Call) {
+  // FIXME: Do we want to overload Call() to directly take
+  // Matcher<clang::Decl>, too?
+  StatementMatcher MethodX = Call(HasDeclaration(Method(HasName("x"))));
+
+  EXPECT_TRUE(Matches("class Y { void x() { x(); } };", MethodX));
+  EXPECT_TRUE(NotMatches("class Y { void x() {} };", MethodX));
+
+  StatementMatcher MethodOnY = Call(On(HasType(Class(HasName("Y")))));
+
+  EXPECT_TRUE(
+      Matches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
+              MethodOnY));
+  EXPECT_TRUE(
+      Matches("class Y { public: void x(); }; void z(Y &y) { y.x(); }",
+              MethodOnY));
+  EXPECT_TRUE(
+      NotMatches("class Y { public: void x(); }; void z(Y *&y) { y->x(); }",
+                 MethodOnY));
+  EXPECT_TRUE(
+      NotMatches("class Y { public: void x(); }; void z(Y y[]) { y->x(); }",
+                 MethodOnY));
+  EXPECT_TRUE(
+      NotMatches("class Y { public: void x(); }; void z() { Y *y; y->x(); }",
+                 MethodOnY));
+
+  StatementMatcher MethodOnYPointer =
+      Call(On(HasType(PointsTo(Class(HasName("Y"))))));
+
+  EXPECT_TRUE(
+      Matches("class Y { public: void x(); }; void z() { Y *y; y->x(); }",
+              MethodOnYPointer));
+  EXPECT_TRUE(
+      Matches("class Y { public: void x(); }; void z(Y *&y) { y->x(); }",
+              MethodOnYPointer));
+  EXPECT_TRUE(
+      Matches("class Y { public: void x(); }; void z(Y y[]) { y->x(); }",
+              MethodOnYPointer));
+  EXPECT_TRUE(
+      NotMatches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
+                 MethodOnYPointer));
+  EXPECT_TRUE(
+      NotMatches("class Y { public: void x(); }; void z(Y &y) { y.x(); }",
+                 MethodOnYPointer));
+}
+
+TEST(Matcher, OverloadedOperatorCall) {
+  StatementMatcher OpCall = OverloadedOperatorCall();
+  // Unary operator
+  EXPECT_TRUE(Matches("class Y { }; "
+              "bool operator!(Y x) { return false; }; "
+              "Y y; bool c = !y;", OpCall));
+  // No match -- special operators like "new", "delete"
+  // FIXME: figure out why these does not match?
+  EXPECT_TRUE(NotMatches("class Y { }; "
+              "void *operator new(unsigned long size) { return 0; } "
+              "Y *y = new Y;", OpCall));
+  EXPECT_TRUE(NotMatches("class Y { }; "
+              "void operator delete(void *p) { } "
+              "void a() {Y *y = new Y; delete y;}", OpCall));
+  // Binary operator
+  EXPECT_TRUE(Matches("class Y { }; "
+              "bool operator&&(Y x, Y y) { return true; }; "
+              "Y a; Y b; bool c = a && b;",
+              OpCall));
+  // No match -- normal operator, not an overloaded one.
+  EXPECT_TRUE(NotMatches("bool x = true, y = true; bool t = x && y;", OpCall));
+  EXPECT_TRUE(NotMatches("int t = 5 << 2;", OpCall));
+}
+
+TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) {
+  StatementMatcher OpCallAndAnd =
+      OverloadedOperatorCall(HasOverloadedOperatorName("&&"));
+  EXPECT_TRUE(Matches("class Y { }; "
+              "bool operator&&(Y x, Y y) { return true; }; "
+              "Y a; Y b; bool c = a && b;", OpCallAndAnd));
+  StatementMatcher OpCallLessLess =
+      OverloadedOperatorCall(HasOverloadedOperatorName("<<"));
+  EXPECT_TRUE(NotMatches("class Y { }; "
+              "bool operator&&(Y x, Y y) { return true; }; "
+              "Y a; Y b; bool c = a && b;",
+              OpCallLessLess));
+}
+
+TEST(Matcher, ThisPointerType) {
+  StatementMatcher MethodOnY = Call(ThisPointerType(Class(HasName("Y"))));
+
+  EXPECT_TRUE(
+      Matches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
+              MethodOnY));
+  EXPECT_TRUE(
+      Matches("class Y { public: void x(); }; void z(Y &y) { y.x(); }",
+              MethodOnY));
+  EXPECT_TRUE(
+      Matches("class Y { public: void x(); }; void z(Y *&y) { y->x(); }",
+              MethodOnY));
+  EXPECT_TRUE(
+      Matches("class Y { public: void x(); }; void z(Y y[]) { y->x(); }",
+              MethodOnY));
+  EXPECT_TRUE(
+      Matches("class Y { public: void x(); }; void z() { Y *y; y->x(); }",
+              MethodOnY));
+
+  EXPECT_TRUE(Matches(
+      "class Y {"
+      "  public: virtual void x();"
+      "};"
+      "class X : public Y {"
+      "  public: virtual void x();"
+      "};"
+      "void z() { X *x; x->Y::x(); }", MethodOnY));
+}
+
+TEST(Matcher, VariableUsage) {
+  StatementMatcher Reference =
+      DeclarationReference(To(
+          Variable(HasInitializer(
+              Call(ThisPointerType(Class(HasName("Y"))))))));
+
+  EXPECT_TRUE(Matches(
+      "class Y {"
+      " public:"
+      "  bool x() const;"
+      "};"
+      "void z(const Y &y) {"
+      "  bool b = y.x();"
+      "  if (b) {}"
+      "}", Reference));
+
+  EXPECT_TRUE(NotMatches(
+      "class Y {"
+      " public:"
+      "  bool x() const;"
+      "};"
+      "void z(const Y &y) {"
+      "  bool b = y.x();"
+      "}", Reference));
+}
+
+TEST(Matcher, CalledVariable) {
+  StatementMatcher CallOnVariableY = Expression(
+      Call(On(DeclarationReference(To(Variable(HasName("y")))))));
+
+  EXPECT_TRUE(Matches(
+      "class Y { public: void x() { Y y; y.x(); } };", CallOnVariableY));
+  EXPECT_TRUE(Matches(
+      "class Y { public: void x() const { Y y; y.x(); } };", CallOnVariableY));
+  EXPECT_TRUE(Matches(
+      "class Y { public: void x(); };"
+      "class X : public Y { void z() { X y; y.x(); } };", CallOnVariableY));
+  EXPECT_TRUE(Matches(
+      "class Y { public: void x(); };"
+      "class X : public Y { void z() { X *y; y->x(); } };", CallOnVariableY));
+  EXPECT_TRUE(NotMatches(
+      "class Y { public: void x(); };"
+      "class X : public Y { void z() { unsigned long y; ((X*)y)->x(); } };",
+      CallOnVariableY));
+}
+
+TEST(MemberExpression, DoesNotMatchClasses) {
+  EXPECT_TRUE(NotMatches("class Y { void x() {} };", MemberExpression()));
+}
+
+TEST(MemberExpression, MatchesMemberFunctionCall) {
+  EXPECT_TRUE(Matches("class Y { void x() { x(); } };", MemberExpression()));
+}
+
+TEST(MemberExpression, MatchesVariable) {
+  EXPECT_TRUE(
+      Matches("class Y { void x() { this->y; } int y; };", MemberExpression()));
+  EXPECT_TRUE(
+      Matches("class Y { void x() { y; } int y; };", MemberExpression()));
+  EXPECT_TRUE(
+      Matches("class Y { void x() { Y y; y.y; } int y; };",
+              MemberExpression()));
+}
+
+TEST(MemberExpression, MatchesStaticVariable) {
+  EXPECT_TRUE(Matches("class Y { void x() { this->y; } static int y; };",
+              MemberExpression()));
+  EXPECT_TRUE(NotMatches("class Y { void x() { y; } static int y; };",
+              MemberExpression()));
+  EXPECT_TRUE(NotMatches("class Y { void x() { Y::y; } static int y; };",
+              MemberExpression()));
+}
+
+TEST(IsArrow, MatchesMemberVariablesViaArrow) {
+  EXPECT_TRUE(Matches("class Y { void x() { this->y; } int y; };",
+              MemberExpression(IsArrow())));
+  EXPECT_TRUE(Matches("class Y { void x() { y; } int y; };",
+              MemberExpression(IsArrow())));
+  EXPECT_TRUE(NotMatches("class Y { void x() { (*this).y; } int y; };",
+              MemberExpression(IsArrow())));
+}
+
+TEST(IsArrow, MatchesStaticMemberVariablesViaArrow) {
+  EXPECT_TRUE(Matches("class Y { void x() { this->y; } static int y; };",
+              MemberExpression(IsArrow())));
+  EXPECT_TRUE(NotMatches("class Y { void x() { y; } static int y; };",
+              MemberExpression(IsArrow())));
+  EXPECT_TRUE(NotMatches("class Y { void x() { (*this).y; } static int y; };",
+              MemberExpression(IsArrow())));
+}
+
+TEST(IsArrow, MatchesMemberCallsViaArrow) {
+  EXPECT_TRUE(Matches("class Y { void x() { this->x(); } };",
+              MemberExpression(IsArrow())));
+  EXPECT_TRUE(Matches("class Y { void x() { x(); } };",
+              MemberExpression(IsArrow())));
+  EXPECT_TRUE(NotMatches("class Y { void x() { Y y; y.x(); } };",
+              MemberExpression(IsArrow())));
+}
+
+TEST(Callee, MatchesDeclarations) {
+  StatementMatcher CallMethodX = Call(Callee(Method(HasName("x"))));
+
+  EXPECT_TRUE(Matches("class Y { void x() { x(); } };", CallMethodX));
+  EXPECT_TRUE(NotMatches("class Y { void x() {} };", CallMethodX));
+}
+
+TEST(Callee, MatchesMemberExpressions) {
+  EXPECT_TRUE(Matches("class Y { void x() { this->x(); } };",
+              Call(Callee(MemberExpression()))));
+  EXPECT_TRUE(
+      NotMatches("class Y { void x() { this->x(); } };", Call(Callee(Call()))));
+}
+
+TEST(Matcher, Argument) {
+  StatementMatcher CallArgumentY = Expression(Call(
+      HasArgument(0, DeclarationReference(To(Variable(HasName("y")))))));
+
+  EXPECT_TRUE(Matches("void x(int) { int y; x(y); }", CallArgumentY));
+  EXPECT_TRUE(
+      Matches("class X { void x(int) { int y; x(y); } };", CallArgumentY));
+  EXPECT_TRUE(NotMatches("void x(int) { int z; x(z); }", CallArgumentY));
+
+  StatementMatcher WrongIndex = Expression(Call(
+      HasArgument(42, DeclarationReference(To(Variable(HasName("y")))))));
+  EXPECT_TRUE(NotMatches("void x(int) { int y; x(y); }", WrongIndex));
+}
+
+TEST(Matcher, AnyArgument) {
+  StatementMatcher CallArgumentY = Expression(Call(
+      HasAnyArgument(DeclarationReference(To(Variable(HasName("y")))))));
+  EXPECT_TRUE(Matches("void x(int, int) { int y; x(1, y); }", CallArgumentY));
+  EXPECT_TRUE(Matches("void x(int, int) { int y; x(y, 42); }", CallArgumentY));
+  EXPECT_TRUE(NotMatches("void x(int, int) { x(1, 2); }", CallArgumentY));
+}
+
+TEST(Matcher, ArgumentCount) {
+  StatementMatcher Call1Arg = Expression(Call(ArgumentCountIs(1)));
+
+  EXPECT_TRUE(Matches("void x(int) { x(0); }", Call1Arg));
+  EXPECT_TRUE(Matches("class X { void x(int) { x(0); } };", Call1Arg));
+  EXPECT_TRUE(NotMatches("void x(int, int) { x(0, 0); }", Call1Arg));
+}
+
+TEST(Matcher, References) {
+  DeclarationMatcher ReferenceClassX = Variable(
+      HasType(References(Class(HasName("X")))));
+  EXPECT_TRUE(Matches("class X {}; void y(X y) { X &x = y; }", ReferenceClassX));
+  EXPECT_TRUE(
+      Matches("class X {}; void y(X y) { const X &x = y; }", ReferenceClassX));
+  EXPECT_TRUE(
+      NotMatches("class X {}; void y(X y) { X x = y; }", ReferenceClassX));
+  EXPECT_TRUE(
+      NotMatches("class X {}; void y(X *y) { X *&x = y; }", ReferenceClassX));
+}
+
+TEST(HasParameter, CallsInnerMatcher) {
+  EXPECT_TRUE(Matches("class X { void x(int) {} };",
+      Method(HasParameter(0, Variable()))));
+  EXPECT_TRUE(NotMatches("class X { void x(int) {} };",
+      Method(HasParameter(0, HasName("x")))));
+}
+
+TEST(HasParameter, DoesNotMatchIfIndexOutOfBounds) {
+  EXPECT_TRUE(NotMatches("class X { void x(int) {} };",
+      Method(HasParameter(42, Variable()))));
+}
+
+TEST(HasType, MatchesParameterVariableTypesStrictly) {
+  EXPECT_TRUE(Matches("class X { void x(X x) {} };",
+      Method(HasParameter(0, HasType(Class(HasName("X")))))));
+  EXPECT_TRUE(NotMatches("class X { void x(const X &x) {} };",
+      Method(HasParameter(0, HasType(Class(HasName("X")))))));
+  EXPECT_TRUE(Matches("class X { void x(const X *x) {} };",
+      Method(HasParameter(0, HasType(PointsTo(Class(HasName("X"))))))));
+  EXPECT_TRUE(Matches("class X { void x(const X &x) {} };",
+      Method(HasParameter(0, HasType(References(Class(HasName("X"))))))));
+}
+
+TEST(HasAnyParameter, MatchesIndependentlyOfPosition) {
+  EXPECT_TRUE(Matches("class Y {}; class X { void x(X x, Y y) {} };",
+      Method(HasAnyParameter(HasType(Class(HasName("X")))))));
+  EXPECT_TRUE(Matches("class Y {}; class X { void x(Y y, X x) {} };",
+      Method(HasAnyParameter(HasType(Class(HasName("X")))))));
+}
+
+TEST(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) {
+  EXPECT_TRUE(NotMatches("class Y {}; class X { void x(int) {} };",
+      Method(HasAnyParameter(HasType(Class(HasName("X")))))));
+}
+
+TEST(HasAnyParameter, DoesNotMatchThisPointer) {
+  EXPECT_TRUE(NotMatches("class Y {}; class X { void x() {} };",
+      Method(HasAnyParameter(HasType(PointsTo(Class(HasName("X"))))))));
+}
+
+TEST(HasName, MatchesParameterVariableDeclartions) {
+  EXPECT_TRUE(Matches("class Y {}; class X { void x(int x) {} };",
+      Method(HasAnyParameter(HasName("x")))));
+  EXPECT_TRUE(NotMatches("class Y {}; class X { void x(int) {} };",
+      Method(HasAnyParameter(HasName("x")))));
+}
+
+TEST(Matcher, ConstructorCall) {
+  StatementMatcher Constructor = Expression(ConstructorCall());
+
+  EXPECT_TRUE(
+      Matches("class X { public: X(); }; void x() { X x; }", Constructor));
+  EXPECT_TRUE(
+      Matches("class X { public: X(); }; void x() { X x = X(); }",
+              Constructor));
+  EXPECT_TRUE(
+      Matches("class X { public: X(int); }; void x() { X x = 0; }",
+              Constructor));
+  EXPECT_TRUE(Matches("class X {}; void x(int) { X x; }", Constructor));
+}
+
+TEST(Matcher, ConstructorArgument) {
+  StatementMatcher Constructor = Expression(ConstructorCall(
+      HasArgument(0, DeclarationReference(To(Variable(HasName("y")))))));
+
+  EXPECT_TRUE(
+      Matches("class X { public: X(int); }; void x() { int y; X x(y); }",
+              Constructor));
+  EXPECT_TRUE(
+      Matches("class X { public: X(int); }; void x() { int y; X x = X(y); }",
+              Constructor));
+  EXPECT_TRUE(
+      Matches("class X { public: X(int); }; void x() { int y; X x = y; }",
+              Constructor));
+  EXPECT_TRUE(
+      NotMatches("class X { public: X(int); }; void x() { int z; X x(z); }",
+                 Constructor));
+
+  StatementMatcher WrongIndex = Expression(ConstructorCall(
+      HasArgument(42, DeclarationReference(To(Variable(HasName("y")))))));
+  EXPECT_TRUE(
+      NotMatches("class X { public: X(int); }; void x() { int y; X x(y); }",
+                 WrongIndex));
+}
+
+TEST(Matcher, ConstructorArgumentCount) {
+  StatementMatcher Constructor1Arg =
+      Expression(ConstructorCall(ArgumentCountIs(1)));
+
+  EXPECT_TRUE(
+      Matches("class X { public: X(int); }; void x() { X x(0); }",
+              Constructor1Arg));
+  EXPECT_TRUE(
+      Matches("class X { public: X(int); }; void x() { X x = X(0); }",
+              Constructor1Arg));
+  EXPECT_TRUE(
+      Matches("class X { public: X(int); }; void x() { X x = 0; }",
+              Constructor1Arg));
+  EXPECT_TRUE(
+      NotMatches("class X { public: X(int, int); }; void x() { X x(0, 0); }",
+                 Constructor1Arg));
+}
+
+TEST(Matcher, DefaultArgument) {
+  StatementMatcher Arg = DefaultArgument();
+
+  EXPECT_TRUE(Matches("void x(int, int = 0) { int y; x(y); }", Arg));
+  EXPECT_TRUE(
+      Matches("class X { void x(int, int = 0) { int y; x(y); } };", Arg));
+  EXPECT_TRUE(NotMatches("void x(int, int = 0) { int y; x(y, 0); }", Arg));
+}
+
+TEST(Matcher, StringLiterals) {
+  StatementMatcher Literal = Expression(StringLiteral());
+  EXPECT_TRUE(Matches("const char *s = \"string\";", Literal));
+  // wide string
+  EXPECT_TRUE(Matches("const wchar_t *s = L\"string\";", Literal));
+  // with escaped characters
+  EXPECT_TRUE(Matches("const char *s = \"\x05five\";", Literal));
+  // no matching -- though the data type is the same, there is no string literal
+  EXPECT_TRUE(NotMatches("const char s[1] = {'a'};", Literal));
+}
+
+TEST(Matcher, CharacterLiterals) {
+  StatementMatcher CharLiteral = Expression(CharacterLiteral());
+  EXPECT_TRUE(Matches("const char c = 'c';", CharLiteral));
+  // wide character
+  EXPECT_TRUE(Matches("const char c = L'c';", CharLiteral));
+  // wide character, Hex encoded, NOT MATCHED!
+  EXPECT_TRUE(NotMatches("const wchar_t c = 0x2126;", CharLiteral));
+  EXPECT_TRUE(NotMatches("const char c = 0x1;", CharLiteral));
+}
+
+TEST(Matcher, IntegerLiterals) {
+  StatementMatcher HasIntLiteral = Expression(IntegerLiteral());
+  EXPECT_TRUE(Matches("int i = 10;", HasIntLiteral));
+  EXPECT_TRUE(Matches("int i = 0x1AB;", HasIntLiteral));
+  EXPECT_TRUE(Matches("int i = 10L;", HasIntLiteral));
+  EXPECT_TRUE(Matches("int i = 10U;", HasIntLiteral));
+
+  // Non-matching cases (character literals, float and double)
+  EXPECT_TRUE(NotMatches("int i = L'a';",
+                HasIntLiteral));  // this is actually a character
+                                  // literal cast to int
+  EXPECT_TRUE(NotMatches("int i = 'a';", HasIntLiteral));
+  EXPECT_TRUE(NotMatches("int i = 1e10;", HasIntLiteral));
+  EXPECT_TRUE(NotMatches("int i = 10.0;", HasIntLiteral));
+}
+
+TEST(Matcher, Conditions) {
+  StatementMatcher Condition = If(HasCondition(BoolLiteral(Equals(true))));
+
+  EXPECT_TRUE(Matches("void x() { if (true) {} }", Condition));
+  EXPECT_TRUE(NotMatches("void x() { if (false) {} }", Condition));
+  EXPECT_TRUE(NotMatches("void x() { bool a = true; if (a) {} }", Condition));
+  EXPECT_TRUE(NotMatches("void x() { if (true || false) {} }", Condition));
+  EXPECT_TRUE(NotMatches("void x() { if (1) {} }", Condition));
+}
+
+TEST(MatchBinaryOperator, HasOperatorName) {
+  StatementMatcher OperatorOr = BinaryOperator(HasOperatorName("||"));
+
+  EXPECT_TRUE(Matches("void x() { true || false; }", OperatorOr));
+  EXPECT_TRUE(NotMatches("void x() { true && false; }", OperatorOr));
+}
+
+TEST(MatchBinaryOperator, HasLHSAndHasRHS) {
+  StatementMatcher OperatorTrueFalse =
+      BinaryOperator(HasLHS(BoolLiteral(Equals(true))),
+                     HasRHS(BoolLiteral(Equals(false))));
+
+  EXPECT_TRUE(Matches("void x() { true || false; }", OperatorTrueFalse));
+  EXPECT_TRUE(Matches("void x() { true && false; }", OperatorTrueFalse));
+  EXPECT_TRUE(NotMatches("void x() { false || true; }", OperatorTrueFalse));
+}
+
+TEST(MatchBinaryOperator, HasEitherOperand) {
+  StatementMatcher HasOperand =
+      BinaryOperator(HasEitherOperand(BoolLiteral(Equals(false))));
+
+  EXPECT_TRUE(Matches("void x() { true || false; }", HasOperand));
+  EXPECT_TRUE(Matches("void x() { false && true; }", HasOperand));
+  EXPECT_TRUE(NotMatches("void x() { true || true; }", HasOperand));
+}
+
+TEST(Matcher, BinaryOperatorTypes) {
+  // Integration test that verifies the AST provides all binary operators in
+  // a way we expect.
+  // FIXME: Operator ','
+  EXPECT_TRUE(
+      Matches("void x() { 3, 4; }", BinaryOperator(HasOperatorName(","))));
+  EXPECT_TRUE(
+      Matches("bool b; bool c = (b = true);",
+              BinaryOperator(HasOperatorName("="))));
+  EXPECT_TRUE(
+      Matches("bool b = 1 != 2;", BinaryOperator(HasOperatorName("!="))));
+  EXPECT_TRUE(
+      Matches("bool b = 1 == 2;", BinaryOperator(HasOperatorName("=="))));
+  EXPECT_TRUE(Matches("bool b = 1 < 2;", BinaryOperator(HasOperatorName("<"))));
+  EXPECT_TRUE(
+      Matches("bool b = 1 <= 2;", BinaryOperator(HasOperatorName("<="))));
+  EXPECT_TRUE(
+      Matches("int i = 1 << 2;", BinaryOperator(HasOperatorName("<<"))));
+  EXPECT_TRUE(
+      Matches("int i = 1; int j = (i <<= 2);",
+              BinaryOperator(HasOperatorName("<<="))));
+  EXPECT_TRUE(Matches("bool b = 1 > 2;", BinaryOperator(HasOperatorName(">"))));
+  EXPECT_TRUE(
+      Matches("bool b = 1 >= 2;", BinaryOperator(HasOperatorName(">="))));
+  EXPECT_TRUE(
+      Matches("int i = 1 >> 2;", BinaryOperator(HasOperatorName(">>"))));
+  EXPECT_TRUE(
+      Matches("int i = 1; int j = (i >>= 2);",
+              BinaryOperator(HasOperatorName(">>="))));
+  EXPECT_TRUE(
+      Matches("int i = 42 ^ 23;", BinaryOperator(HasOperatorName("^"))));
+  EXPECT_TRUE(
+      Matches("int i = 42; int j = (i ^= 42);",
+              BinaryOperator(HasOperatorName("^="))));
+  EXPECT_TRUE(
+      Matches("int i = 42 % 23;", BinaryOperator(HasOperatorName("%"))));
+  EXPECT_TRUE(
+      Matches("int i = 42; int j = (i %= 42);",
+              BinaryOperator(HasOperatorName("%="))));
+  EXPECT_TRUE(
+      Matches("bool b = 42  &23;", BinaryOperator(HasOperatorName("&"))));
+  EXPECT_TRUE(
+      Matches("bool b = true && false;",
+              BinaryOperator(HasOperatorName("&&"))));
+  EXPECT_TRUE(
+      Matches("bool b = true; bool c = (b &= false);",
+              BinaryOperator(HasOperatorName("&="))));
+  EXPECT_TRUE(
+      Matches("bool b = 42 | 23;", BinaryOperator(HasOperatorName("|"))));
+  EXPECT_TRUE(
+      Matches("bool b = true || false;",
+              BinaryOperator(HasOperatorName("||"))));
+  EXPECT_TRUE(
+      Matches("bool b = true; bool c = (b |= false);",
+              BinaryOperator(HasOperatorName("|="))));
+  EXPECT_TRUE(
+      Matches("int i = 42  *23;", BinaryOperator(HasOperatorName("*"))));
+  EXPECT_TRUE(
+      Matches("int i = 42; int j = (i *= 23);",
+              BinaryOperator(HasOperatorName("*="))));
+  EXPECT_TRUE(
+      Matches("int i = 42 / 23;", BinaryOperator(HasOperatorName("/"))));
+  EXPECT_TRUE(
+      Matches("int i = 42; int j = (i /= 23);",
+              BinaryOperator(HasOperatorName("/="))));
+  EXPECT_TRUE(
+      Matches("int i = 42 + 23;", BinaryOperator(HasOperatorName("+"))));
+  EXPECT_TRUE(
+      Matches("int i = 42; int j = (i += 23);",
+              BinaryOperator(HasOperatorName("+="))));
+  EXPECT_TRUE(
+      Matches("int i = 42 - 23;", BinaryOperator(HasOperatorName("-"))));
+  EXPECT_TRUE(
+      Matches("int i = 42; int j = (i -= 23);",
+              BinaryOperator(HasOperatorName("-="))));
+  EXPECT_TRUE(
+      Matches("struct A { void x() { void (A::*a)(); (this->*a)(); } };",
+              BinaryOperator(HasOperatorName("->*"))));
+  EXPECT_TRUE(
+      Matches("struct A { void x() { void (A::*a)(); ((*this).*a)(); } };",
+              BinaryOperator(HasOperatorName(".*"))));
+
+  // Member expressions as operators are not supported in matches.
+  EXPECT_TRUE(
+      NotMatches("struct A { void x(A *a) { a->x(this); } };",
+                 BinaryOperator(HasOperatorName("->"))));
+
+  // Initializer assignments are not represented as operator equals.
+  EXPECT_TRUE(
+      NotMatches("bool b = true;", BinaryOperator(HasOperatorName("="))));
+
+  // Array indexing is not represented as operator.
+  EXPECT_TRUE(NotMatches("int a[42]; void x() { a[23]; }", UnaryOperator()));
+
+  // Overloaded operators do not match at all.
+  EXPECT_TRUE(NotMatches(
+      "struct A { bool operator&&(const A &a) const { return false; } };"
+      "void x() { A a, b; a && b; }",
+      BinaryOperator()));
+}
+
+TEST(MatchUnaryOperator, HasOperatorName) {
+  StatementMatcher OperatorNot = UnaryOperator(HasOperatorName("!"));
+
+  EXPECT_TRUE(Matches("void x() { !true; } ", OperatorNot));
+  EXPECT_TRUE(NotMatches("void x() { true; } ", OperatorNot));
+}
+
+TEST(MatchUnaryOperator, HasUnaryOperand) {
+  StatementMatcher OperatorOnFalse =
+      UnaryOperator(HasUnaryOperand(BoolLiteral(Equals(false))));
+
+  EXPECT_TRUE(Matches("void x() { !false; }", OperatorOnFalse));
+  EXPECT_TRUE(NotMatches("void x() { !true; }", OperatorOnFalse));
+}
+
+TEST(Matcher, UnaryOperatorTypes) {
+  // Integration test that verifies the AST provides all unary operators in
+  // a way we expect.
+  EXPECT_TRUE(Matches("bool b = !true;", UnaryOperator(HasOperatorName("!"))));
+  EXPECT_TRUE(
+      Matches("bool b; bool *p = &b;", UnaryOperator(HasOperatorName("&"))));
+  EXPECT_TRUE(Matches("int i = ~ 1;", UnaryOperator(HasOperatorName("~"))));
+  EXPECT_TRUE(
+      Matches("bool *p; bool b = *p;", UnaryOperator(HasOperatorName("*"))));
+  EXPECT_TRUE(
+      Matches("int i; int j = +i;", UnaryOperator(HasOperatorName("+"))));
+  EXPECT_TRUE(
+      Matches("int i; int j = -i;", UnaryOperator(HasOperatorName("-"))));
+  EXPECT_TRUE(
+      Matches("int i; int j = ++i;", UnaryOperator(HasOperatorName("++"))));
+  EXPECT_TRUE(
+      Matches("int i; int j = i++;", UnaryOperator(HasOperatorName("++"))));
+  EXPECT_TRUE(
+      Matches("int i; int j = --i;", UnaryOperator(HasOperatorName("--"))));
+  EXPECT_TRUE(
+      Matches("int i; int j = i--;", UnaryOperator(HasOperatorName("--"))));
+
+  // We don't match conversion operators.
+  EXPECT_TRUE(NotMatches("int i; double d = (double)i;", UnaryOperator()));
+
+  // Function calls are not represented as operator.
+  EXPECT_TRUE(NotMatches("void f(); void x() { f(); }", UnaryOperator()));
+
+  // Overloaded operators do not match at all.
+  // FIXME: We probably want to add that.
+  EXPECT_TRUE(NotMatches(
+      "struct A { bool operator!() const { return false; } };"
+      "void x() { A a; !a; }", UnaryOperator(HasOperatorName("!"))));
+}
+
+TEST(Matcher, ConditionalOperator) {
+  StatementMatcher Conditional = ConditionalOperator(
+      HasCondition(BoolLiteral(Equals(true))),
+      HasTrueExpression(BoolLiteral(Equals(false))));
+
+  EXPECT_TRUE(Matches("void x() { true ? false : true; }", Conditional));
+  EXPECT_TRUE(NotMatches("void x() { false ? false : true; }", Conditional));
+  EXPECT_TRUE(NotMatches("void x() { true ? true : false; }", Conditional));
+
+  StatementMatcher ConditionalFalse = ConditionalOperator(
+      HasFalseExpression(BoolLiteral(Equals(false))));
+
+  EXPECT_TRUE(Matches("void x() { true ? true : false; }", ConditionalFalse));
+  EXPECT_TRUE(
+      NotMatches("void x() { true ? false : true; }", ConditionalFalse));
+}
+
+TEST(Matcher, HasNameSupportsNamespaces) {
+  EXPECT_TRUE(Matches("namespace a { namespace b { class C; } }",
+              Class(HasName("a::b::C"))));
+  EXPECT_TRUE(Matches("namespace a { namespace b { class C; } }",
+              Class(HasName("::a::b::C"))));
+  EXPECT_TRUE(Matches("namespace a { namespace b { class C; } }",
+              Class(HasName("b::C"))));
+  EXPECT_TRUE(Matches("namespace a { namespace b { class C; } }",
+              Class(HasName("C"))));
+  EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }",
+              Class(HasName("c::b::C"))));
+  EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }",
+              Class(HasName("a::c::C"))));
+  EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }",
+              Class(HasName("a::b::A"))));
+  EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }",
+              Class(HasName("::C"))));
+  EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }",
+              Class(HasName("::b::C"))));
+  EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }",
+              Class(HasName("z::a::b::C"))));
+  EXPECT_TRUE(NotMatches("namespace a { namespace b { class C; } }",
+              Class(HasName("a+b::C"))));
+  EXPECT_TRUE(NotMatches("namespace a { namespace b { class AC; } }",
+              Class(HasName("C"))));
+}
+
+TEST(Matcher, HasNameSupportsOuterClasses) {
+  EXPECT_TRUE(
+      Matches("class A { class B { class C; }; };", Class(HasName("A::B::C"))));
+  EXPECT_TRUE(
+      Matches("class A { class B { class C; }; };",
+              Class(HasName("::A::B::C"))));
+  EXPECT_TRUE(
+      Matches("class A { class B { class C; }; };", Class(HasName("B::C"))));
+  EXPECT_TRUE(
+      Matches("class A { class B { class C; }; };", Class(HasName("C"))));
+  EXPECT_TRUE(
+      NotMatches("class A { class B { class C; }; };",
+                 Class(HasName("c::B::C"))));
+  EXPECT_TRUE(
+      NotMatches("class A { class B { class C; }; };",
+                 Class(HasName("A::c::C"))));
+  EXPECT_TRUE(
+      NotMatches("class A { class B { class C; }; };",
+                 Class(HasName("A::B::A"))));
+  EXPECT_TRUE(
+      NotMatches("class A { class B { class C; }; };", Class(HasName("::C"))));
+  EXPECT_TRUE(
+      NotMatches("class A { class B { class C; }; };",
+                 Class(HasName("::B::C"))));
+  EXPECT_TRUE(NotMatches("class A { class B { class C; }; };",
+              Class(HasName("z::A::B::C"))));
+  EXPECT_TRUE(
+      NotMatches("class A { class B { class C; }; };",
+                 Class(HasName("A+B::C"))));
+}
+
+TEST(Matcher, IsDefinition) {
+  DeclarationMatcher DefinitionOfClassA =
+      Class(HasName("A"), IsDefinition());
+  EXPECT_TRUE(Matches("class A {};", DefinitionOfClassA));
+  EXPECT_TRUE(NotMatches("class A;", DefinitionOfClassA));
+
+  DeclarationMatcher DefinitionOfVariableA =
+      Variable(HasName("a"), IsDefinition());
+  EXPECT_TRUE(Matches("int a;", DefinitionOfVariableA));
+  EXPECT_TRUE(NotMatches("extern int a;", DefinitionOfVariableA));
+
+  DeclarationMatcher DefinitionOfMethodA =
+      Method(HasName("a"), IsDefinition());
+  EXPECT_TRUE(Matches("class A { void a() {} };", DefinitionOfMethodA));
+  EXPECT_TRUE(NotMatches("class A { void a(); };", DefinitionOfMethodA));
+}
+
+TEST(Matcher, OfClass) {
+  StatementMatcher Constructor = ConstructorCall(HasDeclaration(Method(
+      OfClass(HasName("X")))));
+
+  EXPECT_TRUE(
+      Matches("class X { public: X(); }; void x(int) { X x; }", Constructor));
+  EXPECT_TRUE(
+      Matches("class X { public: X(); }; void x(int) { X x = X(); }",
+              Constructor));
+  EXPECT_TRUE(
+      NotMatches("class Y { public: Y(); }; void x(int) { Y y; }",
+                 Constructor));
+}
+
+TEST(Matcher, VisitsTemplateInstantiations) {
+  EXPECT_TRUE(Matches(
+      "class A { public: void x(); };"
+      "template <typename T> class B { public: void y() { T t; t.x(); } };"
+      "void f() { B<A> b; b.y(); }", Call(Callee(Method(HasName("x"))))));
+
+  EXPECT_TRUE(Matches(
+      "class A { public: void x(); };"
+      "class C {"
+      " public:"
+      "  template <typename T> class B { public: void y() { T t; t.x(); } };"
+      "};"
+      "void f() {"
+      "  C::B<A> b; b.y();"
+      "}", Class(HasName("C"),
+                 HasDescendant(Call(Callee(Method(HasName("x"))))))));
+}
+
+// For testing AST_MATCHER_P().
+AST_MATCHER_P(clang::Decl, Just, Matcher<clang::Decl>, AMatcher) {
+  // Make sure all special variables are used: node, match_finder,
+  // bound_nodes_builder, and the parameter named 'AMatcher'.
+  return AMatcher.Matches(Node, Finder, Builder);
+}
+
+TEST(AstMatcherPMacro, Works) {
+  DeclarationMatcher HasClassB = Just(Has(Id("b", Class(HasName("B")))));
+
+  EXPECT_TRUE(MatchAndVerifyResultTrue("class A { class B {}; };",
+      HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b")));
+
+  EXPECT_TRUE(MatchAndVerifyResultFalse("class A { class B {}; };",
+      HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("a")));
+
+  EXPECT_TRUE(MatchAndVerifyResultFalse("class A { class C {}; };",
+      HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b")));
+}
+
+AST_POLYMORPHIC_MATCHER_P(
+    PolymorphicHas, Matcher<clang::Decl>, AMatcher) {
+  COMPILE_ASSERT((llvm::is_same<NodeType, clang::Decl>::value) ||
+                 (llvm::is_same<NodeType, clang::Stmt>::value),
+                 assert_node_type_is_accessible);
+  TypedBaseMatcher<clang::Decl> ChildMatcher(AMatcher);
+  return Finder->MatchesChildOf(
+      Node, ChildMatcher, Builder,
+      ASTMatchFinder::kIgnoreImplicitCastsAndParentheses);
+}
+
+TEST(AstPolymorphicMatcherPMacro, Works) {
+  DeclarationMatcher HasClassB = PolymorphicHas(Id("b", Class(HasName("B"))));
+
+  EXPECT_TRUE(MatchAndVerifyResultTrue("class A { class B {}; };",
+      HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b")));
+
+  EXPECT_TRUE(MatchAndVerifyResultFalse("class A { class B {}; };",
+      HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("a")));
+
+  EXPECT_TRUE(MatchAndVerifyResultFalse("class A { class C {}; };",
+      HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b")));
+
+  StatementMatcher StatementHasClassB =
+      PolymorphicHas(Class(HasName("B")));
+
+  EXPECT_TRUE(Matches("void x() { class B {}; }", StatementHasClassB));
+}
+
+TEST(For, FindsForLoops) {
+  EXPECT_TRUE(Matches("void f() { for(;;); }", For()));
+  EXPECT_TRUE(Matches("void f() { if(true) for(;;); }", For()));
+}
+
+TEST(For, ReportsNoFalsePositives) {
+  EXPECT_TRUE(NotMatches("void f() { ; }", For()));
+  EXPECT_TRUE(NotMatches("void f() { if(true); }", For()));
+}
+
+TEST(CompoundStatement, HandlesSimpleCases) {
+  EXPECT_TRUE(NotMatches("void f();", CompoundStatement()));
+  EXPECT_TRUE(Matches("void f() {}", CompoundStatement()));
+  EXPECT_TRUE(Matches("void f() {{}}", CompoundStatement()));
+}
+
+TEST(CompoundStatement, DoesNotMatchEmptyStruct) {
+  // It's not a compound statement just because there's "{}" in the source
+  // text.  This is an AST search, not grep.
+  EXPECT_TRUE(NotMatches("namespace n { struct S {}; }",
+              CompoundStatement()));
+  EXPECT_TRUE(Matches("namespace n { struct S { void f() {{}} }; }",
+              CompoundStatement()));
+}
+
+TEST(HasBody, FindsBodyOfForLoop) {
+  StatementMatcher HasCompoundStatementBody =
+      For(HasBody(CompoundStatement()));
+  EXPECT_TRUE(Matches("void f() { for(;;) {} }",
+              HasCompoundStatementBody));
+  EXPECT_TRUE(NotMatches("void f() { for(;;); }",
+              HasCompoundStatementBody));
+}
+
+TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) {
+  // The simplest case: every compound statement is in a function
+  // definition, and the function body itself must be a compound
+  // statement.
+  EXPECT_TRUE(Matches("void f() { for (;;); }",
+              CompoundStatement(HasAnySubstatement(For()))));
+}
+
+TEST(HasAnySubstatement, IsNotRecursive) {
+  // It's really "has any immediate substatement".
+  EXPECT_TRUE(NotMatches("void f() { if (true) for (;;); }",
+              CompoundStatement(HasAnySubstatement(For()))));
+}
+
+TEST(HasAnySubstatement, MatchesInNestedCompoundStatements) {
+  EXPECT_TRUE(Matches("void f() { if (true) { for (;;); } }",
+              CompoundStatement(HasAnySubstatement(For()))));
+}
+
+TEST(HasAnySubstatement, FindsSubstatementBetweenOthers) {
+  EXPECT_TRUE(Matches("void f() { 1; 2; 3; for (;;); 4; 5; 6; }",
+              CompoundStatement(HasAnySubstatement(For()))));
+}
+
+TEST(StatementCountIs, FindsNoStatementsInAnEmptyCompoundStatement) {
+  EXPECT_TRUE(Matches("void f() { }",
+              CompoundStatement(StatementCountIs(0))));
+  EXPECT_TRUE(NotMatches("void f() {}",
+              CompoundStatement(StatementCountIs(1))));
+}
+
+TEST(StatementCountIs, AppearsToMatchOnlyOneCount) {
+  EXPECT_TRUE(Matches("void f() { 1; }",
+              CompoundStatement(StatementCountIs(1))));
+  EXPECT_TRUE(NotMatches("void f() { 1; }",
+              CompoundStatement(StatementCountIs(0))));
+  EXPECT_TRUE(NotMatches("void f() { 1; }",
+              CompoundStatement(StatementCountIs(2))));
+}
+
+TEST(StatementCountIs, WorksWithMultipleStatements) {
+  EXPECT_TRUE(Matches("void f() { 1; 2; 3; }",
+              CompoundStatement(StatementCountIs(3))));
+}
+
+TEST(StatementCountIs, WorksWithNestedCompoundStatements) {
+  EXPECT_TRUE(Matches("void f() { { 1; } { 1; 2; 3; 4; } }",
+              CompoundStatement(StatementCountIs(1))));
+  EXPECT_TRUE(Matches("void f() { { 1; } { 1; 2; 3; 4; } }",
+              CompoundStatement(StatementCountIs(2))));
+  EXPECT_TRUE(NotMatches("void f() { { 1; } { 1; 2; 3; 4; } }",
+              CompoundStatement(StatementCountIs(3))));
+  EXPECT_TRUE(Matches("void f() { { 1; } { 1; 2; 3; 4; } }",
+              CompoundStatement(StatementCountIs(4))));
+}
+
+} // end namespace tooling
+} // end namespace clang





More information about the cfe-commits mailing list