forked from OSchip/llvm-project
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:
parent
4cfe554601
commit
8c9f6330e6
|
@ -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<T>()/getTypedMatcher<T>(): These calls will determine if
|
||||
/// the underlying matcher(s) can unambiguously return a Matcher<T>.
|
||||
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<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.
|
||||
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<T>.
|
||||
/// \brief Determines if the contained matcher can be converted to
|
||||
/// \c Matcher<T>.
|
||||
///
|
||||
/// Returns true if one, and only one, of the contained matchers can be
|
||||
/// converted to \c Matcher<T>. 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<T>.
|
||||
/// 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>
|
||||
bool hasTypedMatcher() const {
|
||||
return getTypedMatcher(
|
||||
&ast_matchers::internal::Matcher<T>::canConstructFrom) != NULL;
|
||||
if (Value) return Value->hasTypedMatcher(TypedMatcherOps<T>());
|
||||
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
|
||||
/// as a \c Matcher<T>.
|
||||
/// Handles the different types (Single, Polymorphic) accordingly.
|
||||
/// Asserts that \c hasTypedMatcher<T>() is true.
|
||||
template <class T>
|
||||
ast_matchers::internal::Matcher<T> getTypedMatcher() const {
|
||||
assert(hasTypedMatcher<T>());
|
||||
return ast_matchers::internal::Matcher<T>::constructFrom(*getTypedMatcher(
|
||||
&ast_matchers::internal::Matcher<T>::canConstructFrom));
|
||||
return ast_matchers::internal::Matcher<T>::constructFrom(
|
||||
*Value->getTypedMatcher(TypedMatcherOps<T>()));
|
||||
}
|
||||
|
||||
/// \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) {}
|
||||
|
||||
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.
|
||||
|
|
|
@ -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()) {}
|
||||
|
||||
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 Out;
|
||||
Out.List.push_back(Matcher.clone());
|
||||
return Out;
|
||||
return VariantMatcher(new SinglePayload(Matcher));
|
||||
}
|
||||
|
||||
VariantMatcher
|
||||
VariantMatcher::PolymorphicMatcher(ArrayRef<const DynTypedMatcher *> Matchers) {
|
||||
VariantMatcher Out;
|
||||
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;
|
||||
return VariantMatcher(new PolymorphicPayload(Matchers));
|
||||
}
|
||||
|
||||
bool VariantMatcher::getSingleMatcher(const DynTypedMatcher *&Out) const {
|
||||
if (List.size() != 1) return false;
|
||||
Out = List[0];
|
||||
return true;
|
||||
if (Value) return Value->getSingleMatcher(Out);
|
||||
return false;
|
||||
}
|
||||
|
||||
void VariantMatcher::reset() {
|
||||
llvm::DeleteContainerPointers(List);
|
||||
}
|
||||
void VariantMatcher::reset() { Value.reset(); }
|
||||
|
||||
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();
|
||||
}
|
||||
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;
|
||||
if (Value) return Value->getTypeAsString();
|
||||
return "<Nothing>";
|
||||
}
|
||||
|
||||
VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {
|
||||
|
|
Loading…
Reference in New Issue