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/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.
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue