//===--- ASTMatchersMacros.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.
//
//===----------------------------------------------------------------------===//
//
//  Defines macros that enable us to define new matchers in a single place.
//  Since a matcher is a function which returns a Matcher<T> object, where
//  T is the type of the actual implementation of the matcher, the macros allow
//  us to write matchers like functions and take care of the definition of the
//  class boilerplate.
//
//  Note that when you define a matcher with an AST_MATCHER* macro, only the
//  function which creates the matcher goes into the current namespace - the
//  class that implements the actual matcher, which gets returned by the
//  generator function, is put into the 'internal' namespace. This allows us
//  to only have the functions (which is all the user cares about) in the
//  'ast_matchers' namespace and hide the boilerplate.
//
//  To define a matcher in user code, always put it into the clang::ast_matchers
//  namespace and refer to the internal types via the 'internal::':
//
//  namespace clang {
//  namespace ast_matchers {
//  AST_MATCHER_P(MemberExpr, Member,
//                internal::Matcher<ValueDecl>, InnerMatcher) {
//    return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder);
//  }
//  } // end namespace ast_matchers
//  } // end namespace clang
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H

/// \brief AST_MATCHER(Type, DefineMatcher) { ... }
/// defines a zero 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.
///   Finder:                an ASTMatchFinder*.
///   Builder:               a BoundNodesTreeBuilder*.
///
/// The code should return true if 'Node' matches.
#define AST_MATCHER(Type, DefineMatcher)                                       \
  AST_MATCHER_OVERLOAD(Type, DefineMatcher, 0)

#define AST_MATCHER_OVERLOAD(Type, DefineMatcher, OverloadId)                  \
  namespace internal {                                                         \
  class matcher_##DefineMatcher##OverloadId##Matcher                           \
      : public MatcherInterface<Type> {                                        \
  public:                                                                      \
    explicit matcher_##DefineMatcher##OverloadId##Matcher() {}                 \
    virtual bool matches(const Type &Node, ASTMatchFinder *Finder,             \
                         BoundNodesTreeBuilder *Builder) const;                \
  };                                                                           \
  }                                                                            \
  inline internal::Matcher<Type> DefineMatcher() {                             \
    return internal::makeMatcher(                                              \
        new internal::matcher_##DefineMatcher##OverloadId##Matcher());         \
  }                                                                            \
  inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
      const Type &Node, ASTMatchFinder *Finder,                                \
      BoundNodesTreeBuilder *Builder) const

/// \brief 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 BoundNodesTreeBuilder*.
///
/// The code should return true if 'Node' matches.
#define AST_MATCHER_P(Type, DefineMatcher, ParamType, Param)                   \
  AST_MATCHER_P_OVERLOAD(Type, DefineMatcher, ParamType, Param, 0)

#define AST_MATCHER_P_OVERLOAD(Type, DefineMatcher, ParamType, Param,          \
                               OverloadId)                                     \
  namespace internal {                                                         \
  class matcher_##DefineMatcher##OverloadId##Matcher                           \
      : public MatcherInterface<Type> {                                        \
  public:                                                                      \
    explicit matcher_##DefineMatcher##OverloadId##Matcher(                     \
        const ParamType &A##Param)                                             \
        : Param(A##Param) {                                                    \
    }                                                                          \
    virtual bool matches(const Type &Node, ASTMatchFinder *Finder,             \
                         BoundNodesTreeBuilder *Builder) const;                \
  private:                                                                     \
    const ParamType Param;                                                     \
  };                                                                           \
  }                                                                            \
  inline internal::Matcher<Type> DefineMatcher(const ParamType &Param) {       \
    return internal::makeMatcher(                                              \
        new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param));    \
  }                                                                            \
  inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
      const Type &Node, ASTMatchFinder *Finder,                                \
      BoundNodesTreeBuilder *Builder) const

/// \brief 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 BoundNodesTreeBuilder*.
///
/// The code should return true if 'Node' matches.
#define AST_MATCHER_P2(Type, DefineMatcher, ParamType1, Param1, ParamType2,    \
                       Param2)                                                 \
  AST_MATCHER_P2_OVERLOAD(Type, DefineMatcher, ParamType1, Param1, ParamType2, \
                          Param2, 0)

#define AST_MATCHER_P2_OVERLOAD(Type, DefineMatcher, ParamType1, Param1,       \
                                ParamType2, Param2, OverloadId)                \
  namespace internal {                                                         \
  class matcher_##DefineMatcher##OverloadId##Matcher                           \
      : public MatcherInterface<Type> {                                        \
  public:                                                                      \
    matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1,  \
                                                 const ParamType2 &A##Param2)  \
        : Param1(A##Param1), Param2(A##Param2) {                               \
    }                                                                          \
    virtual bool matches(const Type &Node, ASTMatchFinder *Finder,             \
                         BoundNodesTreeBuilder *Builder) const;                \
  private:                                                                     \
    const ParamType1 Param1;                                                   \
    const ParamType2 Param2;                                                   \
  };                                                                           \
  }                                                                            \
  inline internal::Matcher<Type>                                               \
  DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) {          \
    return internal::makeMatcher(                                              \
        new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param1,     \
                                                                   Param2));   \
  }                                                                            \
  inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
      const Type &Node, ASTMatchFinder *Finder,                                \
      BoundNodesTreeBuilder *Builder) const

/// \brief AST_POLYMORPHIC_MATCHER(DefineMatcher) { ... }
/// defines a single-parameter function named DefineMatcher() that is
/// polymorphic in the return type.
///
/// The variables are the same as for AST_MATCHER, but NodeType will be deduced
/// from the calling context.
#define AST_POLYMORPHIC_MATCHER(DefineMatcher)                                 \
  AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, 0)

#define AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, OverloadId)            \
  namespace internal {                                                         \
  template <typename NodeType>                                                 \
  class matcher_##DefineMatcher##OverloadId##Matcher                           \
      : public MatcherInterface<NodeType> {                                    \
  public:                                                                      \
    virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder,         \
                         BoundNodesTreeBuilder *Builder) const;                \
  };                                                                           \
  }                                                                            \
  inline internal::PolymorphicMatcherWithParam0<                               \
      internal::matcher_##DefineMatcher##OverloadId##Matcher> DefineMatcher() {\
    return internal::PolymorphicMatcherWithParam0<                             \
        internal::matcher_##DefineMatcher##OverloadId##Matcher>();             \
  }                                                                            \
  template <typename NodeType>                                                 \
  bool internal::matcher_##DefineMatcher##OverloadId##Matcher<                 \
      NodeType>::matches(const NodeType &Node, ASTMatchFinder *Finder,         \
                         BoundNodesTreeBuilder *Builder) const

/// \brief 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)             \
  AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ParamType, Param, 0)

#define AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ParamType, Param,    \
                                           OverloadId)                         \
  namespace internal {                                                         \
  template <typename NodeType, typename ParamT>                                \
  class matcher_##DefineMatcher##OverloadId##Matcher                           \
      : public MatcherInterface<NodeType> {                                    \
  public:                                                                      \
    explicit matcher_##DefineMatcher##OverloadId##Matcher(                     \
        const ParamType &A##Param)                                             \
        : Param(A##Param) {                                                    \
    }                                                                          \
    virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder,         \
                         BoundNodesTreeBuilder *Builder) const;                \
  private:                                                                     \
    const ParamType Param;                                                     \
  };                                                                           \
  }                                                                            \
  inline internal::PolymorphicMatcherWithParam1<                               \
      internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType>       \
  DefineMatcher(const ParamType &Param) {                                      \
    return internal::PolymorphicMatcherWithParam1<                             \
        internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType>(    \
        Param);                                                                \
  }                                                                            \
  template <typename NodeType, typename ParamT>                                \
  bool internal::matcher_##DefineMatcher##OverloadId##Matcher<                 \
      NodeType, ParamT>::matches(const NodeType &Node, ASTMatchFinder *Finder, \
                                 BoundNodesTreeBuilder *Builder) const

/// \brief 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)                         \
  AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ParamType1, Param1,       \
                                      ParamType2, Param2, 0)

#define AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ParamType1, Param1, \
                                            ParamType2, Param2, OverloadId)    \
  namespace internal {                                                         \
  template <typename NodeType, typename ParamT1, typename ParamT2>             \
  class matcher_##DefineMatcher##OverloadId##Matcher                           \
      : public MatcherInterface<NodeType> {                                    \
  public:                                                                      \
    matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1,  \
                                                 const ParamType2 &A##Param2)  \
        : Param1(A##Param1), Param2(A##Param2) {                               \
    }                                                                          \
    virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder,         \
                         BoundNodesTreeBuilder *Builder) const;                \
  private:                                                                     \
    const ParamType1 Param1;                                                   \
    const ParamType2 Param2;                                                   \
  };                                                                           \
  }                                                                            \
  inline internal::PolymorphicMatcherWithParam2<                               \
      internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1,      \
      ParamType2>                                                              \
  DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) {          \
    return internal::PolymorphicMatcherWithParam2<                             \
        internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1,    \
        ParamType2>(Param1, Param2);                                           \
  }                                                                            \
  template <typename NodeType, typename ParamT1, typename ParamT2>             \
  bool internal::matcher_##DefineMatcher##OverloadId##Matcher<                 \
      NodeType, ParamT1, ParamT2>::matches(                                    \
      const NodeType &Node, ASTMatchFinder *Finder,                            \
      BoundNodesTreeBuilder *Builder) const

/// \brief Creates a variadic matcher for both a specific \c Type as well as
/// the corresponding \c TypeLoc.
#define AST_TYPE_MATCHER(NodeType, MatcherName)                                \
  const internal::VariadicDynCastAllOfMatcher<Type, NodeType> MatcherName
// FIXME: add a matcher for TypeLoc derived classes using its custom casting
// API (no longer dyn_cast) if/when we need such matching

/// \brief AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) defines
/// the matcher \c MatcherName that can be used to traverse from one \c Type
/// to another.
///
/// For a specific \c SpecificType, the traversal is done using 
/// \c SpecificType::FunctionName. The existance of such a function determines
/// whether a corresponding matcher can be used on \c SpecificType.
#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName)                   \
  class Polymorphic##MatcherName##TypeMatcher {                                \
  public:                                                                      \
    Polymorphic##MatcherName##TypeMatcher(                                     \
        const internal::Matcher<QualType> &InnerMatcher)                       \
        : InnerMatcher(InnerMatcher) {                                         \
    }                                                                          \
    template <typename T> operator internal:: Matcher< T>() {                  \
      return internal::Matcher<T>(new internal::TypeTraverseMatcher<T>(        \
                                          InnerMatcher, &T::FunctionName));    \
    }                                                                          \
  private:                                                                     \
    const internal::Matcher<QualType> InnerMatcher;                            \
  }                                                                            \
  ;                                                                            \
  class Variadic##MatcherName##TypeTraverseMatcher                             \
      : public llvm::VariadicFunction<                                         \
          Polymorphic##MatcherName##TypeMatcher, internal::Matcher<QualType>,  \
          internal::makeTypeAllOfComposite<                                    \
              Polymorphic##MatcherName##TypeMatcher, QualType> > {             \
  public:                                                                      \
    Variadic##MatcherName##TypeTraverseMatcher() {                             \
    }                                                                          \
  }                                                                            \
  ;                                                                            \
  const Variadic##MatcherName##TypeTraverseMatcher MatcherName

/// \brief AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) works
/// identical to \c AST_TYPE_TRAVERSE_MATCHER but operates on \c TypeLocs.
#define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName)                \
  class Polymorphic##MatcherName##TypeLocMatcher {                             \
  public:                                                                      \
    Polymorphic##MatcherName##TypeLocMatcher(                                  \
        const internal::Matcher<TypeLoc> &InnerMatcher)                        \
        : InnerMatcher(InnerMatcher) {                                         \
    }                                                                          \
    template <typename T> operator internal:: Matcher< T>() {                  \
      return internal::Matcher<T>(                                             \
          new internal::TypeLocTraverseMatcher<T>(InnerMatcher,                \
                                                  &T::FunctionName##Loc));     \
    }                                                                          \
  private:                                                                     \
    const internal::Matcher<TypeLoc> InnerMatcher;                             \
  }                                                                            \
  ;                                                                            \
  class Variadic##MatcherName##TypeLocTraverseMatcher                          \
      : public llvm::VariadicFunction<                                         \
          Polymorphic##MatcherName##TypeLocMatcher, internal::Matcher<TypeLoc>,\
          internal::makeTypeAllOfComposite<                                    \
              Polymorphic##MatcherName##TypeLocMatcher, TypeLoc> > {           \
  public:                                                                      \
    Variadic##MatcherName##TypeLocTraverseMatcher() {                          \
    }                                                                          \
  }                                                                            \
  ;                                                                            \
  const Variadic##MatcherName##TypeLocTraverseMatcher MatcherName##Loc;        \
  AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type)

#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
