Add support for .bind("foo") expressions on the dynamic matchers.
Summary: Add support on the parser, registry, and DynTypedMatcher for binding IDs dynamically.
Reviewers: klimek
CC: cfe-commits, revane
Differential Revision: http://llvm-reviews.chandlerc.com/D911
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183144 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index 41f5228..310108a 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -24,6 +24,8 @@
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;
@@ -35,14 +37,21 @@
/// \brief Makes a copy of this matcher object.
virtual DynTypedMatcher *clone() const {
- return new DummyDynTypedMatcher(ID);
+ 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; }
+
private:
uint64_t ID;
+ std::string BoundID;
};
class MockSema : public Parser::Sema {
@@ -65,17 +74,20 @@
DynTypedMatcher *actOnMatcherExpression(StringRef MatcherName,
const SourceRange &NameRange,
+ StringRef BindID,
ArrayRef<ParserValue> Args,
Diagnostics *Error) {
- MatcherInfo ToStore = { MatcherName, NameRange, Args };
+ MatcherInfo ToStore = { MatcherName, NameRange, Args, BindID };
Matchers.push_back(ToStore);
- return new DummyDynTypedMatcher(ExpectedMatchers[MatcherName]);
+ DummyDynTypedMatcher Matcher(ExpectedMatchers[MatcherName]);
+ return Matcher.tryBind(BindID);
}
struct MatcherInfo {
StringRef MatcherName;
SourceRange NameRange;
std::vector<ParserValue> Args;
+ std::string BoundID;
};
std::vector<std::string> Errors;
@@ -110,13 +122,15 @@
const uint64_t ExpectedFoo = Sema.expectMatcher("Foo");
const uint64_t ExpectedBar = Sema.expectMatcher("Bar");
const uint64_t ExpectedBaz = Sema.expectMatcher("Baz");
- Sema.parse(" Foo ( Bar (), Baz( \n \"B A,Z\") ) ");
+ Sema.parse(" Foo ( Bar (), Baz( \n \"B A,Z\") ) .bind( \"Yo!\") ");
for (size_t i = 0, e = Sema.Errors.size(); i != e; ++i) {
EXPECT_EQ("", Sema.Errors[i]);
}
EXPECT_EQ(1ULL, Sema.Values.size());
EXPECT_EQ(ExpectedFoo, Sema.Values[0].getMatcher().getID());
+ EXPECT_EQ("Yo!", static_cast<const DummyDynTypedMatcher &>(
+ Sema.Values[0].getMatcher()).boundID());
EXPECT_EQ(3ULL, Sema.Matchers.size());
const MockSema::MatcherInfo Bar = Sema.Matchers[0];
@@ -136,6 +150,7 @@
EXPECT_EQ(2ULL, Foo.Args.size());
EXPECT_EQ(ExpectedBar, Foo.Args[0].Value.getMatcher().getID());
EXPECT_EQ(ExpectedBaz, Foo.Args[1].Value.getMatcher().getID());
+ EXPECT_EQ("Yo!", Foo.BoundID);
}
using ast_matchers::internal::Matcher;
@@ -186,6 +201,18 @@
EXPECT_EQ("1:1: Error parsing argument 1 for matcher Foo.\n"
"1:5: Invalid token <(> found when looking for a value.",
ParseWithError("Foo(("));
+ EXPECT_EQ("1:7: Expected end of code.", ParseWithError("expr()a"));
+ EXPECT_EQ("1:11: Malformed bind() expression.",
+ ParseWithError("isArrow().biind"));
+ EXPECT_EQ("1:15: Malformed bind() expression.",
+ ParseWithError("isArrow().bind"));
+ EXPECT_EQ("1:16: Malformed bind() expression.",
+ ParseWithError("isArrow().bind(foo"));
+ EXPECT_EQ("1:21: Malformed bind() expression.",
+ ParseWithError("isArrow().bind(\"foo\""));
+ EXPECT_EQ("1:1: Error building matcher isArrow.\n"
+ "1:1: Matcher does not support binding.",
+ ParseWithError("isArrow().bind(\"foo\")"));
}
} // end anonymous namespace