//===--- Marshallers.h - Generic matcher function marshallers -*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief Functions templates and classes to wrap matcher construct functions. /// /// A collection of template function and classes that provide a generic /// marshalling layer on top of matcher construct functions. /// These are used by the registry to export all marshaller constructors with /// the same generic interface. /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H #define LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H #include #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/Dynamic/Diagnostics.h" #include "clang/ASTMatchers/Dynamic/VariantValue.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/type_traits.h" namespace clang { namespace ast_matchers { namespace dynamic { namespace internal { /// \brief Helper template class to just from argument type to the right is/get /// functions in VariantValue. /// Used to verify and extract the matcher arguments below. template struct ArgTypeTraits; template struct ArgTypeTraits : public ArgTypeTraits { }; template <> struct ArgTypeTraits { static StringRef asString() { return "String"; } static bool is(const VariantValue &Value) { return Value.isString(); } static const std::string &get(const VariantValue &Value) { return Value.getString(); } }; template <> struct ArgTypeTraits : public ArgTypeTraits { }; template struct ArgTypeTraits > { static std::string asString() { return (Twine("Matcher<") + ast_type_traits::ASTNodeKind::getFromNodeKind().asStringRef() + ">").str(); } static bool is(const VariantValue &Value) { return Value.isMatcher() && Value.getMatcher().hasTypedMatcher(); } static ast_matchers::internal::Matcher get(const VariantValue &Value) { return Value.getMatcher().getTypedMatcher(); } }; template <> struct ArgTypeTraits { static std::string asString() { return "Unsigned"; } static bool is(const VariantValue &Value) { return Value.isUnsigned(); } static unsigned get(const VariantValue &Value) { return Value.getUnsigned(); } }; /// \brief Generic MatcherCreate interface. /// /// Provides a \c run() method that constructs the matcher from the provided /// arguments. class MatcherCreateCallback { public: virtual ~MatcherCreateCallback() {} virtual VariantMatcher run(const SourceRange &NameRange, ArrayRef Args, Diagnostics *Error) const = 0; }; /// \brief Simple callback implementation. Marshaller and function are provided. /// /// This class wraps a function of arbitrary signature and a marshaller /// function into a MatcherCreateCallback. /// The marshaller is in charge of taking the VariantValue arguments, checking /// their types, unpacking them and calling the underlying function. class FixedArgCountMatcherCreateCallback : public MatcherCreateCallback { public: typedef VariantMatcher (*MarshallerType)(void (*Func)(), StringRef MatcherName, const SourceRange &NameRange, ArrayRef Args, Diagnostics *Error); /// \param Marshaller Function to unpack the arguments and call \c Func /// \param Func Matcher construct function. This is the function that /// compile-time matcher expressions would use to create the matcher. FixedArgCountMatcherCreateCallback(MarshallerType Marshaller, void (*Func)(), StringRef MatcherName) : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName) {} VariantMatcher run(const SourceRange &NameRange, ArrayRef Args, Diagnostics *Error) const { return Marshaller(Func, MatcherName, NameRange, Args, Error); } private: const MarshallerType Marshaller; void (* const Func)(); const std::string MatcherName; }; /// \brief Simple callback implementation. Free function is wrapped. /// /// This class simply wraps a free function with the right signature to export /// it as a MatcherCreateCallback. /// This allows us to have one implementation of the interface for as many free /// functions as we want, reducing the number of symbols and size of the /// object file. class FreeFuncMatcherCreateCallback : public MatcherCreateCallback { public: typedef VariantMatcher (*RunFunc)(StringRef MatcherName, const SourceRange &NameRange, ArrayRef Args, Diagnostics *Error); FreeFuncMatcherCreateCallback(RunFunc Func, StringRef MatcherName) : Func(Func), MatcherName(MatcherName.str()) {} VariantMatcher run(const SourceRange &NameRange, ArrayRef Args, Diagnostics *Error) const { return Func(MatcherName, NameRange, Args, Error); } private: const RunFunc Func; const std::string MatcherName; }; /// \brief Helper macros to check the arguments on all marshaller functions. #define CHECK_ARG_COUNT(count) \ if (Args.size() != count) { \ Error->addError(NameRange, Error->ET_RegistryWrongArgCount) \ << count << Args.size(); \ return VariantMatcher(); \ } #define CHECK_ARG_TYPE(index, type) \ if (!ArgTypeTraits::is(Args[index].Value)) { \ Error->addError(Args[index].Range, Error->ET_RegistryWrongArgType) \ << (index + 1) << ArgTypeTraits::asString() \ << Args[index].Value.getTypeAsString(); \ return VariantMatcher(); \ } /// \brief Helper methods to extract and merge all possible typed matchers /// out of the polymorphic object. template static void mergePolyMatchers(const PolyMatcher &Poly, std::vector &Out, ast_matchers::internal::EmptyTypeList) {} template static void mergePolyMatchers(const PolyMatcher &Poly, std::vector &Out, TypeList) { Out.push_back(ast_matchers::internal::Matcher(Poly)); mergePolyMatchers(Poly, Out, typename TypeList::tail()); } /// \brief Convert the return values of the functions into a VariantMatcher. /// /// There are 2 cases right now: The return value is a Matcher or is a /// polymorphic matcher. For the former, we just construct the VariantMatcher. /// For the latter, we instantiate all the possible Matcher of the poly /// matcher. static VariantMatcher outvalueToVariantMatcher(const DynTypedMatcher &Matcher) { return VariantMatcher::SingleMatcher(Matcher); } template static VariantMatcher outvalueToVariantMatcher(const T &PolyMatcher, typename T::ReturnTypes * = NULL) { std::vector Matchers; mergePolyMatchers(PolyMatcher, Matchers, typename T::ReturnTypes()); VariantMatcher Out = VariantMatcher::PolymorphicMatcher(Matchers); return Out; } /// \brief 0-arg marshaller function. template static VariantMatcher matcherMarshall0(void (*Func)(), StringRef MatcherName, const SourceRange &NameRange, ArrayRef Args, Diagnostics *Error) { typedef ReturnType (*FuncType)(); CHECK_ARG_COUNT(0); return outvalueToVariantMatcher(reinterpret_cast(Func)()); } /// \brief 1-arg marshaller function. template static VariantMatcher matcherMarshall1(void (*Func)(), StringRef MatcherName, const SourceRange &NameRange, ArrayRef Args, Diagnostics *Error) { typedef ReturnType (*FuncType)(ArgType1); CHECK_ARG_COUNT(1); CHECK_ARG_TYPE(0, ArgType1); return outvalueToVariantMatcher(reinterpret_cast(Func)( ArgTypeTraits::get(Args[0].Value))); } /// \brief 2-arg marshaller function. template static VariantMatcher matcherMarshall2(void (*Func)(), StringRef MatcherName, const SourceRange &NameRange, ArrayRef Args, Diagnostics *Error) { typedef ReturnType (*FuncType)(ArgType1, ArgType2); CHECK_ARG_COUNT(2); CHECK_ARG_TYPE(0, ArgType1); CHECK_ARG_TYPE(1, ArgType2); return outvalueToVariantMatcher(reinterpret_cast(Func)( ArgTypeTraits::get(Args[0].Value), ArgTypeTraits::get(Args[1].Value))); } #undef CHECK_ARG_COUNT #undef CHECK_ARG_TYPE /// \brief Variadic marshaller function. template )> VariantMatcher variadicMatcherCreateCallback(StringRef MatcherName, const SourceRange &NameRange, ArrayRef Args, Diagnostics *Error) { ArgT **InnerArgs = new ArgT *[Args.size()](); bool HasError = false; for (size_t i = 0, e = Args.size(); i != e; ++i) { typedef ArgTypeTraits ArgTraits; const ParserValue &Arg = Args[i]; const VariantValue &Value = Arg.Value; if (!ArgTraits::is(Value)) { Error->addError(Arg.Range, Error->ET_RegistryWrongArgType) << (i + 1) << ArgTraits::asString() << Value.getTypeAsString(); HasError = true; break; } InnerArgs[i] = new ArgT(ArgTraits::get(Value)); } VariantMatcher Out; if (!HasError) { Out = outvalueToVariantMatcher( Func(ArrayRef(InnerArgs, Args.size()))); } for (size_t i = 0, e = Args.size(); i != e; ++i) { delete InnerArgs[i]; } delete[] InnerArgs; return Out; } /// \brief Helper class used to collect all the possible overloads of an /// argument adaptative matcher function. template