From: Samuel Benzaquen Date: Thu, 22 Aug 2013 16:38:33 +0000 (+0000) Subject: Refactor VariantMatcher to use an interface underneath. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=544ae5bb0ae09e65f7e09754bdd5d0c97602884d;p=clang Refactor VariantMatcher to use an interface underneath. Summary: Refactor VariantMatcher to use an interface underneath. It supports "Single" and "Polymorphic". Will support more in the future. Reviewers: klimek CC: cfe-commits, revane Differential Revision: http://llvm-reviews.chandlerc.com/D1446 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@189032 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h index abfce078b3..bee5d661db 100644 --- a/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -21,6 +21,7 @@ #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/type_traits.h" @@ -44,13 +45,30 @@ using ast_matchers::internal::DynTypedMatcher; /// - 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; + }; + + /// \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 bool getSingleMatcher(const DynTypedMatcher *&Out) const = 0; + virtual std::string getTypeAsString() const = 0; + virtual bool hasTypedMatcher(const MatcherOps &Ops) const = 0; + virtual const DynTypedMatcher * + getTypedMatcher(const MatcherOps &Ops) const = 0; + }; + public: /// \brief A null matcher. VariantMatcher(); - /// \brief Clones the matcher objects. - VariantMatcher(const VariantMatcher &Other); - /// \brief Clones the provided matcher. static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher); @@ -60,46 +78,42 @@ public: static VariantMatcher PolymorphicMatcher(ArrayRef Matchers); - ~VariantMatcher(); - - /// \brief Copy the \c VariantMatcher, by making a copy of its representation. - VariantMatcher &operator=(const VariantMatcher &Other); - /// \brief Makes the matcher the "null" matcher. void reset(); /// \brief Whether the matcher is null. - bool isNull() const { return List.empty(); } + bool isNull() const { return !Value; } /// \brief Return a single matcher, if there is no ambiguity. /// - /// \returns True, and set Out to the matcher, if there is only one matcher. - /// False, if the underlying matcher is a polymorphic matcher with + /// \returns \c true, and set Out to the matcher, if there is only one + /// matcher. \c false, if the underlying matcher is a polymorphic matcher with /// more than one representation. bool getSingleMatcher(const DynTypedMatcher *&Out) const; - /// \brief Determines if any of the contained matchers can be converted - /// to \c Matcher. + /// \brief Determines if the contained matcher can be converted to + /// \c Matcher. /// - /// Returns true if one, and only one, of the contained matchers can be - /// converted to \c Matcher. If there are more than one that can, the - /// result would be ambigous and false is returned. + /// 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 { - return getTypedMatcher( - &ast_matchers::internal::Matcher::canConstructFrom) != NULL; + if (Value) return Value->hasTypedMatcher(TypedMatcherOps()); + return false; } - /// \brief Wrap the correct matcher as a \c Matcher. + /// \brief Return this matcher as a \c Matcher. /// - /// Selects the appropriate matcher from the wrapped matchers and returns it - /// as a \c Matcher. + /// Handles the different types (Single, Polymorphic) accordingly. /// Asserts that \c hasTypedMatcher() is true. template ast_matchers::internal::Matcher getTypedMatcher() const { assert(hasTypedMatcher()); - return ast_matchers::internal::Matcher::constructFrom(*getTypedMatcher( - &ast_matchers::internal::Matcher::canConstructFrom)); + return ast_matchers::internal::Matcher::constructFrom( + *Value->getTypedMatcher(TypedMatcherOps())); } /// \brief String representation of the type of the value. @@ -109,13 +123,20 @@ public: std::string getTypeAsString() const; private: - /// \brief Returns the matcher that passes the callback. - /// - /// Returns NULL if no matcher passes the test, or if more than one do. - const DynTypedMatcher * - getTypedMatcher(bool (*CanConstructCallback)(const DynTypedMatcher &)) const; + explicit VariantMatcher(Payload *Value) : Value(Value) {} + + class SinglePayload; + class PolymorphicPayload; + + template + class TypedMatcherOps : public MatcherOps { + public: + virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const { + return ast_matchers::internal::Matcher::canConstructFrom(Matcher); + } + }; - std::vector List; + IntrusiveRefCntPtr Value; }; /// \brief Variant value class. diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp index a8fd7c6bbb..87aca7da85 100644 --- a/lib/ASTMatchers/Dynamic/VariantValue.cpp +++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -21,69 +21,105 @@ namespace clang { namespace ast_matchers { namespace dynamic { -VariantMatcher::VariantMatcher() : List() {} +VariantMatcher::MatcherOps::~MatcherOps() {} +VariantMatcher::Payload::~Payload() {} -VariantMatcher::VariantMatcher(const VariantMatcher& Other) { - *this = Other; -} +class VariantMatcher::SinglePayload : public VariantMatcher::Payload { +public: + SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher.clone()) {} -VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) { - VariantMatcher Out; - Out.List.push_back(Matcher.clone()); - return Out; -} + virtual bool getSingleMatcher(const DynTypedMatcher *&Out) const { + Out = Matcher.get(); + return true; + } -VariantMatcher -VariantMatcher::PolymorphicMatcher(ArrayRef Matchers) { - VariantMatcher Out; - for (size_t i = 0, e = Matchers.size(); i != e; ++i) { - Out.List.push_back(Matchers[i]->clone()); + virtual std::string getTypeAsString() const { + return (Twine("Matcher<") + Matcher->getSupportedKind().asStringRef() + ">") + .str(); } - return Out; -} -VariantMatcher::~VariantMatcher() { - reset(); -} + virtual bool hasTypedMatcher(const MatcherOps &Ops) const { + return Ops.canConstructFrom(*Matcher); + } -VariantMatcher &VariantMatcher::operator=(const VariantMatcher &Other) { - if (this == &Other) return *this; - reset(); - for (size_t i = 0, e = Other.List.size(); i != e; ++i) { - List.push_back(Other.List[i]->clone()); + virtual const DynTypedMatcher *getTypedMatcher(const MatcherOps &Ops) const { + assert(hasTypedMatcher(Ops)); + return Matcher.get(); } - return *this; -} -bool VariantMatcher::getSingleMatcher(const DynTypedMatcher *&Out) const { - if (List.size() != 1) return false; - Out = List[0]; - return true; -} +private: + OwningPtr Matcher; +}; -void VariantMatcher::reset() { - llvm::DeleteContainerPointers(List); -} +class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload { +public: + PolymorphicPayload(ArrayRef MatchersIn) { + for (size_t i = 0, e = MatchersIn.size(); i != e; ++i) { + Matchers.push_back(MatchersIn[i]->clone()); + } + } -std::string VariantMatcher::getTypeAsString() const { - std::string Inner; - for (size_t I = 0, E = List.size(); I != E; ++I) { - if (I != 0) Inner += "|"; - Inner += List[I]->getSupportedKind().asStringRef(); + virtual ~PolymorphicPayload() { + llvm::DeleteContainerPointers(Matchers); } - return (Twine("Matcher<") + Inner + ">").str(); -} -const DynTypedMatcher *VariantMatcher::getTypedMatcher( - bool (*CanConstructCallback)(const DynTypedMatcher &)) const { - const DynTypedMatcher *Out = NULL; - for (size_t i = 0, e = List.size(); i != e; ++i) { - if (CanConstructCallback(*List[i])) { - if (Out) return NULL; - Out = List[i]; + virtual bool getSingleMatcher(const DynTypedMatcher *&Out) const { + if (Matchers.size() != 1) + return false; + Out = Matchers[0]; + return true; + } + + virtual std::string getTypeAsString() const { + std::string Inner; + for (size_t i = 0, e = Matchers.size(); i != e; ++i) { + if (i != 0) + Inner += "|"; + Inner += Matchers[i]->getSupportedKind().asStringRef(); } + return (Twine("Matcher<") + Inner + ">").str(); + } + + virtual bool hasTypedMatcher(const MatcherOps &Ops) const { + return getTypedMatcher(Ops) != NULL; } - return Out; + + virtual const DynTypedMatcher *getTypedMatcher(const MatcherOps &Ops) const { + const DynTypedMatcher* Found = NULL; + for (size_t i = 0, e = Matchers.size(); i != e; ++i) { + if (Ops.canConstructFrom(*Matchers[i])) { + if (Found) return NULL; + Found = Matchers[i]; + } + } + return Found; + } + +private: + std::vector Matchers; +}; + +VariantMatcher::VariantMatcher() {} + +VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) { + return VariantMatcher(new SinglePayload(Matcher)); +} + +VariantMatcher +VariantMatcher::PolymorphicMatcher(ArrayRef Matchers) { + return VariantMatcher(new PolymorphicPayload(Matchers)); +} + +bool VariantMatcher::getSingleMatcher(const DynTypedMatcher *&Out) const { + if (Value) return Value->getSingleMatcher(Out); + return false; +} + +void VariantMatcher::reset() { Value.reset(); } + +std::string VariantMatcher::getTypeAsString() const { + if (Value) return Value->getTypeAsString(); + return ""; } VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {