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

llvm-svn: 189032
This commit is contained in:
Samuel Benzaquen 2013-08-22 16:38:33 +00:00
parent 4cfe554601
commit 8c9f6330e6
2 changed files with 135 additions and 78 deletions

View File

@ -21,6 +21,7 @@
#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h" #include "clang/ASTMatchers/ASTMatchersInternal.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Twine.h" #include "llvm/ADT/Twine.h"
#include "llvm/Support/type_traits.h" #include "llvm/Support/type_traits.h"
@ -44,13 +45,30 @@ using ast_matchers::internal::DynTypedMatcher;
/// - hasTypedMatcher<T>()/getTypedMatcher<T>(): These calls will determine if /// - hasTypedMatcher<T>()/getTypedMatcher<T>(): These calls will determine if
/// the underlying matcher(s) can unambiguously return a Matcher<T>. /// the underlying matcher(s) can unambiguously return a Matcher<T>.
class VariantMatcher { 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: public:
/// \brief A null matcher. /// \brief A null matcher.
VariantMatcher(); VariantMatcher();
/// \brief Clones the matcher objects.
VariantMatcher(const VariantMatcher &Other);
/// \brief Clones the provided matcher. /// \brief Clones the provided matcher.
static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher); static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher);
@ -60,46 +78,42 @@ public:
static VariantMatcher static VariantMatcher
PolymorphicMatcher(ArrayRef<const DynTypedMatcher *> Matchers); PolymorphicMatcher(ArrayRef<const DynTypedMatcher *> 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. /// \brief Makes the matcher the "null" matcher.
void reset(); void reset();
/// \brief Whether the matcher is null. /// \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. /// \brief Return a single matcher, if there is no ambiguity.
/// ///
/// \returns True, and set Out to the matcher, if there is only one matcher. /// \returns \c true, and set Out to the matcher, if there is only one
/// False, if the underlying matcher is a polymorphic matcher with /// matcher. \c false, if the underlying matcher is a polymorphic matcher with
/// more than one representation. /// more than one representation.
bool getSingleMatcher(const DynTypedMatcher *&Out) const; bool getSingleMatcher(const DynTypedMatcher *&Out) const;
/// \brief Determines if any of the contained matchers can be converted /// \brief Determines if the contained matcher can be converted to
/// to \c Matcher<T>. /// \c Matcher<T>.
/// ///
/// Returns true if one, and only one, of the contained matchers can be /// For the Single case, it returns true if it can be converted to
/// converted to \c Matcher<T>. If there are more than one that can, the /// \c Matcher<T>.
/// result would be ambigous and false is returned. /// For the Polymorphic case, it returns true if one, and only one, of the
/// overloads can be converted to \c Matcher<T>. If there are more than one
/// that can, the result would be ambiguous and false is returned.
template <class T> template <class T>
bool hasTypedMatcher() const { bool hasTypedMatcher() const {
return getTypedMatcher( if (Value) return Value->hasTypedMatcher(TypedMatcherOps<T>());
&ast_matchers::internal::Matcher<T>::canConstructFrom) != NULL; return false;
} }
/// \brief Wrap the correct matcher as a \c Matcher<T>. /// \brief Return this matcher as a \c Matcher<T>.
/// ///
/// Selects the appropriate matcher from the wrapped matchers and returns it /// Handles the different types (Single, Polymorphic) accordingly.
/// as a \c Matcher<T>.
/// Asserts that \c hasTypedMatcher<T>() is true. /// Asserts that \c hasTypedMatcher<T>() is true.
template <class T> template <class T>
ast_matchers::internal::Matcher<T> getTypedMatcher() const { ast_matchers::internal::Matcher<T> getTypedMatcher() const {
assert(hasTypedMatcher<T>()); assert(hasTypedMatcher<T>());
return ast_matchers::internal::Matcher<T>::constructFrom(*getTypedMatcher( return ast_matchers::internal::Matcher<T>::constructFrom(
&ast_matchers::internal::Matcher<T>::canConstructFrom)); *Value->getTypedMatcher(TypedMatcherOps<T>()));
} }
/// \brief String representation of the type of the value. /// \brief String representation of the type of the value.
@ -109,13 +123,20 @@ public:
std::string getTypeAsString() const; std::string getTypeAsString() const;
private: private:
/// \brief Returns the matcher that passes the callback. explicit VariantMatcher(Payload *Value) : Value(Value) {}
///
/// Returns NULL if no matcher passes the test, or if more than one do.
const DynTypedMatcher *
getTypedMatcher(bool (*CanConstructCallback)(const DynTypedMatcher &)) const;
std::vector<const DynTypedMatcher *> List; class SinglePayload;
class PolymorphicPayload;
template <typename T>
class TypedMatcherOps : public MatcherOps {
public:
virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const {
return ast_matchers::internal::Matcher<T>::canConstructFrom(Matcher);
}
};
IntrusiveRefCntPtr<const Payload> Value;
}; };
/// \brief Variant value class. /// \brief Variant value class.

View File

@ -21,69 +21,105 @@ namespace clang {
namespace ast_matchers { namespace ast_matchers {
namespace dynamic { namespace dynamic {
VariantMatcher::VariantMatcher() : List() {} VariantMatcher::MatcherOps::~MatcherOps() {}
VariantMatcher::Payload::~Payload() {}
VariantMatcher::VariantMatcher(const VariantMatcher& Other) { class VariantMatcher::SinglePayload : public VariantMatcher::Payload {
*this = Other; public:
} SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher.clone()) {}
virtual bool getSingleMatcher(const DynTypedMatcher *&Out) const {
Out = Matcher.get();
return true;
}
virtual std::string getTypeAsString() const {
return (Twine("Matcher<") + Matcher->getSupportedKind().asStringRef() + ">")
.str();
}
virtual bool hasTypedMatcher(const MatcherOps &Ops) const {
return Ops.canConstructFrom(*Matcher);
}
virtual const DynTypedMatcher *getTypedMatcher(const MatcherOps &Ops) const {
assert(hasTypedMatcher(Ops));
return Matcher.get();
}
private:
OwningPtr<const DynTypedMatcher> Matcher;
};
class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload {
public:
PolymorphicPayload(ArrayRef<const DynTypedMatcher *> MatchersIn) {
for (size_t i = 0, e = MatchersIn.size(); i != e; ++i) {
Matchers.push_back(MatchersIn[i]->clone());
}
}
virtual ~PolymorphicPayload() {
llvm::DeleteContainerPointers(Matchers);
}
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;
}
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<const DynTypedMatcher *> Matchers;
};
VariantMatcher::VariantMatcher() {}
VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) { VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) {
VariantMatcher Out; return VariantMatcher(new SinglePayload(Matcher));
Out.List.push_back(Matcher.clone());
return Out;
} }
VariantMatcher VariantMatcher
VariantMatcher::PolymorphicMatcher(ArrayRef<const DynTypedMatcher *> Matchers) { VariantMatcher::PolymorphicMatcher(ArrayRef<const DynTypedMatcher *> Matchers) {
VariantMatcher Out; return VariantMatcher(new PolymorphicPayload(Matchers));
for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
Out.List.push_back(Matchers[i]->clone());
}
return Out;
}
VariantMatcher::~VariantMatcher() {
reset();
}
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());
}
return *this;
} }
bool VariantMatcher::getSingleMatcher(const DynTypedMatcher *&Out) const { bool VariantMatcher::getSingleMatcher(const DynTypedMatcher *&Out) const {
if (List.size() != 1) return false; if (Value) return Value->getSingleMatcher(Out);
Out = List[0]; return false;
return true;
} }
void VariantMatcher::reset() { void VariantMatcher::reset() { Value.reset(); }
llvm::DeleteContainerPointers(List);
}
std::string VariantMatcher::getTypeAsString() const { std::string VariantMatcher::getTypeAsString() const {
std::string Inner; if (Value) return Value->getTypeAsString();
for (size_t I = 0, E = List.size(); I != E; ++I) { return "<Nothing>";
if (I != 0) Inner += "|";
Inner += List[I]->getSupportedKind().asStringRef();
}
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];
}
}
return Out;
} }
VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) { VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {