r184429 - Enhancements for the DynTypedMatcher system.
Samuel Benzaquen
sbenza at google.com
Thu Jun 20 07:28:33 PDT 2013
Author: sbenza
Date: Thu Jun 20 09:28:32 2013
New Revision: 184429
URL: http://llvm.org/viewvc/llvm-project?rev=184429&view=rev
Log:
Enhancements for the DynTypedMatcher system.
- Added conversion routines and checks in Matcher<T> that take a DynTypedMatcher.
- Added type information on the error messages for the marshallers.
- Allows future work on Polymorphic/overloaded matchers. We should be
able to disambiguate at runtime and choose the appropriate overload.
Modified:
cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h
cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h
cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h
cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp
cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h
cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h Thu Jun 20 09:28:32 2013
@@ -136,17 +136,6 @@ public:
MatchCallback *Action);
/// @}
- /// \brief Adds a matcher to execute when running over the AST.
- ///
- /// This is similar to \c addMatcher(), but it uses the dynamic interface. It
- /// is more flexible, but the lost type information enables a caller to pass
- /// a matcher that cannot match anything.
- ///
- /// \returns \c true if the matcher is a valid top-level matcher, \c false
- /// otherwise.
- bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
- MatchCallback *Action);
-
/// \brief Creates a clang ASTConsumer that finds all matches.
clang::ASTConsumer *newASTConsumer();
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Thu Jun 20 09:28:32 2013
@@ -224,6 +224,12 @@ public:
/// \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.
@@ -261,6 +267,27 @@ 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 Matcher<T>(new WrappedMatcher(Other));
+ }
+
/// \brief Forwards the call to the underlying MatcherInterface<T> pointer.
bool matches(const T &Node,
ASTMatchFinder *Finder,
@@ -281,6 +308,11 @@ 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,
@@ -335,6 +367,23 @@ 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
@@ -345,6 +394,34 @@ inline Matcher<T> makeMatcher(MatcherInt
return Matcher<T>(Implementation);
}
+/// \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>
+ return SourceKind.isSame(
+ ast_type_traits::ASTNodeKind::getFromNodeKind<Type>()) ||
+ SourceKind.isSame(
+ ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>());
+}
+
+template <>
+inline Matcher<QualType>
+Matcher<QualType>::constructFrom(const DynTypedMatcher &Other) {
+ assert(canConstructFrom(Other));
+ ast_type_traits::ASTNodeKind SourceKind = Other.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 makeMatcher(new WrappedMatcher(Other));
+}
+
/// \brief Finds the first node in a range that matches the given matcher.
template <typename MatcherT, typename IteratorT>
bool matchesFirstInRange(const MatcherT &Matcher, IteratorT Start,
Modified: cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h Thu Jun 20 09:28:32 2013
@@ -70,44 +70,24 @@ public:
/// \brief Set the value to be \c Matcher by taking ownership of the object.
void takeMatcher(DynTypedMatcher *Matcher);
- /// \brief Specialized Matcher<T> is/get functions.
+ /// \brief Specialized Matcher<T> functions.
template <class T>
- bool isTypedMatcher() const {
- // TODO: Add some logic to test if T is actually valid for the underlying
- // type of the matcher.
- return isMatcher();
+ bool hasTypedMatcher() const {
+ return isMatcher() &&
+ ast_matchers::internal::Matcher<T>::canConstructFrom(getMatcher());
}
template <class T>
ast_matchers::internal::Matcher<T> getTypedMatcher() const {
- return ast_matchers::internal::makeMatcher(
- new DerivedTypeMatcher<T>(getMatcher()));
+ return ast_matchers::internal::Matcher<T>::constructFrom(getMatcher());
}
+ /// \brief String representation of the type of the value.
+ std::string getTypeAsString() const;
+
private:
void reset();
- /// \brief Matcher bridge between a Matcher<T> and a generic DynTypedMatcher.
- template <class T>
- class DerivedTypeMatcher :
- public ast_matchers::internal::MatcherInterface<T> {
- public:
- explicit DerivedTypeMatcher(const DynTypedMatcher &DynMatcher)
- : DynMatcher(DynMatcher.clone()) {}
- virtual ~DerivedTypeMatcher() {}
-
- typedef ast_matchers::internal::ASTMatchFinder ASTMatchFinder;
- typedef ast_matchers::internal::BoundNodesTreeBuilder BoundNodesTreeBuilder;
- bool matches(const T &Node, ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const {
- return DynMatcher->matches(ast_type_traits::DynTypedNode::create(Node),
- Finder, Builder);
- }
-
- private:
- const OwningPtr<DynTypedMatcher> DynMatcher;
- };
-
/// \brief All supported value types.
enum ValueType {
VT_Nothing,
Modified: cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp Thu Jun 20 09:28:32 2013
@@ -803,14 +803,6 @@ void MatchFinder::addMatcher(const TypeL
new TypeLocMatcher(NodeMatch), Action));
}
-bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
- MatchCallback *Action) {
- MatcherCallbackPairs.push_back(std::make_pair(NodeMatch.clone(), Action));
- // TODO: Do runtime type checking to make sure the matcher is one of the valid
- // top-level matchers.
- return true;
-}
-
ASTConsumer *MatchFinder::newASTConsumer() {
return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone);
}
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp Thu Jun 20 09:28:32 2013
@@ -36,7 +36,7 @@ StringRef ErrorTypeToString(Diagnostics:
case Diagnostics::ET_RegistryWrongArgCount:
return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
case Diagnostics::ET_RegistryWrongArgType:
- return "Incorrect type on function $0 for arg $1.";
+ return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";
case Diagnostics::ET_RegistryNotBindable:
return "Matcher does not support binding.";
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h Thu Jun 20 09:28:32 2013
@@ -42,6 +42,7 @@ template <class T> struct ArgTypeTraits<
};
template <> struct ArgTypeTraits<std::string> {
+ static StringRef asString() { return "String"; }
static bool is(const VariantValue &Value) { return Value.isString(); }
static const std::string &get(const VariantValue &Value) {
return Value.getString();
@@ -49,13 +50,21 @@ template <> struct ArgTypeTraits<std::st
};
template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > {
- static bool is(const VariantValue &Value) { return Value.isMatcher(); }
+ static std::string asString() {
+ return (Twine("Matcher<") +
+ ast_type_traits::ASTNodeKind::getFromNodeKind<T>().asStringRef() +
+ ">").str();
+ }
+ static bool is(const VariantValue &Value) {
+ return Value.hasTypedMatcher<T>();
+ }
static ast_matchers::internal::Matcher<T> get(const VariantValue &Value) {
return Value.getTypedMatcher<T>();
}
};
template <> struct ArgTypeTraits<unsigned> {
+ static std::string asString() { return "Unsigned"; }
static bool is(const VariantValue &Value) { return Value.isUnsigned(); }
static unsigned get(const VariantValue &Value) {
return Value.getUnsigned();
@@ -147,7 +156,8 @@ private:
#define CHECK_ARG_TYPE(index, type) \
if (!ArgTypeTraits<type>::is(Args[index].Value)) { \
Error->pushErrorFrame(Args[index].Range, Error->ET_RegistryWrongArgType) \
- << MatcherName << (index + 1); \
+ << (index + 1) << ArgTypeTraits<type>::asString() \
+ << Args[index].Value.getTypeAsString(); \
return NULL; \
}
@@ -201,14 +211,16 @@ DynTypedMatcher *VariadicMatcherCreateCa
bool HasError = false;
for (size_t i = 0, e = Args.size(); i != e; ++i) {
- if (!Args[i].Value.isTypedMatcher<DerivedType>()) {
- Error->pushErrorFrame(Args[i].Range, Error->ET_RegistryWrongArgType)
- << MatcherName << (i + 1);
+ typedef ArgTypeTraits<DerivedMatcherType> DerivedTraits;
+ const ParserValue &Arg = Args[i];
+ const VariantValue &Value = Arg.Value;
+ if (!DerivedTraits::is(Value)) {
+ Error->pushErrorFrame(Arg.Range, Error->ET_RegistryWrongArgType)
+ << (i + 1) << DerivedTraits::asString() << Value.getTypeAsString();
HasError = true;
break;
}
- InnerArgs[i] =
- new DerivedMatcherType(Args[i].Value.getTypedMatcher<DerivedType>());
+ InnerArgs[i] = new DerivedMatcherType(DerivedTraits::get(Value));
}
DynTypedMatcher *Out = NULL;
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp Thu Jun 20 09:28:32 2013
@@ -14,6 +14,8 @@
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "clang/Basic/LLVM.h"
+
namespace clang {
namespace ast_matchers {
namespace dynamic {
@@ -123,6 +125,18 @@ void VariantValue::takeMatcher(DynTypedM
Value.Matcher = NewValue;
}
+std::string VariantValue::getTypeAsString() const {
+ switch (Type) {
+ case VT_String: return "String";
+ case VT_Matcher:
+ return (Twine("Matcher<") + getMatcher().getSupportedKind().asStringRef() +
+ ">").str();
+ case VT_Unsigned: return "Unsigned";
+ case VT_Nothing: return "Nothing";
+ }
+ llvm_unreachable("Invalid Type");
+}
+
} // end namespace dynamic
} // end namespace ast_matchers
} // end namespace clang
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h Thu Jun 20 09:28:32 2013
@@ -84,41 +84,6 @@ testing::AssertionResult notMatches(cons
return matchesConditionally(Code, AMatcher, false, "-std=c++11");
}
-inline testing::AssertionResult
-matchesConditionallyDynamic(const std::string &Code,
- const internal::DynTypedMatcher &AMatcher,
- bool ExpectMatch, llvm::StringRef CompileArg) {
- bool Found = false;
- MatchFinder Finder;
- Finder.addDynamicMatcher(AMatcher, new VerifyMatch(0, &Found));
- OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
- // Some tests use typeof, which is a gnu extension.
- std::vector<std::string> Args(1, CompileArg);
- if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
- return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
- }
- if (!Found && ExpectMatch) {
- return testing::AssertionFailure()
- << "Could not find match in \"" << Code << "\"";
- } else if (Found && !ExpectMatch) {
- return testing::AssertionFailure()
- << "Found unexpected match in \"" << Code << "\"";
- }
- return testing::AssertionSuccess();
-}
-
-inline testing::AssertionResult
-matchesDynamic(const std::string &Code,
- const internal::DynTypedMatcher &AMatcher) {
- return matchesConditionallyDynamic(Code, AMatcher, true, "-std=c++11");
-}
-
-inline testing::AssertionResult
-notMatchesDynamic(const std::string &Code,
- const internal::DynTypedMatcher &AMatcher) {
- return matchesConditionallyDynamic(Code, AMatcher, false, "-std=c++11");
-}
-
template <typename T>
testing::AssertionResult
matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp Thu Jun 20 09:28:32 2013
@@ -49,6 +49,9 @@ public:
StringRef boundID() const { return BoundID; }
+ virtual ast_type_traits::ASTNodeKind getSupportedKind() const {
+ return ast_type_traits::ASTNodeKind();
+ }
private:
uint64_t ID;
std::string BoundID;
@@ -172,15 +175,19 @@ TEST(ParserTest, ParseMatcher) {
using ast_matchers::internal::Matcher;
TEST(ParserTest, FullParserTest) {
- OwningPtr<DynTypedMatcher> Matcher(Parser::parseMatcherExpression(
- "hasInitializer(binaryOperator(hasLHS(integerLiteral())))", NULL));
- EXPECT_TRUE(matchesDynamic("int x = 1 + false;", *Matcher));
- EXPECT_FALSE(matchesDynamic("int x = true + 1;", *Matcher));
-
- Matcher.reset(
- Parser::parseMatcherExpression("hasParameter(1, hasName(\"x\"))", NULL));
- EXPECT_TRUE(matchesDynamic("void f(int a, int x);", *Matcher));
- EXPECT_FALSE(matchesDynamic("void f(int x, int a);", *Matcher));
+ OwningPtr<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression(
+ "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()))))",
+ NULL));
+ Matcher<Decl> M = Matcher<Decl>::constructFrom(*VarDecl);
+ EXPECT_TRUE(matches("int x = 1 + false;", M));
+ EXPECT_FALSE(matches("int x = true + 1;", M));
+
+ OwningPtr<DynTypedMatcher> HasParameter(Parser::parseMatcherExpression(
+ "functionDecl(hasParameter(1, hasName(\"x\")))", NULL));
+ M = Matcher<Decl>::constructFrom(*HasParameter);
+
+ EXPECT_TRUE(matches("void f(int a, int x);", M));
+ EXPECT_FALSE(matches("void f(int x, int a);", M));
Diagnostics Error;
EXPECT_TRUE(Parser::parseMatcherExpression(
@@ -188,7 +195,8 @@ TEST(ParserTest, FullParserTest) {
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"
- "2:27: Incorrect type on function hasLHS for arg 1.",
+ "2:27: Incorrect type for arg 1. "
+ "(Expected = Matcher<Expr>) != (Actual = String)",
Error.ToStringFull());
}
Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Thu Jun 20 09:28:32 2013
@@ -20,98 +20,131 @@ namespace {
using ast_matchers::internal::Matcher;
-DynTypedMatcher *constructMatcher(StringRef MatcherName, Diagnostics *Error) {
- const std::vector<ParserValue> Args;
- return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
-}
-
-DynTypedMatcher *constructMatcher(StringRef MatcherName,
- const VariantValue &Arg1,
- Diagnostics *Error) {
- std::vector<ParserValue> Args(1);
- Args[0].Value = Arg1;
- return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
-}
-
-DynTypedMatcher *constructMatcher(StringRef MatcherName,
- const VariantValue &Arg1,
- const VariantValue &Arg2,
- Diagnostics *Error) {
- std::vector<ParserValue> Args(2);
- Args[0].Value = Arg1;
- Args[1].Value = Arg2;
- return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
-}
-
-TEST(RegistryTest, CanConstructNoArgs) {
- OwningPtr<DynTypedMatcher> IsArrowValue(constructMatcher("isArrow", NULL));
- OwningPtr<DynTypedMatcher> BoolValue(constructMatcher("boolLiteral", NULL));
+class RegistryTest : public ::testing::Test {
+public:
+ std::vector<ParserValue> Args() { return std::vector<ParserValue>(); }
+ std::vector<ParserValue> Args(const VariantValue &Arg1) {
+ std::vector<ParserValue> Out(1);
+ Out[0].Value = Arg1;
+ return Out;
+ }
+ std::vector<ParserValue> Args(const VariantValue &Arg1,
+ const VariantValue &Arg2) {
+ std::vector<ParserValue> Out(2);
+ Out[0].Value = Arg1;
+ Out[1].Value = Arg2;
+ return Out;
+ }
+
+ template <class T>
+ Matcher<T> constructMatcher(StringRef MatcherName, Diagnostics *Error) {
+ OwningPtr<DynTypedMatcher> Out(
+ Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error));
+ return Matcher<T>::constructFrom(*Out);
+ }
+
+ template <class T>
+ Matcher<T> constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
+ Diagnostics *Error) {
+ OwningPtr<DynTypedMatcher> Out(Registry::constructMatcher(
+ MatcherName, SourceRange(), Args(Arg1), Error));
+ return Matcher<T>::constructFrom(*Out);
+ }
+
+ template <class T>
+ Matcher<T> constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
+ const VariantValue &Arg2, Diagnostics *Error) {
+ OwningPtr<DynTypedMatcher> Out(Registry::constructMatcher(
+ MatcherName, SourceRange(), Args(Arg1, Arg2), Error));
+ return Matcher<T>::constructFrom(*Out);
+ }
+};
+
+TEST_F(RegistryTest, CanConstructNoArgs) {
+ Matcher<Stmt> IsArrowValue = constructMatcher<Stmt>(
+ "memberExpr", constructMatcher<MemberExpr>("isArrow", NULL), NULL);
+ Matcher<Stmt> BoolValue = constructMatcher<Stmt>("boolLiteral", NULL);
const std::string ClassSnippet = "struct Foo { int x; };\n"
"Foo *foo = new Foo;\n"
"int i = foo->x;\n";
const std::string BoolSnippet = "bool Foo = true;\n";
- EXPECT_TRUE(matchesDynamic(ClassSnippet, *IsArrowValue));
- EXPECT_TRUE(matchesDynamic(BoolSnippet, *BoolValue));
- EXPECT_FALSE(matchesDynamic(ClassSnippet, *BoolValue));
- EXPECT_FALSE(matchesDynamic(BoolSnippet, *IsArrowValue));
-}
-
-TEST(RegistryTest, ConstructWithSimpleArgs) {
- OwningPtr<DynTypedMatcher> Value(
- constructMatcher("hasName", std::string("X"), NULL));
- EXPECT_TRUE(matchesDynamic("class X {};", *Value));
- EXPECT_FALSE(matchesDynamic("int x;", *Value));
-
- Value.reset(constructMatcher("parameterCountIs", 2, NULL));
- EXPECT_TRUE(matchesDynamic("void foo(int,int);", *Value));
- EXPECT_FALSE(matchesDynamic("void foo(int);", *Value));
-}
-
-TEST(RegistryTest, ConstructWithMatcherArgs) {
- OwningPtr<DynTypedMatcher> HasInitializerSimple(
- constructMatcher("hasInitializer", stmt(), NULL));
- OwningPtr<DynTypedMatcher> HasInitializerComplex(
- constructMatcher("hasInitializer", callExpr(), NULL));
+ EXPECT_TRUE(matches(ClassSnippet, IsArrowValue));
+ EXPECT_TRUE(matches(BoolSnippet, BoolValue));
+ EXPECT_FALSE(matches(ClassSnippet, BoolValue));
+ EXPECT_FALSE(matches(BoolSnippet, IsArrowValue));
+}
+
+TEST_F(RegistryTest, ConstructWithSimpleArgs) {
+ Matcher<Decl> Value = constructMatcher<Decl>(
+ "namedDecl",
+ constructMatcher<NamedDecl>("hasName", std::string("X"), NULL), NULL);
+ EXPECT_TRUE(matches("class X {};", Value));
+ EXPECT_FALSE(matches("int x;", Value));
+
+ Value =
+ functionDecl(constructMatcher<FunctionDecl>("parameterCountIs", 2, NULL));
+ EXPECT_TRUE(matches("void foo(int,int);", Value));
+ EXPECT_FALSE(matches("void foo(int);", Value));
+}
+
+TEST_F(RegistryTest, ConstructWithMatcherArgs) {
+ Matcher<Decl> HasInitializerSimple = constructMatcher<Decl>(
+ "varDecl", constructMatcher<VarDecl>("hasInitializer", stmt(), NULL),
+ NULL);
+ Matcher<Decl> HasInitializerComplex = constructMatcher<Decl>(
+ "varDecl", constructMatcher<VarDecl>("hasInitializer", callExpr(), NULL),
+ NULL);
std::string code = "int i;";
- EXPECT_FALSE(matchesDynamic(code, *HasInitializerSimple));
- EXPECT_FALSE(matchesDynamic(code, *HasInitializerComplex));
+ EXPECT_FALSE(matches(code, HasInitializerSimple));
+ EXPECT_FALSE(matches(code, HasInitializerComplex));
code = "int i = 1;";
- EXPECT_TRUE(matchesDynamic(code, *HasInitializerSimple));
- EXPECT_FALSE(matchesDynamic(code, *HasInitializerComplex));
+ EXPECT_TRUE(matches(code, HasInitializerSimple));
+ EXPECT_FALSE(matches(code, HasInitializerComplex));
code = "int y(); int i = y();";
- EXPECT_TRUE(matchesDynamic(code, *HasInitializerSimple));
- EXPECT_TRUE(matchesDynamic(code, *HasInitializerComplex));
+ EXPECT_TRUE(matches(code, HasInitializerSimple));
+ EXPECT_TRUE(matches(code, HasInitializerComplex));
- OwningPtr<DynTypedMatcher> HasParameter(
- constructMatcher("hasParameter", 1, hasName("x"), NULL));
- EXPECT_TRUE(matchesDynamic("void f(int a, int x);", *HasParameter));
- EXPECT_FALSE(matchesDynamic("void f(int x, int a);", *HasParameter));
+ Matcher<Decl> HasParameter = functionDecl(
+ constructMatcher<FunctionDecl>("hasParameter", 1, hasName("x"), NULL));
+ EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
+ EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
}
-TEST(RegistryTest, Errors) {
+TEST_F(RegistryTest, Errors) {
// Incorrect argument count.
OwningPtr<Diagnostics> Error(new Diagnostics());
- EXPECT_TRUE(NULL == constructMatcher("hasInitializer", Error.get()));
+ EXPECT_TRUE(NULL ==
+ Registry::constructMatcher("hasInitializer", SourceRange(),
+ Args(), Error.get()));
EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
Error->ToString());
Error.reset(new Diagnostics());
- EXPECT_TRUE(NULL == constructMatcher("isArrow", std::string(), Error.get()));
+ EXPECT_TRUE(NULL ==
+ Registry::constructMatcher("isArrow", SourceRange(),
+ Args(std::string()), Error.get()));
EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
Error->ToString());
// Bad argument type
Error.reset(new Diagnostics());
- EXPECT_TRUE(NULL == constructMatcher("ofClass", std::string(), Error.get()));
- EXPECT_EQ("Incorrect type on function ofClass for arg 1.", Error->ToString());
+ EXPECT_TRUE(NULL ==
+ Registry::constructMatcher("ofClass", SourceRange(),
+ Args(std::string()), Error.get()));
+ EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
+ "(Actual = String)",
+ Error->ToString());
Error.reset(new Diagnostics());
- EXPECT_TRUE(NULL == constructMatcher("recordDecl", recordDecl(),
- ::std::string(), Error.get()));
- EXPECT_EQ("Incorrect type on function recordDecl for arg 2.",
+ EXPECT_TRUE(NULL ==
+ Registry::constructMatcher(
+ "recordDecl", SourceRange(),
+ Args(recordDecl(), parameterCountIs(3)), Error.get()));
+ EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
+ "(Actual = Matcher<FunctionDecl>)",
Error->ToString());
}
Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp Thu Jun 20 09:28:32 2013
@@ -28,8 +28,8 @@ TEST(VariantValueTest, Unsigned) {
EXPECT_FALSE(Value.isString());
EXPECT_FALSE(Value.isMatcher());
- EXPECT_FALSE(Value.isTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.isTypedMatcher<clang::UnaryOperator>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
}
TEST(VariantValueTest, String) {
@@ -38,11 +38,12 @@ TEST(VariantValueTest, String) {
EXPECT_TRUE(Value.isString());
EXPECT_EQ(kString, Value.getString());
+ EXPECT_EQ("String", Value.getTypeAsString());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isMatcher());
- EXPECT_FALSE(Value.isTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.isTypedMatcher<clang::UnaryOperator>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
}
TEST(VariantValueTest, DynTypedMatcher) {
@@ -52,22 +53,25 @@ TEST(VariantValueTest, DynTypedMatcher)
EXPECT_FALSE(Value.isString());
EXPECT_TRUE(Value.isMatcher());
- EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
- EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+ EXPECT_TRUE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_EQ("Matcher<Stmt>", Value.getTypeAsString());
- // Conversion to any type of matcher works.
- // If they are not compatible it would just return a matcher that matches
- // nothing. We test this below.
+ // Can only convert to compatible matchers.
Value = recordDecl();
EXPECT_TRUE(Value.isMatcher());
- EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
- EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+ EXPECT_TRUE(Value.hasTypedMatcher<clang::Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
- Value = unaryOperator();
+ Value = ignoringImpCasts(expr());
EXPECT_TRUE(Value.isMatcher());
- EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
- EXPECT_TRUE(Value.isTypedMatcher<clang::Stmt>());
- EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::Stmt>());
+ EXPECT_TRUE(Value.hasTypedMatcher<clang::Expr>());
+ EXPECT_TRUE(Value.hasTypedMatcher<clang::IntegerLiteral>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::GotoStmt>());
+ EXPECT_EQ("Matcher<Expr>", Value.getTypeAsString());
}
TEST(VariantValueTest, Assignment) {
@@ -76,13 +80,15 @@ TEST(VariantValueTest, Assignment) {
EXPECT_EQ("A", Value.getString());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isMatcher());
+ EXPECT_EQ("String", Value.getTypeAsString());
Value = recordDecl();
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
EXPECT_TRUE(Value.isMatcher());
- EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
- EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+ EXPECT_TRUE(Value.hasTypedMatcher<clang::Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
Value = 17;
EXPECT_TRUE(Value.isUnsigned());
@@ -94,25 +100,28 @@ TEST(VariantValueTest, Assignment) {
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
EXPECT_FALSE(Value.isMatcher());
+ EXPECT_EQ("Nothing", Value.getTypeAsString());
}
TEST(GeneicValueTest, Matcher) {
- EXPECT_TRUE(matchesDynamic(
- "class X {};", VariantValue(recordDecl(hasName("X"))).getMatcher()));
- EXPECT_TRUE(matchesDynamic(
- "int x;", VariantValue(varDecl()).getTypedMatcher<clang::Decl>()));
- EXPECT_TRUE(matchesDynamic("int foo() { return 1 + 1; }",
- VariantValue(functionDecl()).getMatcher()));
- // Going through the wrong Matcher<T> will fail to match, even if the
- // underlying matcher is correct.
- EXPECT_FALSE(matchesDynamic(
- "int x;", VariantValue(varDecl()).getTypedMatcher<clang::Stmt>()));
+ EXPECT_TRUE(matches("class X {};", VariantValue(recordDecl(hasName("X")))
+ .getTypedMatcher<Decl>()));
+ EXPECT_TRUE(
+ matches("int x;", VariantValue(varDecl()).getTypedMatcher<Decl>()));
+ EXPECT_TRUE(matches("int foo() { return 1 + 1; }",
+ VariantValue(functionDecl()).getTypedMatcher<Decl>()));
+ // Can't get the wrong matcher.
+ EXPECT_FALSE(VariantValue(varDecl()).hasTypedMatcher<Stmt>());
+#if GTEST_HAS_DEATH_TEST and DEBUG
+ // Trying to get the wrong matcher fails an assertion in Matcher<T>.
+ EXPECT_DEATH(VariantValue(varDecl()).getTypedMatcher<Stmt>(),
+ "canConstructFrom");
+#endif
EXPECT_FALSE(
- matchesDynamic("int x;", VariantValue(functionDecl()).getMatcher()));
- EXPECT_FALSE(matchesDynamic(
- "int foo() { return 1 + 1; }",
- VariantValue(declRefExpr()).getTypedMatcher<clang::DeclRefExpr>()));
+ matches("int x;", VariantValue(functionDecl()).getTypedMatcher<Decl>()));
+ EXPECT_FALSE(matches("int foo() { return 1 + 1; }",
+ VariantValue(declRefExpr()).getTypedMatcher<Stmt>()));
}
} // end anonymous namespace
More information about the cfe-commits
mailing list