summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/ASTMatchers/ASTMatchersInternal.cpp25
-rw-r--r--clang/unittests/ASTMatchers/ASTMatchersTest.cpp5
-rw-r--r--clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp7
3 files changed, 25 insertions, 12 deletions
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index f6fd5ba2a3f..c8e5852475c 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -89,18 +89,19 @@ static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance;
DynTypedMatcher DynTypedMatcher::constructVariadic(
VariadicOperatorFunction Func, std::vector<DynTypedMatcher> InnerMatchers) {
assert(InnerMatchers.size() > 0 && "Array must not be empty.");
- DynTypedMatcher Result = InnerMatchers[0];
- // Use the least derived type as the restriction for the wrapper.
- // This allows mismatches to be resolved on the inner matchers.
- for (const DynTypedMatcher &M : InnerMatchers) {
- assert(Result.SupportedKind.isSame(M.SupportedKind) &&
- "SupportedKind must match!");
- Result.RestrictKind =
- ast_type_traits::ASTNodeKind::getMostDerivedCommonAncestor(
- Result.RestrictKind, M.RestrictKind);
- }
- Result.Implementation = new VariadicMatcher(Func, std::move(InnerMatchers));
- return Result;
+ assert(std::all_of(InnerMatchers.begin(), InnerMatchers.end(),
+ [&InnerMatchers](const DynTypedMatcher &M) {
+ return InnerMatchers[0].SupportedKind.isSame(M.SupportedKind);
+ }) &&
+ "SupportedKind must match!");
+
+ // We must relax the restrict kind here.
+ // The different operators might deal differently with a mismatch.
+ // Make it the same as SupportedKind, since that is the broadest type we are
+ // allowed to accept.
+ return DynTypedMatcher(InnerMatchers[0].SupportedKind,
+ InnerMatchers[0].SupportedKind,
+ new VariadicMatcher(Func, std::move(InnerMatchers)));
}
DynTypedMatcher DynTypedMatcher::trueMatcher(
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp
index 2195604799b..d458431ecbb 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -591,6 +591,11 @@ TEST(DeclarationMatcher, MatchNot) {
EXPECT_TRUE(matches("class X { class Z {}; };", ClassXHasNotClassY));
EXPECT_TRUE(notMatches("class X { class Y {}; class Z {}; };",
ClassXHasNotClassY));
+
+ DeclarationMatcher NamedNotRecord =
+ namedDecl(hasName("Foo"), unless(recordDecl()));
+ EXPECT_TRUE(matches("void Foo(){}", NamedNotRecord));
+ EXPECT_TRUE(notMatches("struct Foo {};", NamedNotRecord));
}
TEST(DeclarationMatcher, HasDescendant) {
diff --git a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index 9011b3f65ec..5483f8f3580 100644
--- a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -380,6 +380,13 @@ TEST_F(RegistryTest, VariadicOp) {
EXPECT_FALSE(matches("class Bar{ int Foo; };", D));
EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D));
+
+ D = constructMatcher(
+ "namedDecl", constructMatcher("hasName", std::string("Foo")),
+ constructMatcher("unless", constructMatcher("recordDecl")))
+ .getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("void Foo(){}", D));
+ EXPECT_TRUE(notMatches("struct Foo {};", D));
}
TEST_F(RegistryTest, Errors) {
OpenPOWER on IntegriCloud