//===--- VariantValue.h - Polymorphic value type -*- C++ -*-===/ // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief Polymorphic value type. /// /// Supports all the types required for dynamic Matcher construction. /// Used by the registry to construct matchers in a generic way. /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H #define LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H #include #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/type_traits.h" namespace clang { namespace ast_matchers { namespace dynamic { using ast_matchers::internal::DynTypedMatcher; /// \brief A variant matcher object. /// /// The purpose of this object is to abstract simple and polymorphic matchers /// into a single object type. /// Polymorphic matchers might be implemented as a list of all the possible /// overloads of the matcher. \c VariantMatcher knows how to select the /// appropriate overload when needed. /// To get a real matcher object out of a \c VariantMatcher you can do: /// - getSingleMatcher() which returns a matcher, only if it is not ambiguous /// to decide which matcher to return. Eg. it contains only a single /// matcher, or a polymorphic one with only one overload. /// - hasTypedMatcher()/getTypedMatcher(): These calls will determine if /// the underlying matcher(s) can unambiguously return a Matcher. class VariantMatcher { /// \brief Methods that depend on T from hasTypedMatcher/getTypedMatcher. class MatcherOps { public: virtual ~MatcherOps(); virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const = 0; virtual void constructFrom(const DynTypedMatcher &Matcher) = 0; virtual void constructVariadicOperator( ast_matchers::internal::VariadicOperatorFunction Func, ArrayRef InnerMatchers) = 0; }; /// \brief Payload interface to be specialized by each matcher type. /// /// It follows a similar interface as VariantMatcher itself. class Payload : public RefCountedBaseVPTR { public: virtual ~Payload(); virtual llvm::Optional getSingleMatcher() const = 0; virtual std::string getTypeAsString() const = 0; virtual void makeTypedMatcher(MatcherOps &Ops) const = 0; }; public: /// \brief A null matcher. VariantMatcher(); /// \brief Clones the provided matcher. static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher); /// \brief Clones the provided matchers. /// /// They should be the result of a polymorphic matcher. static VariantMatcher PolymorphicMatcher(ArrayRef Matchers); /// \brief Creates a 'variadic' operator matcher. /// /// It will bind to the appropriate type on getTypedMatcher(). static VariantMatcher VariadicOperatorMatcher( ast_matchers::internal::VariadicOperatorFunction Func, ArrayRef Args); /// \brief Makes the matcher the "null" matcher. void reset(); /// \brief Whether the matcher is null. bool isNull() const { return !Value; } /// \brief Return a single matcher, if there is no ambiguity. /// /// \returns the matcher, if there is only one matcher. An empty Optional, if /// the underlying matcher is a polymorphic matcher with more than one /// representation. llvm::Optional getSingleMatcher() const; /// \brief Determines if the contained matcher can be converted to /// \c Matcher. /// /// For the Single case, it returns true if it can be converted to /// \c Matcher. /// For the Polymorphic case, it returns true if one, and only one, of the /// overloads can be converted to \c Matcher. If there are more than one /// that can, the result would be ambiguous and false is returned. template bool hasTypedMatcher() const { TypedMatcherOps Ops; if (Value) Value->makeTypedMatcher(Ops); return Ops.hasMatcher(); } /// \brief Return this matcher as a \c Matcher. /// /// Handles the different types (Single, Polymorphic) accordingly. /// Asserts that \c hasTypedMatcher() is true. template ast_matchers::internal::Matcher getTypedMatcher() const { TypedMatcherOps Ops; Value->makeTypedMatcher(Ops); assert(Ops.hasMatcher() && "hasTypedMatcher() == false"); return Ops.matcher(); } /// \brief String representation of the type of the value. /// /// If the underlying matcher is a polymorphic one, the string will show all /// the types. std::string getTypeAsString() const; private: explicit VariantMatcher(Payload *Value) : Value(Value) {} class SinglePayload; class PolymorphicPayload; class VariadicOpPayload; template class TypedMatcherOps : public MatcherOps { public: typedef ast_matchers::internal::Matcher MatcherT; virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const { return Matcher.canConvertTo(); } virtual void constructFrom(const DynTypedMatcher& Matcher) { Out.reset(new MatcherT(Matcher.convertTo())); } virtual void constructVariadicOperator( ast_matchers::internal::VariadicOperatorFunction Func, ArrayRef InnerMatchers) { const size_t NumArgs = InnerMatchers.size(); MatcherT **InnerArgs = new MatcherT *[NumArgs](); bool HasError = false; for (size_t i = 0; i != NumArgs; ++i) { // Abort if any of the inner matchers can't be converted to // Matcher. if (!InnerMatchers[i].hasTypedMatcher()) { HasError = true; break; } InnerArgs[i] = new MatcherT(InnerMatchers[i].getTypedMatcher()); } if (!HasError) { Out.reset(new MatcherT( new ast_matchers::internal::VariadicOperatorMatcherInterface( Func, ArrayRef(InnerArgs, NumArgs)))); } for (size_t i = 0; i != NumArgs; ++i) { delete InnerArgs[i]; } delete[] InnerArgs; } bool hasMatcher() const { return Out.get() != NULL; } const MatcherT &matcher() const { return *Out; } private: OwningPtr Out; }; IntrusiveRefCntPtr Value; }; /// \brief Variant value class. /// /// Basically, a tagged union with value type semantics. /// It is used by the registry as the return value and argument type for the /// matcher factory methods. /// It can be constructed from any of the supported types. It supports /// copy/assignment. /// /// Supported types: /// - \c unsigned /// - \c std::string /// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher) class VariantValue { public: VariantValue() : Type(VT_Nothing) {} VariantValue(const VariantValue &Other); ~VariantValue(); VariantValue &operator=(const VariantValue &Other); /// \brief Specific constructors for each supported type. VariantValue(unsigned Unsigned); VariantValue(const std::string &String); VariantValue(const VariantMatcher &Matchers); /// \brief Unsigned value functions. bool isUnsigned() const; unsigned getUnsigned() const; void setUnsigned(unsigned Unsigned); /// \brief String value functions. bool isString() const; const std::string &getString() const; void setString(const std::string &String); /// \brief Matcher value functions. bool isMatcher() const; const VariantMatcher &getMatcher() const; void setMatcher(const VariantMatcher &Matcher); /// \brief String representation of the type of the value. std::string getTypeAsString() const; private: void reset(); /// \brief All supported value types. enum ValueType { VT_Nothing, VT_Unsigned, VT_String, VT_Matcher }; /// \brief All supported value types. union AllValues { unsigned Unsigned; std::string *String; VariantMatcher *Matcher; }; ValueType Type; AllValues Value; }; } // end namespace dynamic } // end namespace ast_matchers } // end namespace clang #endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_VARIANT_VALUE_H