Re-introduce MatchFinder::addDynamicMatcher.
Differential Revision: http://llvm-reviews.chandlerc.com/D2114 llvm-svn: 194222
This commit is contained in:
parent
d3d140da36
commit
2b94713053
|
@ -136,6 +136,17 @@ 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();
|
||||
|
||||
|
|
|
@ -811,6 +811,30 @@ void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch,
|
|||
MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
|
||||
}
|
||||
|
||||
bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
|
||||
MatchCallback *Action) {
|
||||
if (NodeMatch.canConvertTo<Decl>()) {
|
||||
addMatcher(NodeMatch.convertTo<Decl>(), Action);
|
||||
return true;
|
||||
} else if (NodeMatch.canConvertTo<QualType>()) {
|
||||
addMatcher(NodeMatch.convertTo<QualType>(), Action);
|
||||
return true;
|
||||
} else if (NodeMatch.canConvertTo<Stmt>()) {
|
||||
addMatcher(NodeMatch.convertTo<Stmt>(), Action);
|
||||
return true;
|
||||
} else if (NodeMatch.canConvertTo<NestedNameSpecifier>()) {
|
||||
addMatcher(NodeMatch.convertTo<NestedNameSpecifier>(), Action);
|
||||
return true;
|
||||
} else if (NodeMatch.canConvertTo<NestedNameSpecifierLoc>()) {
|
||||
addMatcher(NodeMatch.convertTo<NestedNameSpecifierLoc>(), Action);
|
||||
return true;
|
||||
} else if (NodeMatch.canConvertTo<TypeLoc>()) {
|
||||
addMatcher(NodeMatch.convertTo<TypeLoc>(), Action);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTConsumer *MatchFinder::newASTConsumer() {
|
||||
return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,18 @@ TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) {
|
|||
}
|
||||
#endif
|
||||
|
||||
TEST(Finder, DynamicOnlyAcceptsSomeMatchers) {
|
||||
MatchFinder Finder;
|
||||
EXPECT_TRUE(Finder.addDynamicMatcher(decl(), NULL));
|
||||
EXPECT_TRUE(Finder.addDynamicMatcher(callExpr(), NULL));
|
||||
EXPECT_TRUE(Finder.addDynamicMatcher(constantArrayType(hasSize(42)), NULL));
|
||||
|
||||
// Do not accept non-toplevel matchers.
|
||||
EXPECT_FALSE(Finder.addDynamicMatcher(isArrow(), NULL));
|
||||
EXPECT_FALSE(Finder.addDynamicMatcher(hasSize(2), NULL));
|
||||
EXPECT_FALSE(Finder.addDynamicMatcher(hasName("x"), NULL));
|
||||
}
|
||||
|
||||
TEST(Decl, MatchesDeclarations) {
|
||||
EXPECT_TRUE(notMatches("", decl(usingDecl())));
|
||||
EXPECT_TRUE(matches("namespace x { class X {}; } using x::X;",
|
||||
|
@ -651,11 +663,18 @@ public:
|
|||
: Id(Id), ExpectedCount(ExpectedCount), Count(0),
|
||||
ExpectedName(ExpectedName) {}
|
||||
|
||||
~VerifyIdIsBoundTo() {
|
||||
void onEndOfTranslationUnit() LLVM_OVERRIDE {
|
||||
if (ExpectedCount != -1)
|
||||
EXPECT_EQ(ExpectedCount, Count);
|
||||
if (!ExpectedName.empty())
|
||||
EXPECT_EQ(ExpectedName, Name);
|
||||
Count = 0;
|
||||
Name.clear();
|
||||
}
|
||||
|
||||
~VerifyIdIsBoundTo() {
|
||||
EXPECT_EQ(0, Count);
|
||||
EXPECT_EQ("", Name);
|
||||
}
|
||||
|
||||
virtual bool run(const BoundNodes *Nodes) {
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
virtual ~BoundNodesCallback() {}
|
||||
virtual bool run(const BoundNodes *BoundNodes) = 0;
|
||||
virtual bool run(const BoundNodes *BoundNodes, ASTContext *Context) = 0;
|
||||
virtual void onEndOfTranslationUnit() {}
|
||||
};
|
||||
|
||||
// If 'FindResultVerifier' is not NULL, sets *Verified to the result of
|
||||
|
@ -44,6 +45,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void onEndOfTranslationUnit() LLVM_OVERRIDE {
|
||||
if (FindResultReviewer)
|
||||
FindResultReviewer->onEndOfTranslationUnit();
|
||||
}
|
||||
|
||||
private:
|
||||
bool *const Verified;
|
||||
BoundNodesCallback *const FindResultReviewer;
|
||||
|
@ -54,15 +60,23 @@ testing::AssertionResult matchesConditionally(const std::string &Code,
|
|||
const T &AMatcher,
|
||||
bool ExpectMatch,
|
||||
llvm::StringRef CompileArg) {
|
||||
bool Found = false;
|
||||
bool Found = false, DynamicFound = false;
|
||||
MatchFinder Finder;
|
||||
Finder.addMatcher(AMatcher, new VerifyMatch(0, &Found));
|
||||
if (!Finder.addDynamicMatcher(AMatcher, new VerifyMatch(0, &DynamicFound)))
|
||||
return testing::AssertionFailure() << "Could not add dynamic matcher";
|
||||
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 != DynamicFound) {
|
||||
return testing::AssertionFailure() << "Dynamic match result ("
|
||||
<< DynamicFound
|
||||
<< ") does not match static result ("
|
||||
<< Found << ")";
|
||||
}
|
||||
if (!Found && ExpectMatch) {
|
||||
return testing::AssertionFailure()
|
||||
<< "Could not find match in \"" << Code << "\"";
|
||||
|
|
Loading…
Reference in New Issue