summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Jasper <djasper@google.com>2012-11-11 22:14:55 +0000
committerDaniel Jasper <djasper@google.com>2012-11-11 22:14:55 +0000
commit11c98771ba5d7fb1ec5707f9e1c77a6cf65bbc59 (patch)
treea6c4d9ce6e92f481bef20e25d1785f913bd8754b
parent18f236886b02e999bea6ceff3aa90951198007cb (diff)
Fix binding of nodes in case of forEach..() matchers.
When recursively visiting the generated matches, the aggregated bindings need to be copied during the recursion. Otherwise, we they might not be properly overwritten (which is shown by the test), or there might be bound nodes present that were bound on a different matching branch. Review: http://llvm-reviews.chandlerc.com/D112 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167695 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/ASTMatchers/ASTMatchersInternal.h2
-rw-r--r--lib/ASTMatchers/ASTMatchersInternal.cpp11
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp11
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h2
4 files changed, 19 insertions, 7 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index 7bcf90fce7..e5365ff89d 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -141,7 +141,7 @@ public:
private:
void visitMatchesRecursively(
Visitor* ResultVistior,
- BoundNodesMap *AggregatedBindings);
+ const BoundNodesMap& AggregatedBindings);
// FIXME: Find out whether we want to use different data structures here -
// first benchmarks indicate that it doesn't matter though.
diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp
index e7ee8ee7ed..408195d369 100644
--- a/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -51,19 +51,20 @@ void BoundNodesTree::copyTo(BoundNodesTreeBuilder* Builder) const {
void BoundNodesTree::visitMatches(Visitor* ResultVisitor) {
BoundNodesMap AggregatedBindings;
- visitMatchesRecursively(ResultVisitor, &AggregatedBindings);
+ visitMatchesRecursively(ResultVisitor, AggregatedBindings);
}
void BoundNodesTree::
visitMatchesRecursively(Visitor* ResultVisitor,
- BoundNodesMap* AggregatedBindings) {
- Bindings.copyTo(AggregatedBindings);
+ const BoundNodesMap& AggregatedBindings) {
+ BoundNodesMap CombinedBindings(AggregatedBindings);
+ Bindings.copyTo(&CombinedBindings);
if (RecursiveBindings.empty()) {
- ResultVisitor->visitMatch(BoundNodes(*AggregatedBindings));
+ ResultVisitor->visitMatch(BoundNodes(CombinedBindings));
} else {
for (unsigned I = 0; I < RecursiveBindings.size(); ++I) {
RecursiveBindings[I].visitMatchesRecursively(ResultVisitor,
- AggregatedBindings);
+ CombinedBindings);
}
}
}
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index ad5469348d..e15940aea4 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -2775,6 +2775,17 @@ TEST(ForEachDescendant, BindsRecursiveCombinations) {
new VerifyIdIsBoundTo<FieldDecl>("f", 8)));
}
+TEST(ForEachDescendant, BindsCorrectNodes) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class C { void f(); int i; };",
+ recordDecl(hasName("C"), forEachDescendant(decl().bind("decl"))),
+ new VerifyIdIsBoundTo<FieldDecl>("decl", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class C { void f() {} int i; };",
+ recordDecl(hasName("C"), forEachDescendant(decl().bind("decl"))),
+ new VerifyIdIsBoundTo<FunctionDecl>("decl", 1)));
+}
+
TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) {
// Make sure that we can both match the class by name (::X) and by the type
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index 5e63b6bb11..3b23ada8da 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -38,7 +38,7 @@ public:
virtual void run(const MatchFinder::MatchResult &Result) {
if (FindResultReviewer != NULL) {
- *Verified = FindResultReviewer->run(&Result.Nodes, Result.Context);
+ *Verified |= FindResultReviewer->run(&Result.Nodes, Result.Context);
} else {
*Verified = true;
}