template <typename T>
bool matchesChildOf(const T &Node, const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder, TraversalKind Traverse,
- BindKind Bind) {
+ BoundNodesTreeBuilder *Builder, BindKind Bind) {
static_assert(std::is_base_of<Decl, T>::value ||
std::is_base_of<Stmt, T>::value ||
std::is_base_of<NestedNameSpecifier, T>::value ||
std::is_base_of<QualType, T>::value,
"unsupported type for recursive matching");
return matchesChildOf(DynTypedNode::create(Node), getASTContext(), Matcher,
- Builder, Traverse, Bind);
+ Builder, Bind);
}
template <typename T>
virtual bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
- TraversalKind Traverse, BindKind Bind) = 0;
+ BindKind Bind) = 0;
virtual bool matchesDescendantOf(const DynTypedNode &Node, ASTContext &Ctx,
const DynTypedMatcher &Matcher,
bool matches(const T &Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const override {
return Finder->matchesChildOf(Node, this->InnerMatcher, Builder,
- TraversalKind::TK_AsIs,
ASTMatchFinder::BK_First);
}
};
BoundNodesTreeBuilder *Builder) const override {
return Finder->matchesChildOf(
Node, this->InnerMatcher, Builder,
- TraversalKind::TK_IgnoreImplicitCastsAndParentheses,
ASTMatchFinder::BK_All);
}
};
// matching the descendants.
MatchChildASTVisitor(const DynTypedMatcher *Matcher, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder, int MaxDepth,
- TraversalKind Traversal, bool IgnoreImplicitChildren,
+ bool IgnoreImplicitChildren,
ASTMatchFinder::BindKind Bind)
: Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),
- MaxDepth(MaxDepth), Traversal(Traversal),
- IgnoreImplicitChildren(IgnoreImplicitChildren), Bind(Bind),
- Matches(false) {}
+ MaxDepth(MaxDepth), IgnoreImplicitChildren(IgnoreImplicitChildren),
+ Bind(Bind), Matches(false) {}
// Returns true if a match is found in the subtree rooted at the
// given AST node. This is done via a set of mutually recursive
Finder->getASTContext().getParentMapContext().traverseIgnored(
ExprNode);
}
- if (Traversal == TraversalKind::TK_IgnoreImplicitCastsAndParentheses) {
- if (Expr *ExprNode = dyn_cast_or_null<Expr>(StmtNode))
- StmtToTraverse = ExprNode->IgnoreParenImpCasts();
- }
return StmtToTraverse;
}
BoundNodesTreeBuilder ResultBindings;
int CurrentDepth;
const int MaxDepth;
- const TraversalKind Traversal;
const bool IgnoreImplicitChildren;
const ASTMatchFinder::BindKind Bind;
bool Matches;
bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder, int MaxDepth,
- TraversalKind Traversal, BindKind Bind) {
+ BindKind Bind) {
// For AST-nodes that don't have an identity, we can't memoize.
if (!Node.getMemoizationData() || !Builder->isComparable())
- return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal,
- Bind);
+ return matchesRecursively(Node, Matcher, Builder, MaxDepth, Bind);
MatchKey Key;
Key.MatcherID = Matcher.getID();
MemoizedMatchResult Result;
Result.Nodes = *Builder;
- Result.ResultOfMatch = matchesRecursively(Node, Matcher, &Result.Nodes,
- MaxDepth, Traversal, Bind);
+ Result.ResultOfMatch =
+ matchesRecursively(Node, Matcher, &Result.Nodes, MaxDepth, Bind);
MemoizedMatchResult &CachedResult = ResultCache[Key];
CachedResult = std::move(Result);
bool matchesRecursively(const DynTypedNode &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder, int MaxDepth,
- TraversalKind Traversal, BindKind Bind) {
+ BindKind Bind) {
bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
TraversingASTChildrenNotSpelledInSource;
ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);
- MatchChildASTVisitor Visitor(&Matcher, this, Builder, MaxDepth, Traversal,
+ MatchChildASTVisitor Visitor(&Matcher, this, Builder, MaxDepth,
IgnoreImplicitChildren, Bind);
return Visitor.findMatch(Node);
}
// Implements ASTMatchFinder::matchesChildOf.
bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder, TraversalKind Traversal,
- BindKind Bind) override {
+ BoundNodesTreeBuilder *Builder, BindKind Bind) override {
if (ResultCache.size() > MaxMemoizationEntries)
ResultCache.clear();
- return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Traversal,
- Bind);
+ return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Bind);
}
// Implements ASTMatchFinder::matchesDescendantOf.
bool matchesDescendantOf(const DynTypedNode &Node, ASTContext &Ctx,
if (ResultCache.size() > MaxMemoizationEntries)
ResultCache.clear();
return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, INT_MAX,
- TraversalKind::TK_AsIs, Bind);
+ Bind);
}
// Implements ASTMatchFinder::matchesAncestorOf.
bool matchesAncestorOf(const DynTypedNode &Node, ASTContext &Ctx,
std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("f", 4)));
}
+TEST(ForEach, DoesNotIgnoreImplicit) {
+ StringRef Code = R"cpp(
+void foo()
+{
+ int i = 0;
+ int b = 4;
+ i < b;
+}
+)cpp";
+ EXPECT_TRUE(matchAndVerifyResultFalse(
+ Code, binaryOperator(forEach(declRefExpr().bind("dre"))),
+ std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("dre", 0)));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Code,
+ binaryOperator(forEach(
+ implicitCastExpr(hasSourceExpression(declRefExpr().bind("dre"))))),
+ std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("dre", 2)));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Code,
+ binaryOperator(
+ forEach(expr(ignoringImplicit(declRefExpr().bind("dre"))))),
+ std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("dre", 2)));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Code,
+ traverse(TK_IgnoreUnlessSpelledInSource,
+ binaryOperator(forEach(declRefExpr().bind("dre")))),
+ std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("dre", 2)));
+}
+
TEST(ForEachDescendant, BindsOneNode) {
EXPECT_TRUE(matchAndVerifyResultTrue("class C { class D { int x; }; };",
recordDecl(hasName("C"),