//===- Marshallers.h - Generic matcher function marshallers -----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // /// \file /// 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_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H #define LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/OperationKinds.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" #include "clang/ASTMatchers/Dynamic/Diagnostics.h" #include "clang/ASTMatchers/Dynamic/VariantValue.h" #include "clang/Basic/AttrKinds.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/TypeTraits.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Regex.h" #include #include #include #include #include #include #include #include namespace clang { namespace ast_matchers { namespace dynamic { namespace internal { /// 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 bool is(const VariantValue &Value) { return Value.isString(); } static const std::string &get(const VariantValue &Value) { return Value.getString(); } static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } static llvm::Optional getBestGuess(const VariantValue &) { return llvm::None; } }; template <> struct ArgTypeTraits : public ArgTypeTraits { }; template struct ArgTypeTraits> { 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(); } static ArgKind getKind() { return ArgKind(ASTNodeKind::getFromNodeKind()); } static llvm::Optional getBestGuess(const VariantValue &) { return llvm::None; } }; template <> struct ArgTypeTraits { static bool is(const VariantValue &Value) { return Value.isBoolean(); } static bool get(const VariantValue &Value) { return Value.getBoolean(); } static ArgKind getKind() { return ArgKind(ArgKind::AK_Boolean); } static llvm::Optional getBestGuess(const VariantValue &) { return llvm::None; } }; template <> struct ArgTypeTraits { static bool is(const VariantValue &Value) { return Value.isDouble(); } static double get(const VariantValue &Value) { return Value.getDouble(); } static ArgKind getKind() { return ArgKind(ArgKind::AK_Double); } static llvm::Optional getBestGuess(const VariantValue &) { return llvm::None; } }; template <> struct ArgTypeTraits { static bool is(const VariantValue &Value) { return Value.isUnsigned(); } static unsigned get(const VariantValue &Value) { return Value.getUnsigned(); } static ArgKind getKind() { return ArgKind(ArgKind::AK_Unsigned); } static llvm::Optional getBestGuess(const VariantValue &) { return llvm::None; } }; template <> struct ArgTypeTraits { private: static Optional getAttrKind(llvm::StringRef AttrKind) { return llvm::StringSwitch>(AttrKind) #define ATTR(X) .Case("attr::" #X, attr:: X) #include "clang/Basic/AttrList.inc" .Default(llvm::None); } public: static bool is(const VariantValue &Value) { return Value.isString() && getAttrKind(Value.getString()); } static attr::Kind get(const VariantValue &Value) { return *getAttrKind(Value.getString()); } static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } static llvm::Optional getBestGuess(const VariantValue &Value); }; template <> struct ArgTypeTraits { private: static Optional getCastKind(llvm::StringRef AttrKind) { return llvm::StringSwitch>(AttrKind) #define CAST_OPERATION(Name) .Case("CK_" #Name, CK_##Name) #include "clang/AST/OperationKinds.def" .Default(llvm::None); } public: static bool is(const VariantValue &Value) { return Value.isString() && getCastKind(Value.getString()); } static CastKind get(const VariantValue &Value) { return *getCastKind(Value.getString()); } static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } static llvm::Optional getBestGuess(const VariantValue &Value); }; template <> struct ArgTypeTraits { private: static Optional getFlags(llvm::StringRef Flags); public: static bool is(const VariantValue &Value) { return Value.isString() && getFlags(Value.getString()); } static llvm::Regex::RegexFlags get(const VariantValue &Value) { return *getFlags(Value.getString()); } static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } static llvm::Optional getBestGuess(const VariantValue &Value); }; template <> struct ArgTypeTraits { private: static Optional getClauseKind(llvm::StringRef ClauseKind) { return llvm::StringSwitch>(ClauseKind) #define OMP_CLAUSE_CLASS(Enum, Str, Class) .Case(#Enum, llvm::omp::Clause::Enum) #include "llvm/Frontend/OpenMP/OMPKinds.def" .Default(llvm::None); } public: static bool is(const VariantValue &Value) { return Value.isString() && getClauseKind(Value.getString()); } static OpenMPClauseKind get(const VariantValue &Value) { return *getClauseKind(Value.getString()); } static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } static llvm::Optional getBestGuess(const VariantValue &Value); }; template <> struct ArgTypeTraits { private: static Optional getUnaryOrTypeTraitKind(llvm::StringRef ClauseKind) { return llvm::StringSwitch>(ClauseKind) #define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) \ .Case("UETT_" #Name, UETT_##Name) #define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) \ .Case("UETT_" #Name, UETT_##Name) #include "clang/Basic/TokenKinds.def" .Default(llvm::None); } public: static bool is(const VariantValue &Value) { return Value.isString() && getUnaryOrTypeTraitKind(Value.getString()); } static UnaryExprOrTypeTrait get(const VariantValue &Value) { return *getUnaryOrTypeTraitKind(Value.getString()); } static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } static llvm::Optional getBestGuess(const VariantValue &Value); }; /// Matcher descriptor interface. /// /// Provides a \c create() method that constructs the matcher from the provided /// arguments, and various other methods for type introspection. class MatcherDescriptor { public: virtual ~MatcherDescriptor() = default; virtual VariantMatcher create(SourceRange NameRange, ArrayRef Args, Diagnostics *Error) const = 0; /// Returns whether the matcher is variadic. Variadic matchers can take any /// number of arguments, but they must be of the same type. virtual bool isVariadic() const = 0; /// Returns the number of arguments accepted by the matcher if not variadic. virtual unsigned getNumArgs() const = 0; /// Given that the matcher is being converted to type \p ThisKind, append the /// set of argument types accepted for argument \p ArgNo to \p ArgKinds. // FIXME: We should provide the ability to constrain the output of this // function based on the types of other matcher arguments. virtual void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo, std::vector &ArgKinds) const = 0; /// Returns whether this matcher is convertible to the given type. If it is /// so convertible, store in *Specificity a value corresponding to the /// "specificity" of the converted matcher to the given context, and in /// *LeastDerivedKind the least derived matcher kind which would result in the /// same matcher overload. Zero specificity indicates that this conversion /// would produce a trivial matcher that will either always or never match. /// Such matchers are excluded from code completion results. virtual bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity = nullptr, ASTNodeKind *LeastDerivedKind = nullptr) const = 0; /// Returns whether the matcher will, given a matcher of any type T, yield a /// matcher of type T. virtual bool isPolymorphic() const { return false; } }; inline bool isRetKindConvertibleTo(ArrayRef RetKinds, ASTNodeKind Kind, unsigned *Specificity, ASTNodeKind *LeastDerivedKind) { for (const ASTNodeKind &NodeKind : RetKinds) { if (ArgKind(NodeKind).isConvertibleTo(Kind, Specificity)) { if (LeastDerivedKind) *LeastDerivedKind = NodeKind; return true; } } return false; } /// Simple callback implementation. Marshaller and function are provided. /// /// This class wraps a function of arbitrary signature and a marshaller /// function into a MatcherDescriptor. /// The marshaller is in charge of taking the VariantValue arguments, checking /// their types, unpacking them and calling the underlying function. class FixedArgCountMatcherDescriptor : public MatcherDescriptor { public: using MarshallerType = VariantMatcher (*)(void (*Func)(), StringRef MatcherName, 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. /// \param RetKinds The list of matcher types to which the matcher is /// convertible. /// \param ArgKinds The types of the arguments this matcher takes. FixedArgCountMatcherDescriptor(MarshallerType Marshaller, void (*Func)(), StringRef MatcherName, ArrayRef RetKinds, ArrayRef ArgKinds) : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName), RetKinds(RetKinds.begin(), RetKinds.end()), ArgKinds(ArgKinds.begin(), ArgKinds.end()) {} VariantMatcher create(SourceRange NameRange, ArrayRef Args, Diagnostics *Error) const override { return Marshaller(Func, MatcherName, NameRange, Args, Error); } bool isVariadic() const override { return false; } unsigned getNumArgs() const override { return ArgKinds.size(); } void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo, std::vector &Kinds) const override { Kinds.push_back(ArgKinds[ArgNo]); } bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity, ASTNodeKind *LeastDerivedKind) const override { return isRetKindConvertibleTo(RetKinds, Kind, Specificity, LeastDerivedKind); } private: const MarshallerType Marshaller; void (* const Func)(); const std::string MatcherName; const std::vector RetKinds; const std::vector ArgKinds; }; /// 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()); } /// 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. inline VariantMatcher outvalueToVariantMatcher(const DynTypedMatcher &Matcher) { return VariantMatcher::SingleMatcher(Matcher); } template static VariantMatcher outvalueToVariantMatcher(const T &PolyMatcher, typename T::ReturnTypes * = nullptr) { std::vector Matchers; mergePolyMatchers(PolyMatcher, Matchers, typename T::ReturnTypes()); VariantMatcher Out = VariantMatcher::PolymorphicMatcher(std::move(Matchers)); return Out; } template inline void buildReturnTypeVectorFromTypeList(std::vector &RetTypes) { RetTypes.push_back(ASTNodeKind::getFromNodeKind()); buildReturnTypeVectorFromTypeList(RetTypes); } template <> inline void buildReturnTypeVectorFromTypeList( std::vector &RetTypes) {} template struct BuildReturnTypeVector { static void build(std::vector &RetTypes) { buildReturnTypeVectorFromTypeList(RetTypes); } }; template struct BuildReturnTypeVector> { static void build(std::vector &RetTypes) { RetTypes.push_back(ASTNodeKind::getFromNodeKind()); } }; template struct BuildReturnTypeVector> { static void build(std::vector &RetTypes) { RetTypes.push_back(ASTNodeKind::getFromNodeKind()); } }; /// Variadic marshaller function. template )> VariantMatcher variadicMatcherDescriptor(StringRef MatcherName, 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) { using ArgTraits = ArgTypeTraits; const ParserValue &Arg = Args[i]; const VariantValue &Value = Arg.Value; if (!ArgTraits::is(Value)) { Error->addError(Arg.Range, Error->ET_RegistryWrongArgType) << (i + 1) << ArgTraits::getKind().asString() << Value.getTypeAsString(); HasError = true; break; } InnerArgs[i] = new ArgT(ArgTraits::get(Value)); } VariantMatcher Out; if (!HasError) { Out = outvalueToVariantMatcher(Func(llvm::makeArrayRef(InnerArgs, Args.size()))); } for (size_t i = 0, e = Args.size(); i != e; ++i) { delete InnerArgs[i]; } delete[] InnerArgs; return Out; } /// Matcher descriptor for variadic functions. /// /// This class simply wraps a VariadicFunction with the right signature to export /// it as a MatcherDescriptor. /// 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 VariadicFuncMatcherDescriptor : public MatcherDescriptor { public: using RunFunc = VariantMatcher (*)(StringRef MatcherName, SourceRange NameRange, ArrayRef Args, Diagnostics *Error); template )> VariadicFuncMatcherDescriptor( ast_matchers::internal::VariadicFunction Func, StringRef MatcherName) : Func(&variadicMatcherDescriptor), MatcherName(MatcherName.str()), ArgsKind(ArgTypeTraits::getKind()) { BuildReturnTypeVector::build(RetKinds); } VariantMatcher create(SourceRange NameRange, ArrayRef Args, Diagnostics *Error) const override { return Func(MatcherName, NameRange, Args, Error); } bool isVariadic() const override { return true; } unsigned getNumArgs() const override { return 0; } void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo, std::vector &Kinds) const override { Kinds.push_back(ArgsKind); } bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity, ASTNodeKind *LeastDerivedKind) const override { return isRetKindConvertibleTo(RetKinds, Kind, Specificity, LeastDerivedKind); } private: const RunFunc Func; const std::string MatcherName; std::vector RetKinds; const ArgKind ArgsKind; }; /// Return CK_Trivial when appropriate for VariadicDynCastAllOfMatchers. class DynCastAllOfMatcherDescriptor : public VariadicFuncMatcherDescriptor { public: template DynCastAllOfMatcherDescriptor( ast_matchers::internal::VariadicDynCastAllOfMatcher Func, StringRef MatcherName) : VariadicFuncMatcherDescriptor(Func, MatcherName), DerivedKind(ASTNodeKind::getFromNodeKind()) {} bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity, ASTNodeKind *LeastDerivedKind) const override { // If Kind is not a base of DerivedKind, either DerivedKind is a base of // Kind (in which case the match will always succeed) or Kind and // DerivedKind are unrelated (in which case it will always fail), so set // Specificity to 0. if (VariadicFuncMatcherDescriptor::isConvertibleTo(Kind, Specificity, LeastDerivedKind)) { if (Kind.isSame(DerivedKind) || !Kind.isBaseOf(DerivedKind)) { if (Specificity) *Specificity = 0; } return true; } else { return false; } } private: const ASTNodeKind DerivedKind; }; /// 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)) { \ if (llvm::Optional BestGuess = \ ArgTypeTraits::getBestGuess(Args[index].Value)) { \ Error->addError(Args[index].Range, \ Error->ET_RegistryUnknownEnumWithReplace) \ << index + 1 << Args[index].Value.getString() << *BestGuess; \ } else { \ Error->addError(Args[index].Range, Error->ET_RegistryWrongArgType) \ << (index + 1) << ArgTypeTraits::getKind().asString() \ << Args[index].Value.getTypeAsString(); \ } \ return VariantMatcher(); \ } /// 0-arg marshaller function. template static VariantMatcher matcherMarshall0(void (*Func)(), StringRef MatcherName, SourceRange NameRange, ArrayRef Args, Diagnostics *Error) { using FuncType = ReturnType (*)(); CHECK_ARG_COUNT(0); return outvalueToVariantMatcher(reinterpret_cast(Func)()); } /// 1-arg marshaller function. template static VariantMatcher matcherMarshall1(void (*Func)(), StringRef MatcherName, SourceRange NameRange, ArrayRef Args, Diagnostics *Error) { using FuncType = ReturnType (*)(ArgType1); CHECK_ARG_COUNT(1); CHECK_ARG_TYPE(0, ArgType1); return outvalueToVariantMatcher(reinterpret_cast(Func)( ArgTypeTraits::get(Args[0].Value))); } /// 2-arg marshaller function. template static VariantMatcher matcherMarshall2(void (*Func)(), StringRef MatcherName, SourceRange NameRange, ArrayRef Args, Diagnostics *Error) { using FuncType = ReturnType (*)(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 /// Helper class used to collect all the possible overloads of an /// argument adaptative matcher function. template