From: Samuel Benzaquen Date: Mon, 13 Oct 2014 17:38:12 +0000 (+0000) Subject: Fix bug in DynTypedMatcher::constructVariadic() that would cause false negatives. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e0265decdac966c98cede46cf612cc2cd8eb6c6c;p=clang Fix bug in DynTypedMatcher::constructVariadic() that would cause false negatives. Summary: Change r219118 fixed the bug for anyOf and eachOf, but it is still present for unless. The variadic wrapper doesn't have enough information to know how to restrict the type. Different operators handle restrict failures in different ways. Reviewers: klimek Subscribers: klimek, cfe-commits Differential Revision: http://reviews.llvm.org/D5731 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219622 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp index f6fd5ba2a3..c8e5852475 100644 --- a/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -89,18 +89,19 @@ static llvm::ManagedStatic TrueMatcherInstance; DynTypedMatcher DynTypedMatcher::constructVariadic( VariadicOperatorFunction Func, std::vector 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/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index 2195604799..d458431ecb 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/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/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp index 9011b3f65e..5483f8f358 100644 --- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/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(); + EXPECT_TRUE(matches("void Foo(){}", D)); + EXPECT_TRUE(notMatches("struct Foo {};", D)); } TEST_F(RegistryTest, Errors) {