public:
virtual ~MatcherOps();
virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const = 0;
+ virtual void constructFrom(const DynTypedMatcher &Matcher) = 0;
+ virtual void constructVariadicOperator(
+ ast_matchers::internal::VariadicOperatorFunction Func,
+ ArrayRef<VariantMatcher> InnerMatchers) = 0;
};
/// \brief Payload interface to be specialized by each matcher type.
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;
+ virtual void makeTypedMatcher(MatcherOps &Ops) const = 0;
};
public:
static VariantMatcher
PolymorphicMatcher(ArrayRef<const DynTypedMatcher *> Matchers);
+ /// \brief Creates a 'variadic' operator matcher.
+ ///
+ /// It will bind to the appropriate type on getTypedMatcher<T>().
+ static VariantMatcher VariadicOperatorMatcher(
+ ast_matchers::internal::VariadicOperatorFunction Func,
+ ArrayRef<VariantMatcher> Args);
+
/// \brief Makes the matcher the "null" matcher.
void reset();
/// that can, the result would be ambiguous and false is returned.
template <class T>
bool hasTypedMatcher() const {
- if (Value) return Value->hasTypedMatcher(TypedMatcherOps<T>());
- return false;
+ TypedMatcherOps<T> Ops;
+ if (Value) Value->makeTypedMatcher(Ops);
+ return Ops.hasMatcher();
}
/// \brief Return this matcher as a \c Matcher<T>.
/// 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(
- *Value->getTypedMatcher(TypedMatcherOps<T>()));
+ TypedMatcherOps<T> Ops;
+ Value->makeTypedMatcher(Ops);
+ assert(Ops.hasMatcher() && "hasTypedMatcher<T>() == false");
+ return Ops.matcher();
}
/// \brief String representation of the type of the value.
class SinglePayload;
class PolymorphicPayload;
+ class VariadicOpPayload;
template <typename T>
class TypedMatcherOps : public MatcherOps {
public:
+ typedef ast_matchers::internal::Matcher<T> MatcherT;
+
virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const {
- return ast_matchers::internal::Matcher<T>::canConstructFrom(Matcher);
+ return MatcherT::canConstructFrom(Matcher);
+ }
+
+ virtual void constructFrom(const DynTypedMatcher& Matcher) {
+ Out.reset(new MatcherT(MatcherT::constructFrom(Matcher)));
}
+
+ virtual void constructVariadicOperator(
+ ast_matchers::internal::VariadicOperatorFunction Func,
+ ArrayRef<VariantMatcher> InnerMatchers) {
+ const size_t NumArgs = InnerMatchers.size();
+ MatcherT **InnerArgs = new MatcherT *[NumArgs]();
+ bool HasError = false;
+ for (size_t i = 0; i != NumArgs; ++i) {
+ // Abort if any of the inner matchers can't be converted to
+ // Matcher<T>.
+ if (!InnerMatchers[i].hasTypedMatcher<T>()) {
+ HasError = true;
+ break;
+ }
+ InnerArgs[i] = new MatcherT(InnerMatchers[i].getTypedMatcher<T>());
+ }
+ if (!HasError) {
+ Out.reset(new MatcherT(
+ new ast_matchers::internal::VariadicOperatorMatcherInterface<T>(
+ Func, ArrayRef<const MatcherT *>(InnerArgs, NumArgs))));
+ }
+ std::for_each(InnerArgs, InnerArgs + NumArgs, llvm::deleter<MatcherT>);
+ delete[] InnerArgs;
+ }
+
+ bool hasMatcher() const { return Out.get() != NULL; }
+ const MatcherT &matcher() const { return *Out; }
+
+ private:
+ OwningPtr<MatcherT> Out;
};
IntrusiveRefCntPtr<const Payload> Value;
std::vector<MatcherCreateCallback *> Overloads;
};
+/// \brief Variadic operator marshaller function.
+class VariadicOperatorMatcherCreateCallback : public MatcherCreateCallback {
+public:
+ typedef ast_matchers::internal::VariadicOperatorFunction VarFunc;
+ VariadicOperatorMatcherCreateCallback(VarFunc Func, StringRef MatcherName)
+ : Func(Func), MatcherName(MatcherName) {}
+
+ virtual VariantMatcher run(const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const {
+ std::vector<VariantMatcher> InnerArgs;
+ for (size_t i = 0, e = Args.size(); i != e; ++i) {
+ const ParserValue &Arg = Args[i];
+ const VariantValue &Value = Arg.Value;
+ if (!Value.isMatcher()) {
+ Error->addError(Arg.Range, Error->ET_RegistryWrongArgType)
+ << (i + 1) << "Matcher<>" << Value.getTypeAsString();
+ return VariantMatcher();
+ }
+ InnerArgs.push_back(Value.getMatcher());
+ }
+ return VariantMatcher::VariadicOperatorMatcher(Func, InnerArgs);
+ }
+
+private:
+ const VarFunc Func;
+ const StringRef MatcherName;
+};
+
+
/// Helper functions to select the appropriate marshaller functions.
/// They detect the number of arguments, arguments types and return type.
collect(typename FromTypeList::tail());
}
+/// \brief Variadic operator overload.
+MatcherCreateCallback *makeMatcherAutoMarshall(
+ ast_matchers::internal::VariadicOperatorMatcherFunc Func,
+ StringRef MatcherName) {
+ return new VariadicOperatorMatcherCreateCallback(Func.Func, MatcherName);
+}
+
} // namespace internal
} // namespace dynamic
} // namespace ast_matchers
//
// Polymorphic + argument overload:
// unless
- // eachOf
- // anyOf
- // allOf
// findAll
//
// Other:
REGISTER_MATCHER(accessSpecDecl);
REGISTER_MATCHER(alignOfExpr);
+ REGISTER_MATCHER(allOf);
+ REGISTER_MATCHER(anyOf);
REGISTER_MATCHER(anything);
REGISTER_MATCHER(argumentCountIs);
REGISTER_MATCHER(arraySubscriptExpr);
REGISTER_MATCHER(destructorDecl);
REGISTER_MATCHER(doStmt);
REGISTER_MATCHER(dynamicCastExpr);
+ REGISTER_MATCHER(eachOf);
REGISTER_MATCHER(elaboratedType);
REGISTER_MATCHER(enumConstantDecl);
REGISTER_MATCHER(enumDecl);
.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();
+ virtual void makeTypedMatcher(MatcherOps &Ops) const {
+ if (Ops.canConstructFrom(*Matcher))
+ Ops.constructFrom(*Matcher);
}
private:
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;
+ 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 (Found) return NULL;
+ if (Found)
+ return;
Found = Matchers[i];
}
}
- return Found;
+ if (Found)
+ Ops.constructFrom(*Found);
}
-private:
std::vector<const DynTypedMatcher *> Matchers;
};
+class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload {
+public:
+ VariadicOpPayload(ast_matchers::internal::VariadicOperatorFunction Func,
+ ArrayRef<VariantMatcher> Args)
+ : Func(Func), Args(Args) {}
+
+ virtual bool getSingleMatcher(const DynTypedMatcher *&Out) const {
+ return false;
+ }
+
+ virtual std::string getTypeAsString() const {
+ std::string Inner;
+ for (size_t i = 0, e = Args.size(); i != e; ++i) {
+ if (i != 0)
+ Inner += "&";
+ Inner += Args[i].getTypeAsString();
+ }
+ return Inner;
+ }
+
+ virtual void makeTypedMatcher(MatcherOps &Ops) const {
+ Ops.constructVariadicOperator(Func, Args);
+ }
+
+private:
+ const ast_matchers::internal::VariadicOperatorFunction Func;
+ const std::vector<VariantMatcher> Args;
+};
+
VariantMatcher::VariantMatcher() {}
VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) {
return VariantMatcher(new PolymorphicPayload(Matchers));
}
+VariantMatcher VariantMatcher::VariadicOperatorMatcher(
+ ast_matchers::internal::VariadicOperatorFunction Func,
+ ArrayRef<VariantMatcher> Args) {
+ return VariantMatcher(new VariadicOpPayload(Func, Args));
+}
+
bool VariantMatcher::getSingleMatcher(const DynTypedMatcher *&Out) const {
if (Value) return Value->getSingleMatcher(Out);
return false;
Range.Start.Column == StartColumn && Range.End.Column == EndColumn;
}
-const DynTypedMatcher *getSingleMatcher(const VariantValue &value) {
+const DynTypedMatcher *getSingleMatcher(const VariantValue &Value) {
const DynTypedMatcher *Out;
- EXPECT_TRUE(value.getMatcher().getSingleMatcher(Out));
+ EXPECT_TRUE(Value.getMatcher().getSingleMatcher(Out));
return Out;
}
EXPECT_FALSE(matches("void foo() { if (true) return; }", S));
}
+TEST_F(RegistryTest, VariadicOp) {
+ Matcher<Decl> D = constructMatcher(
+ "anyOf", constructMatcher("recordDecl"),
+ constructMatcher("namedDecl",
+ constructMatcher("hasName", std::string("foo"))))
+ .getTypedMatcher<Decl>();
+
+ EXPECT_TRUE(matches("void foo(){}", D));
+ EXPECT_TRUE(matches("struct Foo{};", D));
+ EXPECT_FALSE(matches("int i = 0;", D));
+
+ D = constructMatcher(
+ "allOf", constructMatcher("recordDecl"),
+ constructMatcher(
+ "namedDecl",
+ constructMatcher("anyOf",
+ constructMatcher("hasName", std::string("Foo")),
+ constructMatcher("hasName", std::string("Bar")))))
+ .getTypedMatcher<Decl>();
+
+ EXPECT_FALSE(matches("void foo(){}", D));
+ EXPECT_TRUE(matches("struct Foo{};", D));
+ EXPECT_FALSE(matches("int i = 0;", D));
+ EXPECT_TRUE(matches("class Bar{};", D));
+ EXPECT_FALSE(matches("class OtherBar{};", D));
+}
+
TEST_F(RegistryTest, Errors) {
// Incorrect argument count.
OwningPtr<Diagnostics> Error(new Diagnostics());
EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
"(Actual = Matcher<FunctionDecl>)",
Error->toString());
+
+ // Bad argument type with variadic.
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher("anyOf", std::string(), Error.get()).isNull());
+ EXPECT_EQ(
+ "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)",
+ Error->toString());
+ Error.reset(new Diagnostics());
+ EXPECT_TRUE(constructMatcher(
+ "recordDecl",
+ constructMatcher("allOf",
+ constructMatcher("isDerivedFrom", std::string("FOO")),
+ constructMatcher("isArrow")),
+ Error.get()).isNull());
+ EXPECT_EQ("Incorrect type for arg 1. "
+ "(Expected = Matcher<CXXRecordDecl>) != "
+ "(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)",
+ Error->toString());
}
} // end anonymous namespace