Refactor DynTypedMatcher into a value type class, just like Matcher<T>.

Summary:
Refactor DynTypedMatcher into a value type class, just like Matcher<T>.
This simplifies its usage and removes the virtual hierarchy from Matcher<T>.
It also enables planned changes to replace MatcherInteface<T>.
Too many instantiaions of this class hierarchy has been causing Registry.cpp.o to bloat in size and number of symbols.

Reviewers: klimek

CC: cfe-commits, revane

Differential Revision: http://llvm-reviews.chandlerc.com/D1661

llvm-svn: 193100
This commit is contained in:
Samuel Benzaquen 2013-10-21 18:40:51 +00:00
parent 4517d59880
commit f46e5f1c9a
11 changed files with 297 additions and 321 deletions

View File

@ -162,7 +162,7 @@ public:
private:
/// \brief For each \c DynTypedMatcher a \c MatchCallback that will be called
/// when it matches.
std::vector<std::pair<const internal::DynTypedMatcher*, MatchCallback*> >
std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> >
MatcherCallbackPairs;
/// \brief Called when parsing is done.

View File

@ -36,12 +36,13 @@
#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/VariadicFunction.h"
#include "llvm/Support/type_traits.h"
#include <map>
@ -200,38 +201,6 @@ private:
}
};
/// \brief Base class for all matchers that works on a \c DynTypedNode.
///
/// Matcher implementations will check whether the \c DynTypedNode is
/// convertible into the respecitve types and then do the actual match
/// on the actual node, or return false if it is not convertible.
class DynTypedMatcher {
public:
virtual ~DynTypedMatcher();
/// \brief Returns true if the matcher matches the given \c DynNode.
virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const = 0;
/// \brief Makes a copy of this matcher object.
virtual DynTypedMatcher *clone() const = 0;
/// \brief Returns a unique ID for the matcher.
virtual uint64_t getID() const = 0;
/// \brief Bind the specified \p ID to the matcher.
/// \return A new matcher with the \p ID bound to it if this matcher supports
/// binding. Otherwise, returns NULL. Returns NULL by default.
virtual DynTypedMatcher* tryBind(StringRef ID) const;
/// \brief Returns the type this matcher works on.
///
/// \c matches() will always return false unless the node passed is of this
/// or a derived type.
virtual ast_type_traits::ASTNodeKind getSupportedKind() const = 0;
};
/// \brief Wrapper of a MatcherInterface<T> *that allows copying.
///
/// A Matcher<Base> can be used anywhere a Matcher<Derived> is
@ -241,7 +210,7 @@ public:
/// operator rather than a type hierarchy to be able to templatize the
/// type hierarchy instead of spelling it out.
template <typename T>
class Matcher : public DynTypedMatcher {
class Matcher {
public:
/// \brief Takes ownership of the provided implementation pointer.
explicit Matcher(MatcherInterface<T> *Implementation)
@ -267,35 +236,6 @@ public:
llvm::is_same<TypeT, Type>::value >::type* = 0)
: Implementation(new TypeToQualType<TypeT>(Other)) {}
/// \brief Returns \c true if the passed DynTypedMatcher can be converted
/// to a \c Matcher<T>.
///
/// This method verifies that the underlying matcher in \c Other can process
/// nodes of types T.
static bool canConstructFrom(const DynTypedMatcher &Other) {
return Other.getSupportedKind()
.isBaseOf(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
}
/// \brief Construct a Matcher<T> interface around the dynamic matcher
/// \c Other.
///
/// This method asserts that canConstructFrom(Other) is \c true. Callers
/// should call canConstructFrom(Other) first to make sure that Other is
/// compatible with T.
static Matcher<T> constructFrom(const DynTypedMatcher &Other) {
assert(canConstructFrom(Other));
return constructFromUnsafe(Other);
}
/// \brief Same as constructFrom(), but does not check that the underlying
/// matcher can handle a value of T.
///
/// If it is not compatible, then this matcher will never match anything.
static Matcher<T> constructFromUnsafe(const DynTypedMatcher &Other) {
return Matcher<T>(new WrappedMatcher(Other));
}
/// \brief Forwards the call to the underlying MatcherInterface<T> pointer.
bool matches(const T &Node,
ASTMatchFinder *Finder,
@ -316,23 +256,6 @@ public:
return reinterpret_cast<uint64_t>(Implementation.getPtr());
}
/// \brief Returns the type this matcher works on.
ast_type_traits::ASTNodeKind getSupportedKind() const {
return ast_type_traits::ASTNodeKind::getFromNodeKind<T>();
}
/// \brief Returns whether the matcher matches on the given \c DynNode.
virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
const T *Node = DynNode.get<T>();
if (!Node) return false;
return matches(*Node, Finder, Builder);
}
/// \brief Makes a copy of this matcher object.
virtual Matcher<T> *clone() const { return new Matcher<T>(*this); }
/// \brief Allows the conversion of a \c Matcher<Type> to a \c
/// Matcher<QualType>.
///
@ -375,23 +298,6 @@ private:
const Matcher<Base> From;
};
/// \brief Simple MatcherInterface<T> wrapper around a DynTypedMatcher.
class WrappedMatcher : public MatcherInterface<T> {
public:
explicit WrappedMatcher(const DynTypedMatcher &Matcher)
: Inner(Matcher.clone()) {}
virtual ~WrappedMatcher() {}
bool matches(const T &Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return Inner->matches(ast_type_traits::DynTypedNode::create(Node), Finder,
Builder);
}
private:
const OwningPtr<DynTypedMatcher> Inner;
};
IntrusiveRefCntPtr< MatcherInterface<T> > Implementation;
}; // class Matcher
@ -402,15 +308,160 @@ inline Matcher<T> makeMatcher(MatcherInterface<T> *Implementation) {
return Matcher<T>(Implementation);
}
template <typename T> class BindableMatcher;
/// \brief Matcher that works on a \c DynTypedNode.
///
/// It is constructed from a \c Matcher<T> object and redirects most calls to
/// underlying matcher.
/// It checks whether the \c DynTypedNode is convertible into the type of the
/// underlying matcher and then do the actual match on the actual node, or
/// return false if it is not convertible.
class DynTypedMatcher {
public:
/// \brief Construct from a \c Matcher<T>. Copies the matcher.
template <typename T>
DynTypedMatcher(const Matcher<T> &M)
: Storage(new TypedMatcherStorage<T>(M, false)) {}
/// \brief Construct from a bindable \c Matcher<T>. Copies the matcher.
///
/// This version enables \c tryBind() on the \c DynTypedMatcher.
template <typename T>
DynTypedMatcher(const BindableMatcher<T> &M)
: Storage(new TypedMatcherStorage<T>(M, true)) {}
/// \brief Returns true if the matcher matches the given \c DynNode.
bool matches(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const {
return Storage->matches(DynNode, Finder, Builder);
}
/// \brief Bind the specified \p ID to the matcher.
/// \return A new matcher with the \p ID bound to it if this matcher supports
/// binding. Otherwise, returns an empty \c Optional<>.
llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const {
return Storage->tryBind(ID);
}
/// \brief Returns a unique \p ID for the matcher.
uint64_t getID() const { return Storage->getID(); }
/// \brief Returns the type this matcher works on.
///
/// \c matches() will always return false unless the node passed is of this
/// or a derived type.
ast_type_traits::ASTNodeKind getSupportedKind() const {
return Storage->getSupportedKind();
}
/// \brief Returns \c true if the passed \c DynTypedMatcher can be converted
/// to a \c Matcher<T>.
///
/// This method verifies that the underlying matcher in \c Other can process
/// nodes of types T.
template <typename T> bool canConvertTo() const {
return getSupportedKind().isBaseOf(
ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
}
/// \brief Construct a \c Matcher<T> interface around the dynamic matcher.
///
/// This method asserts that \c canConvertTo() is \c true. Callers
/// should call \c canConvertTo() first to make sure that \c this is
/// compatible with T.
template <typename T> Matcher<T> convertTo() const {
assert(canConvertTo<T>());
return unconditionalConvertTo<T>();
}
/// \brief Same as \c convertTo(), but does not check that the underlying
/// matcher can handle a value of T.
///
/// If it is not compatible, then this matcher will never match anything.
template <typename T> Matcher<T> unconditionalConvertTo() const {
return Matcher<T>(new WrappedMatcher<T>(*this));
}
private:
class MatcherStorage : public RefCountedBaseVPTR {
public:
MatcherStorage(ast_type_traits::ASTNodeKind SupportedKind, uint64_t ID)
: SupportedKind(SupportedKind), ID(ID) {}
virtual ~MatcherStorage();
virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const = 0;
virtual llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const = 0;
ast_type_traits::ASTNodeKind getSupportedKind() const {
return SupportedKind;
}
uint64_t getID() const { return ID; }
private:
const ast_type_traits::ASTNodeKind SupportedKind;
const uint64_t ID;
};
template <typename T> class TypedMatcherStorage : public MatcherStorage {
public:
TypedMatcherStorage(const Matcher<T> &Other, bool AllowBind)
: MatcherStorage(ast_type_traits::ASTNodeKind::getFromNodeKind<T>(),
Other.getID()),
InnerMatcher(Other), AllowBind(AllowBind) {}
bool matches(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const
LLVM_OVERRIDE {
if (const T *Node = DynNode.get<T>()) {
return InnerMatcher.matches(*Node, Finder, Builder);
}
return false;
}
llvm::Optional<DynTypedMatcher> tryBind(StringRef ID) const LLVM_OVERRIDE {
if (!AllowBind)
return llvm::Optional<DynTypedMatcher>();
return DynTypedMatcher(BindableMatcher<T>(InnerMatcher).bind(ID));
}
private:
const Matcher<T> InnerMatcher;
const bool AllowBind;
};
/// \brief Simple MatcherInterface<T> wrapper around a DynTypedMatcher.
template <typename T> class WrappedMatcher;
IntrusiveRefCntPtr<const MatcherStorage> Storage;
};
template <typename T>
class DynTypedMatcher::WrappedMatcher : public MatcherInterface<T> {
public:
explicit WrappedMatcher(const DynTypedMatcher &Matcher) : Inner(Matcher) {}
virtual ~WrappedMatcher() {}
bool matches(const T &Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return Inner.matches(ast_type_traits::DynTypedNode::create(Node), Finder,
Builder);
}
private:
const DynTypedMatcher Inner;
};
/// \brief Specialization of the conversion functions for QualType.
///
/// These specializations provide the Matcher<Type>->Matcher<QualType>
/// conversion that the static API does.
template <>
inline bool
Matcher<QualType>::canConstructFrom(const DynTypedMatcher &Other) {
ast_type_traits::ASTNodeKind SourceKind = Other.getSupportedKind();
// We support implicit conversion from Matcher<Type> to Matcher<QualType>
template <> inline bool DynTypedMatcher::canConvertTo<QualType>() const {
const ast_type_traits::ASTNodeKind SourceKind = getSupportedKind();
return SourceKind.isSame(
ast_type_traits::ASTNodeKind::getFromNodeKind<Type>()) ||
SourceKind.isSame(
@ -418,16 +469,15 @@ Matcher<QualType>::canConstructFrom(const DynTypedMatcher &Other) {
}
template <>
inline Matcher<QualType>
Matcher<QualType>::constructFrom(const DynTypedMatcher &Other) {
assert(canConstructFrom(Other));
ast_type_traits::ASTNodeKind SourceKind = Other.getSupportedKind();
inline Matcher<QualType> DynTypedMatcher::convertTo<QualType>() const {
assert(canConvertTo<QualType>());
const ast_type_traits::ASTNodeKind SourceKind = getSupportedKind();
if (SourceKind.isSame(
ast_type_traits::ASTNodeKind::getFromNodeKind<Type>())) {
// We support implicit conversion from Matcher<Type> to Matcher<QualType>
return Matcher<Type>::constructFrom(Other);
return unconditionalConvertTo<Type>();
}
return makeMatcher(new WrappedMatcher(Other));
return unconditionalConvertTo<QualType>();
}
/// \brief Finds the first node in a range that matches the given matcher.
@ -973,16 +1023,6 @@ public:
Matcher<T> bind(StringRef ID) const {
return Matcher<T>(new IdMatcher<T>(ID, *this));
}
/// \brief Makes a copy of this matcher object.
virtual BindableMatcher<T>* clone() const {
return new BindableMatcher<T>(*this);
}
/// \brief Bind the specified \c ID to the matcher.
virtual Matcher<T>* tryBind(StringRef ID) const {
return new Matcher<T>(bind(ID));
}
};
/// \brief Matches nodes of type T that have child nodes of type ChildT for
@ -1075,8 +1115,7 @@ private:
/// matchers as an array of DynTypedMatcher.
typedef bool (*VariadicOperatorFunction)(
const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<const DynTypedMatcher *> InnerMatchers);
BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers);
/// \brief \c MatcherInterface<T> implementation for an variadic operator.
template <typename T>
@ -1086,14 +1125,10 @@ public:
ArrayRef<const Matcher<T> *> InputMatchers)
: Func(Func) {
for (size_t i = 0, e = InputMatchers.size(); i != e; ++i) {
InnerMatchers.push_back(new Matcher<T>(*InputMatchers[i]));
InnerMatchers.push_back(*InputMatchers[i]);
}
}
~VariadicOperatorMatcherInterface() {
llvm::DeleteContainerPointers(InnerMatchers);
}
virtual bool matches(const T &Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return Func(ast_type_traits::DynTypedNode::create(Node), Finder, Builder,
@ -1102,7 +1137,7 @@ public:
private:
const VariadicOperatorFunction Func;
std::vector<const DynTypedMatcher *> InnerMatchers;
std::vector<DynTypedMatcher> InnerMatchers;
};
/// \brief "No argument" placeholder to use as template paratemers.
@ -1196,24 +1231,24 @@ struct VariadicOperatorMatcherFunc {
/// @}
/// \brief Matches nodes for which all provided matchers match.
bool
AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
ArrayRef<const DynTypedMatcher *> InnerMatchers);
bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers);
/// \brief Matches nodes for which at least one of the provided matchers
/// matches, but doesn't stop at the first match.
bool
EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
ArrayRef<const DynTypedMatcher *> InnerMatchers);
bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers);
/// \brief Matches nodes for which at least one of the provided matchers
/// matches.
bool
AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
ArrayRef<const DynTypedMatcher *> InnerMatchers);
bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers);
/// \brief Creates a Matcher<T> that matches if all inner matchers match.
template<typename T>
@ -1232,8 +1267,8 @@ BindableMatcher<T> makeAllOfComposite(
template<typename T, typename InnerT>
BindableMatcher<T> makeDynCastAllOfComposite(
ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
return BindableMatcher<T>(
Matcher<T>::constructFromUnsafe(makeAllOfComposite(InnerMatchers)));
return BindableMatcher<T>(DynTypedMatcher(makeAllOfComposite(InnerMatchers))
.unconditionalConvertTo<T>());
}
/// \brief Matches nodes of type T that have at least one descendant node of

View File

@ -37,6 +37,7 @@
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
namespace clang {
@ -92,11 +93,12 @@ public:
///
/// \param MatcherCode The matcher expression to parse.
///
/// \return The matcher object constructed, or NULL if an error occurred.
// In that case, \c Error will contain a description of the error.
/// \return The matcher object constructed, or an empty Optional if an error
/// occurred.
/// In that case, \c Error will contain a description of the error.
/// The caller takes ownership of the DynTypedMatcher object returned.
static DynTypedMatcher *parseMatcherExpression(StringRef MatcherCode,
Diagnostics *Error);
static llvm::Optional<DynTypedMatcher>
parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error);
/// \brief Parse a matcher expression.
///
@ -104,13 +106,12 @@ public:
///
/// \param S The Sema instance that will help the parser
/// construct the matchers.
/// \return The matcher object constructed by the processor, or NULL
/// if an error occurred. In that case, \c Error will contain a
/// \return The matcher object constructed by the processor, or an empty
/// Optional if an error occurred. In that case, \c Error will contain a
/// description of the error.
/// The caller takes ownership of the DynTypedMatcher object returned.
static DynTypedMatcher *parseMatcherExpression(StringRef MatcherCode,
Sema *S,
Diagnostics *Error);
static llvm::Optional<DynTypedMatcher>
parseMatcherExpression(StringRef MatcherCode, Sema *S, Diagnostics *Error);
/// \brief Parse an expression, creating matchers from the registry.
///

View File

@ -22,6 +22,7 @@
#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"
@ -62,7 +63,7 @@ class VariantMatcher {
class Payload : public RefCountedBaseVPTR {
public:
virtual ~Payload();
virtual bool getSingleMatcher(const DynTypedMatcher *&Out) const = 0;
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const = 0;
virtual std::string getTypeAsString() const = 0;
virtual void makeTypedMatcher(MatcherOps &Ops) const = 0;
};
@ -77,8 +78,7 @@ public:
/// \brief Clones the provided matchers.
///
/// They should be the result of a polymorphic matcher.
static VariantMatcher
PolymorphicMatcher(ArrayRef<const DynTypedMatcher *> Matchers);
static VariantMatcher PolymorphicMatcher(ArrayRef<DynTypedMatcher> Matchers);
/// \brief Creates a 'variadic' operator matcher.
///
@ -95,10 +95,10 @@ public:
/// \brief Return a single matcher, if there is no ambiguity.
///
/// \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;
/// \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<DynTypedMatcher> getSingleMatcher() const;
/// \brief Determines if the contained matcher can be converted to
/// \c Matcher<T>.
@ -146,11 +146,11 @@ private:
typedef ast_matchers::internal::Matcher<T> MatcherT;
virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const {
return MatcherT::canConstructFrom(Matcher);
return Matcher.canConvertTo<T>();
}
virtual void constructFrom(const DynTypedMatcher& Matcher) {
Out.reset(new MatcherT(MatcherT::constructFrom(Matcher)));
Out.reset(new MatcherT(Matcher.convertTo<T>()));
}
virtual void constructVariadicOperator(
@ -173,7 +173,9 @@ private:
new ast_matchers::internal::VariadicOperatorMatcherInterface<T>(
Func, ArrayRef<const MatcherT *>(InnerArgs, NumArgs))));
}
std::for_each(InnerArgs, InnerArgs + NumArgs, llvm::deleter<MatcherT>);
for (size_t i = 0; i != NumArgs; ++i) {
delete InnerArgs[i];
}
delete[] InnerArgs;
}

View File

@ -295,25 +295,26 @@ private:
class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
public ASTMatchFinder {
public:
MatchASTVisitor(std::vector<std::pair<const internal::DynTypedMatcher*,
MatchCallback*> > *MatcherCallbackPairs)
: MatcherCallbackPairs(MatcherCallbackPairs),
ActiveASTContext(NULL) {
}
MatchASTVisitor(
std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > *
MatcherCallbackPairs)
: MatcherCallbackPairs(MatcherCallbackPairs), ActiveASTContext(NULL) {}
void onStartOfTranslationUnit() {
for (std::vector<std::pair<const internal::DynTypedMatcher*,
MatchCallback*> >::const_iterator
I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
for (std::vector<std::pair<internal::DynTypedMatcher,
MatchCallback *> >::const_iterator
I = MatcherCallbackPairs->begin(),
E = MatcherCallbackPairs->end();
I != E; ++I) {
I->second->onStartOfTranslationUnit();
}
}
void onEndOfTranslationUnit() {
for (std::vector<std::pair<const internal::DynTypedMatcher*,
MatchCallback*> >::const_iterator
I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
for (std::vector<std::pair<internal::DynTypedMatcher,
MatchCallback *> >::const_iterator
I = MatcherCallbackPairs->begin(),
E = MatcherCallbackPairs->end();
I != E; ++I) {
I->second->onEndOfTranslationUnit();
}
@ -450,12 +451,13 @@ public:
// Matches all registered matchers on the given node and calls the
// result callback for every node that matches.
void match(const ast_type_traits::DynTypedNode& Node) {
for (std::vector<std::pair<const internal::DynTypedMatcher*,
MatchCallback*> >::const_iterator
I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
for (std::vector<std::pair<internal::DynTypedMatcher,
MatchCallback *> >::const_iterator
I = MatcherCallbackPairs->begin(),
E = MatcherCallbackPairs->end();
I != E; ++I) {
BoundNodesTreeBuilder Builder;
if (I->first->matches(Node, this, &Builder)) {
if (I->first.matches(Node, this, &Builder)) {
MatchVisitor Visitor(ActiveASTContext, I->second);
Builder.visitMatches(&Visitor);
}
@ -603,8 +605,8 @@ private:
return false;
}
std::vector<std::pair<const internal::DynTypedMatcher*,
MatchCallback*> > *const MatcherCallbackPairs;
std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > *const
MatcherCallbackPairs;
ASTContext *ActiveASTContext;
// Maps a canonical type to its TypedefDecls.
@ -743,11 +745,10 @@ bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
class MatchASTConsumer : public ASTConsumer {
public:
MatchASTConsumer(
std::vector<std::pair<const internal::DynTypedMatcher*,
MatchCallback*> > *MatcherCallbackPairs,
MatchFinder::ParsingDoneTestCallback *ParsingDone)
: Visitor(MatcherCallbackPairs),
ParsingDone(ParsingDone) {}
std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > *
MatcherCallbackPairs,
MatchFinder::ParsingDoneTestCallback *ParsingDone)
: Visitor(MatcherCallbackPairs), ParsingDone(ParsingDone) {}
private:
virtual void HandleTranslationUnit(ASTContext &Context) {
@ -778,49 +779,36 @@ MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
MatchFinder::MatchFinder() : ParsingDone(NULL) {}
MatchFinder::~MatchFinder() {
for (std::vector<std::pair<const internal::DynTypedMatcher*,
MatchCallback*> >::const_iterator
It = MatcherCallbackPairs.begin(), End = MatcherCallbackPairs.end();
It != End; ++It) {
delete It->first;
}
}
MatchFinder::~MatchFinder() {}
void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
MatchCallback *Action) {
MatcherCallbackPairs.push_back(std::make_pair(
new internal::Matcher<Decl>(NodeMatch), Action));
MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
}
void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
MatchCallback *Action) {
MatcherCallbackPairs.push_back(std::make_pair(
new internal::Matcher<QualType>(NodeMatch), Action));
MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
}
void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
MatchCallback *Action) {
MatcherCallbackPairs.push_back(std::make_pair(
new internal::Matcher<Stmt>(NodeMatch), Action));
MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
}
void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
MatchCallback *Action) {
MatcherCallbackPairs.push_back(std::make_pair(
new NestedNameSpecifierMatcher(NodeMatch), Action));
MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
}
void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
MatchCallback *Action) {
MatcherCallbackPairs.push_back(std::make_pair(
new NestedNameSpecifierLocMatcher(NodeMatch), Action));
MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
}
void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch,
MatchCallback *Action) {
MatcherCallbackPairs.push_back(std::make_pair(
new TypeLocMatcher(NodeMatch), Action));
MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
}
ASTConsumer *MatchFinder::newASTConsumer() {

View File

@ -26,25 +26,23 @@ void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
}
}
DynTypedMatcher::MatcherStorage::~MatcherStorage() {}
void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
for (unsigned i = 0, e = Other.Bindings.size(); i != e; ++i) {
Bindings.push_back(Other.Bindings[i]);
}
}
DynTypedMatcher::~DynTypedMatcher() {}
DynTypedMatcher *DynTypedMatcher::tryBind(StringRef ID) const { return NULL; }
bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<const DynTypedMatcher *> InnerMatchers) {
ArrayRef<DynTypedMatcher> InnerMatchers) {
// allOf leads to one matcher for each alternative in the first
// matcher combined with each alternative in the second matcher.
// Thus, we can reuse the same Builder.
for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
if (!InnerMatchers[i]->matches(DynNode, Finder, Builder))
if (!InnerMatchers[i].matches(DynNode, Finder, Builder))
return false;
}
return true;
@ -53,12 +51,12 @@ bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<const DynTypedMatcher *> InnerMatchers) {
ArrayRef<DynTypedMatcher> InnerMatchers) {
BoundNodesTreeBuilder Result;
bool Matched = false;
for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
BoundNodesTreeBuilder BuilderInner(*Builder);
if (InnerMatchers[i]->matches(DynNode, Finder, &BuilderInner)) {
if (InnerMatchers[i].matches(DynNode, Finder, &BuilderInner)) {
Matched = true;
Result.addMatch(BuilderInner);
}
@ -70,10 +68,10 @@ bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<const DynTypedMatcher *> InnerMatchers) {
ArrayRef<DynTypedMatcher> InnerMatchers) {
for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
BoundNodesTreeBuilder Result = *Builder;
if (InnerMatchers[i]->matches(DynNode, Finder, &Result)) {
if (InnerMatchers[i].matches(DynNode, Finder, &Result)) {
*Builder = Result;
return true;
}

View File

@ -167,15 +167,13 @@ private:
/// out of the polymorphic object.
template <class PolyMatcher>
static void mergePolyMatchers(const PolyMatcher &Poly,
std::vector<const DynTypedMatcher *> &Out,
std::vector<DynTypedMatcher> &Out,
ast_matchers::internal::EmptyTypeList) {}
template <class PolyMatcher, class TypeList>
static void mergePolyMatchers(const PolyMatcher &Poly,
std::vector<const DynTypedMatcher *> &Out,
TypeList) {
Out.push_back(ast_matchers::internal::Matcher<typename TypeList::head>(Poly)
.clone());
std::vector<DynTypedMatcher> &Out, TypeList) {
Out.push_back(ast_matchers::internal::Matcher<typename TypeList::head>(Poly));
mergePolyMatchers(Poly, Out, typename TypeList::tail());
}
@ -193,10 +191,9 @@ template <typename T>
static VariantMatcher outvalueToVariantMatcher(const T &PolyMatcher,
typename T::ReturnTypes * =
NULL) {
std::vector<const DynTypedMatcher *> Matchers;
std::vector<DynTypedMatcher> Matchers;
mergePolyMatchers(PolyMatcher, Matchers, typename T::ReturnTypes());
VariantMatcher Out = VariantMatcher::PolymorphicMatcher(Matchers);
llvm::DeleteContainerPointers(Matchers);
return Out;
}

View File

@ -390,29 +390,29 @@ bool Parser::parseExpression(StringRef Code, Sema *S,
return true;
}
DynTypedMatcher *Parser::parseMatcherExpression(StringRef Code,
Diagnostics *Error) {
llvm::Optional<DynTypedMatcher>
Parser::parseMatcherExpression(StringRef Code, Diagnostics *Error) {
RegistrySema S;
return parseMatcherExpression(Code, &S, Error);
}
DynTypedMatcher *Parser::parseMatcherExpression(StringRef Code,
Parser::Sema *S,
Diagnostics *Error) {
llvm::Optional<DynTypedMatcher>
Parser::parseMatcherExpression(StringRef Code, Parser::Sema *S,
Diagnostics *Error) {
VariantValue Value;
if (!parseExpression(Code, S, &Value, Error))
return NULL;
return llvm::Optional<DynTypedMatcher>();
if (!Value.isMatcher()) {
Error->addError(SourceRange(), Error->ET_ParserNotAMatcher);
return NULL;
return llvm::Optional<DynTypedMatcher>();
}
const DynTypedMatcher *Result;
if (!Value.getMatcher().getSingleMatcher(Result)) {
llvm::Optional<DynTypedMatcher> Result =
Value.getMatcher().getSingleMatcher();
if (!Result.hasValue()) {
Error->addError(SourceRange(), Error->ET_ParserOverloadedType)
<< Value.getTypeAsString();
return NULL;
}
return Result->clone();
return Result;
}
} // namespace dynamic

View File

@ -329,10 +329,10 @@ VariantMatcher Registry::constructBoundMatcher(StringRef MatcherName,
VariantMatcher Out = constructMatcher(MatcherName, NameRange, Args, Error);
if (Out.isNull()) return Out;
const DynTypedMatcher *Result;
if (Out.getSingleMatcher(Result)) {
OwningPtr<DynTypedMatcher> Bound(Result->tryBind(BindID));
if (Bound) {
llvm::Optional<DynTypedMatcher> Result = Out.getSingleMatcher();
if (Result.hasValue()) {
llvm::Optional<DynTypedMatcher> Bound = Result->tryBind(BindID);
if (Bound.hasValue()) {
return VariantMatcher::SingleMatcher(*Bound);
}
}

View File

@ -26,44 +26,37 @@ VariantMatcher::Payload::~Payload() {}
class VariantMatcher::SinglePayload : public VariantMatcher::Payload {
public:
SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher.clone()) {}
SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {}
virtual bool getSingleMatcher(const DynTypedMatcher *&Out) const {
Out = Matcher.get();
return true;
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
return Matcher;
}
virtual std::string getTypeAsString() const {
return (Twine("Matcher<") + Matcher->getSupportedKind().asStringRef() + ">")
return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">")
.str();
}
virtual void makeTypedMatcher(MatcherOps &Ops) const {
if (Ops.canConstructFrom(*Matcher))
Ops.constructFrom(*Matcher);
if (Ops.canConstructFrom(Matcher))
Ops.constructFrom(Matcher);
}
private:
OwningPtr<const DynTypedMatcher> Matcher;
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());
}
}
PolymorphicPayload(ArrayRef<DynTypedMatcher> MatchersIn)
: Matchers(MatchersIn) {}
virtual ~PolymorphicPayload() {
llvm::DeleteContainerPointers(Matchers);
}
virtual ~PolymorphicPayload() {}
virtual bool getSingleMatcher(const DynTypedMatcher *&Out) const {
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
if (Matchers.size() != 1)
return false;
Out = Matchers[0];
return true;
return llvm::Optional<DynTypedMatcher>();
return Matchers[0];
}
virtual std::string getTypeAsString() const {
@ -71,7 +64,7 @@ public:
for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
if (i != 0)
Inner += "|";
Inner += Matchers[i]->getSupportedKind().asStringRef();
Inner += Matchers[i].getSupportedKind().asStringRef();
}
return (Twine("Matcher<") + Inner + ">").str();
}
@ -79,17 +72,17 @@ public:
virtual void makeTypedMatcher(MatcherOps &Ops) const {
const DynTypedMatcher *Found = NULL;
for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
if (Ops.canConstructFrom(*Matchers[i])) {
if (Ops.canConstructFrom(Matchers[i])) {
if (Found)
return;
Found = Matchers[i];
Found = &Matchers[i];
}
}
if (Found)
Ops.constructFrom(*Found);
}
std::vector<const DynTypedMatcher *> Matchers;
const std::vector<DynTypedMatcher> Matchers;
};
class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload {
@ -98,8 +91,8 @@ public:
ArrayRef<VariantMatcher> Args)
: Func(Func), Args(Args) {}
virtual bool getSingleMatcher(const DynTypedMatcher *&Out) const {
return false;
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
return llvm::Optional<DynTypedMatcher>();
}
virtual std::string getTypeAsString() const {
@ -128,7 +121,7 @@ VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) {
}
VariantMatcher
VariantMatcher::PolymorphicMatcher(ArrayRef<const DynTypedMatcher *> Matchers) {
VariantMatcher::PolymorphicMatcher(ArrayRef<DynTypedMatcher> Matchers) {
return VariantMatcher(new PolymorphicPayload(Matchers));
}
@ -138,9 +131,8 @@ VariantMatcher VariantMatcher::VariadicOperatorMatcher(
return VariantMatcher(new VariadicOpPayload(Func, Args));
}
bool VariantMatcher::getSingleMatcher(const DynTypedMatcher *&Out) const {
if (Value) return Value->getSingleMatcher(Out);
return false;
llvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const {
return Value ? Value->getSingleMatcher() : llvm::Optional<DynTypedMatcher>();
}
void VariantMatcher::reset() { Value.reset(); }

View File

@ -21,51 +21,14 @@ namespace ast_matchers {
namespace dynamic {
namespace {
class DummyDynTypedMatcher : public DynTypedMatcher {
public:
DummyDynTypedMatcher(uint64_t ID) : ID(ID) {}
DummyDynTypedMatcher(uint64_t ID, StringRef BoundID)
: ID(ID), BoundID(BoundID) {}
typedef ast_matchers::internal::ASTMatchFinder ASTMatchFinder;
typedef ast_matchers::internal::BoundNodesTreeBuilder BoundNodesTreeBuilder;
virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return false;
}
/// \brief Makes a copy of this matcher object.
virtual DynTypedMatcher *clone() const {
return new DummyDynTypedMatcher(*this);
}
/// \brief Returns a unique ID for the matcher.
virtual uint64_t getID() const { return ID; }
virtual DynTypedMatcher* tryBind(StringRef BoundID) const {
return new DummyDynTypedMatcher(ID, BoundID);
}
StringRef boundID() const { return BoundID; }
virtual ast_type_traits::ASTNodeKind getSupportedKind() const {
return ast_type_traits::ASTNodeKind();
}
private:
uint64_t ID;
std::string BoundID;
};
class MockSema : public Parser::Sema {
public:
virtual ~MockSema() {}
uint64_t expectMatcher(StringRef MatcherName) {
uint64_t ID = ExpectedMatchers.size() + 1;
ExpectedMatchers[MatcherName] = ID;
return ID;
ast_matchers::internal::Matcher<Stmt> M = stmt();
ExpectedMatchers.insert(std::make_pair(MatcherName, M));
return M.getID();
}
void parse(StringRef Code) {
@ -83,9 +46,8 @@ public:
Diagnostics *Error) {
MatcherInfo ToStore = { MatcherName, NameRange, Args, BindID };
Matchers.push_back(ToStore);
DummyDynTypedMatcher Matcher(ExpectedMatchers[MatcherName]);
OwningPtr<DynTypedMatcher> Out(Matcher.tryBind(BindID));
return VariantMatcher::SingleMatcher(*Out);
return VariantMatcher::SingleMatcher(
ExpectedMatchers.find(MatcherName)->second);
}
struct MatcherInfo {
@ -98,7 +60,8 @@ public:
std::vector<std::string> Errors;
std::vector<VariantValue> Values;
std::vector<MatcherInfo> Matchers;
llvm::StringMap<uint64_t> ExpectedMatchers;
std::map<std::string, ast_matchers::internal::Matcher<Stmt> >
ExpectedMatchers;
};
TEST(ParserTest, ParseUnsigned) {
@ -137,10 +100,11 @@ bool matchesRange(const SourceRange &Range, unsigned StartLine,
Range.Start.Column == StartColumn && Range.End.Column == EndColumn;
}
const DynTypedMatcher *getSingleMatcher(const VariantValue &Value) {
const DynTypedMatcher *Out;
EXPECT_TRUE(Value.getMatcher().getSingleMatcher(Out));
return Out;
llvm::Optional<DynTypedMatcher> getSingleMatcher(const VariantValue &Value) {
llvm::Optional<DynTypedMatcher> Result =
Value.getMatcher().getSingleMatcher();
EXPECT_TRUE(Result.hasValue());
return Result;
}
TEST(ParserTest, ParseMatcher) {
@ -155,8 +119,6 @@ TEST(ParserTest, ParseMatcher) {
EXPECT_EQ(1ULL, Sema.Values.size());
EXPECT_EQ(ExpectedFoo, getSingleMatcher(Sema.Values[0])->getID());
EXPECT_EQ("Yo!", static_cast<const DummyDynTypedMatcher *>(
getSingleMatcher(Sema.Values[0]))->boundID());
EXPECT_EQ(3ULL, Sema.Matchers.size());
const MockSema::MatcherInfo Bar = Sema.Matchers[0];
@ -184,27 +146,28 @@ using ast_matchers::internal::Matcher;
TEST(ParserTest, FullParserTest) {
Diagnostics Error;
OwningPtr<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression(
llvm::Optional<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression(
"varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()),"
" hasOperatorName(\"+\"))))",
&Error));
EXPECT_EQ("", Error.toStringFull());
Matcher<Decl> M = Matcher<Decl>::constructFrom(*VarDecl);
Matcher<Decl> M = VarDecl->unconditionalConvertTo<Decl>();
EXPECT_TRUE(matches("int x = 1 + false;", M));
EXPECT_FALSE(matches("int x = true + 1;", M));
EXPECT_FALSE(matches("int x = 1 - false;", M));
EXPECT_FALSE(matches("int x = true - 1;", M));
OwningPtr<DynTypedMatcher> HasParameter(Parser::parseMatcherExpression(
llvm::Optional<DynTypedMatcher> HasParameter(Parser::parseMatcherExpression(
"functionDecl(hasParameter(1, hasName(\"x\")))", &Error));
EXPECT_EQ("", Error.toStringFull());
M = Matcher<Decl>::constructFrom(*HasParameter);
M = HasParameter->unconditionalConvertTo<Decl>();
EXPECT_TRUE(matches("void f(int a, int x);", M));
EXPECT_FALSE(matches("void f(int x, int a);", M));
EXPECT_TRUE(Parser::parseMatcherExpression(
"hasInitializer(\n binaryOperator(hasLHS(\"A\")))", &Error) == NULL);
EXPECT_TRUE(!Parser::parseMatcherExpression(
"hasInitializer(\n binaryOperator(hasLHS(\"A\")))",
&Error).hasValue());
EXPECT_EQ("1:1: Error parsing argument 1 for matcher hasInitializer.\n"
"2:5: Error parsing argument 1 for matcher binaryOperator.\n"
"2:20: Error building matcher hasLHS.\n"