forked from OSchip/llvm-project
Adds the possibility to run ASTMatchFinder over arbitrary AST nodes.
llvm-svn: 166567
This commit is contained in:
parent
d6afb03bc9
commit
c268745011
|
@ -123,6 +123,13 @@ public:
|
|||
/// \brief Creates a clang ASTConsumer that finds all matches.
|
||||
clang::ASTConsumer *newASTConsumer();
|
||||
|
||||
/// \brief Finds all matches on the given \c Node.
|
||||
///
|
||||
/// @{
|
||||
void findAll(const Decl &Node, ASTContext &Context);
|
||||
void findAll(const Stmt &Node, ASTContext &Context);
|
||||
/// @}
|
||||
|
||||
/// \brief Registers a callback to notify the end of parsing.
|
||||
///
|
||||
/// The provided closure is called after parsing is done, before the AST is
|
||||
|
|
|
@ -667,6 +667,18 @@ ASTConsumer *MatchFinder::newASTConsumer() {
|
|||
return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone);
|
||||
}
|
||||
|
||||
void MatchFinder::findAll(const Decl &Node, ASTContext &Context) {
|
||||
internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
|
||||
Visitor.set_active_ast_context(&Context);
|
||||
Visitor.TraverseDecl(const_cast<Decl*>(&Node));
|
||||
}
|
||||
|
||||
void MatchFinder::findAll(const Stmt &Node, ASTContext &Context) {
|
||||
internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
|
||||
Visitor.set_active_ast_context(&Context);
|
||||
Visitor.TraverseStmt(const_cast<Stmt*>(&Node));
|
||||
}
|
||||
|
||||
void MatchFinder::registerTestCallbackAfterParsing(
|
||||
MatchFinder::ParsingDoneTestCallback *NewParsingDone) {
|
||||
ParsingDone = NewParsingDone;
|
||||
|
|
|
@ -3171,5 +3171,42 @@ TEST(NNS, MatchesNestedNameSpecifierPrefixes) {
|
|||
specifiesTypeLoc(loc(qualType(asString("struct A"))))))));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class VerifyRecursiveMatch : public BoundNodesCallback {
|
||||
public:
|
||||
explicit VerifyRecursiveMatch(StringRef Id,
|
||||
const internal::Matcher<T> &InnerMatcher)
|
||||
: Id(Id), InnerMatcher(InnerMatcher) {}
|
||||
virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
|
||||
const T *Node = Nodes->getNodeAs<T>(Id);
|
||||
bool Found = false;
|
||||
MatchFinder Finder;
|
||||
Finder.addMatcher(InnerMatcher, new VerifyMatch(0, &Found));
|
||||
Finder.findAll(*Node, *Context);
|
||||
return Found;
|
||||
}
|
||||
private:
|
||||
std::string Id;
|
||||
internal::Matcher<T> InnerMatcher;
|
||||
};
|
||||
|
||||
TEST(MatchFinder, CanMatchDeclarationsRecursively) {
|
||||
EXPECT_TRUE(matchAndVerifyResultTrue("class X { class Y {}; };",
|
||||
recordDecl(hasName("::X")).bind("X"),
|
||||
new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Y")))));
|
||||
EXPECT_TRUE(matchAndVerifyResultFalse("class X { class Y {}; };",
|
||||
recordDecl(hasName("::X")).bind("X"),
|
||||
new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Z")))));
|
||||
}
|
||||
|
||||
TEST(MatchFinder, CanMatchStatementsRecursively) {
|
||||
EXPECT_TRUE(matchAndVerifyResultTrue("void f() { if (1) { for (;;) { } } }",
|
||||
ifStmt().bind("if"),
|
||||
new VerifyRecursiveMatch<clang::Stmt>("if", forStmt())));
|
||||
EXPECT_TRUE(matchAndVerifyResultFalse("void f() { if (1) { for (;;) { } } }",
|
||||
ifStmt().bind("if"),
|
||||
new VerifyRecursiveMatch<clang::Stmt>("if", declStmt())));
|
||||
}
|
||||
|
||||
} // end namespace ast_matchers
|
||||
} // end namespace clang
|
||||
|
|
|
@ -24,7 +24,10 @@ using clang::tooling::FrontendActionFactory;
|
|||
class BoundNodesCallback {
|
||||
public:
|
||||
virtual ~BoundNodesCallback() {}
|
||||
virtual bool run(const BoundNodes *BoundNodes) = 0;
|
||||
virtual bool run(const BoundNodes *BoundNodes) { return false; }
|
||||
virtual bool run(const BoundNodes *BoundNodes, ASTContext *Context) {
|
||||
return run(BoundNodes);
|
||||
}
|
||||
};
|
||||
|
||||
// If 'FindResultVerifier' is not NULL, sets *Verified to the result of
|
||||
|
@ -37,7 +40,7 @@ public:
|
|||
|
||||
virtual void run(const MatchFinder::MatchResult &Result) {
|
||||
if (FindResultReviewer != NULL) {
|
||||
*Verified = FindResultReviewer->run(&Result.Nodes);
|
||||
*Verified = FindResultReviewer->run(&Result.Nodes, Result.Context);
|
||||
} else {
|
||||
*Verified = true;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue