From: Samuel Benzaquen Date: Fri, 22 Nov 2013 14:41:48 +0000 (+0000) Subject: Add support for the 'unless' matcher in the dynamic layer. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=674e54c167eab0be7a54bca7082c07d2f1d0c8cc;p=clang Add support for the 'unless' matcher in the dynamic layer. Summary: Add support for the 'unless' matcher in the dynamic layer. Reviewers: klimek CC: cfe-commits, revane, klimek Differential Revision: http://llvm-reviews.chandlerc.com/D2247 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@195466 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 0a3157dde8..31571a66b5 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -1317,21 +1317,21 @@ const internal::VariadicAllOfMatcher typeLoc; /// \c b. /// /// Usable as: Any Matcher -const internal::VariadicOperatorMatcherFunc eachOf = { +const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> eachOf = { internal::EachOfVariadicOperator }; /// \brief Matches if any of the given matchers matches. /// /// Usable as: Any Matcher -const internal::VariadicOperatorMatcherFunc anyOf = { +const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> anyOf = { internal::AnyOfVariadicOperator }; /// \brief Matches if all given matchers match. /// /// Usable as: Any Matcher -const internal::VariadicOperatorMatcherFunc allOf = { +const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> allOf = { internal::AllOfVariadicOperator }; @@ -1671,12 +1671,9 @@ const internal::ArgumentAdaptingMatcherFunc< /// \endcode /// /// Usable as: Any Matcher -template -internal::PolymorphicMatcherWithParam1 -unless(const M &InnerMatcher) { - return internal::PolymorphicMatcherWithParam1< - internal::NotMatcher, M>(InnerMatcher); -} +const internal::VariadicOperatorMatcherFunc<1, 1> unless = { + internal::NotUnaryOperator +}; /// \brief Matches a node if the declaration associated with that node /// matches the given matcher. diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h index e1f30151fd..bcc26db5de 100644 --- a/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1098,38 +1098,6 @@ private: const Matcher ChildMatcher; }; -/// \brief Matches nodes of type T if the given Matcher does not match. -/// -/// Type argument MatcherT is required by PolymorphicMatcherWithParam1 -/// but not actually used. It will always be instantiated with a type -/// convertible to Matcher. -template -class NotMatcher : public MatcherInterface { -public: - explicit NotMatcher(const Matcher &InnerMatcher) - : InnerMatcher(InnerMatcher) {} - - virtual bool matches(const T &Node, - ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const { - // The 'unless' matcher will always discard the result: - // If the inner matcher doesn't match, unless returns true, - // but the inner matcher cannot have bound anything. - // If the inner matcher matches, the result is false, and - // any possible binding will be discarded. - // We still need to hand in all the bound nodes up to this - // point so the inner matcher can depend on bound nodes, - // and we need to actively discard the bound nodes, otherwise - // the inner matcher will reset the bound nodes if it doesn't - // match, but this would be inversed by 'unless'. - BoundNodesTreeBuilder Discard(*Builder); - return !InnerMatcher.matches(Node, Finder, &Discard); - } - -private: - const Matcher InnerMatcher; -}; - /// \brief VariadicOperatorMatcher related types. /// @{ @@ -1167,14 +1135,14 @@ struct VariadicOperatorNoArg {}; /// Input matchers can have any type (including other polymorphic matcher /// types), and the actual Matcher is generated on demand with an implicit /// coversion operator. -template class VariadicOperatorMatcher { public: VariadicOperatorMatcher(VariadicOperatorFunction Func, const P1 &Param1, - const P2 &Param2, + const P2 &Param2 = VariadicOperatorNoArg(), const P3 &Param3 = VariadicOperatorNoArg(), const P4 &Param4 = VariadicOperatorNoArg(), const P5 &Param5 = VariadicOperatorNoArg()) @@ -1183,7 +1151,6 @@ public: template operator Matcher() const { std::vector Matchers; - addMatcher(Param1, Matchers); addMatcher(Param2, Matchers); addMatcher(Param3, Matchers); @@ -1215,26 +1182,38 @@ private: /// \brief Overloaded function object to generate VariadicOperatorMatcher /// objects from arbitrary matchers. /// -/// It supports 2-5 argument overloaded operator(). More can be added if needed. +/// It supports 1-5 argument overloaded operator(). More can be added if needed. +template struct VariadicOperatorMatcherFunc { VariadicOperatorFunction Func; + template + struct EnableIfValidArity + : public llvm::enable_if_c {}; + + template + typename EnableIfValidArity<1, VariadicOperatorMatcher >::type + operator()(const M1 &P1) const { + return VariadicOperatorMatcher(Func, P1); + } template - VariadicOperatorMatcher operator()(const M1 &P1, const M2 &P2) const { + typename EnableIfValidArity<2, VariadicOperatorMatcher >::type + operator()(const M1 &P1, const M2 &P2) const { return VariadicOperatorMatcher(Func, P1, P2); } template - VariadicOperatorMatcher operator()(const M1 &P1, const M2 &P2, - const M3 &P3) const { + typename EnableIfValidArity<3, VariadicOperatorMatcher >::type + operator()(const M1 &P1, const M2 &P2, const M3 &P3) const { return VariadicOperatorMatcher(Func, P1, P2, P3); } template - VariadicOperatorMatcher + typename EnableIfValidArity<4, VariadicOperatorMatcher >::type operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) const { return VariadicOperatorMatcher(Func, P1, P2, P3, P4); } template - VariadicOperatorMatcher + typename EnableIfValidArity< + 5, VariadicOperatorMatcher >::type operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5) const { return VariadicOperatorMatcher(Func, P1, P2, P3, P4, @@ -1244,6 +1223,13 @@ struct VariadicOperatorMatcherFunc { /// @} +/// \brief Matches nodes that do not match the provided matcher. +/// +/// Uses the variadic matcher interface, but fails if InnerMatchers.size()!=1. +bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, + ArrayRef InnerMatchers); + /// \brief Matches nodes for which all provided matchers match. bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp index d15eb54002..47b8b6d2f2 100644 --- a/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -34,6 +34,26 @@ void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) { } } +bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, + ArrayRef InnerMatchers) { + if (InnerMatchers.size() != 1) + return false; + + // The 'unless' matcher will always discard the result: + // If the inner matcher doesn't match, unless returns true, + // but the inner matcher cannot have bound anything. + // If the inner matcher matches, the result is false, and + // any possible binding will be discarded. + // We still need to hand in all the bound nodes up to this + // point so the inner matcher can depend on bound nodes, + // and we need to actively discard the bound nodes, otherwise + // the inner matcher will reset the bound nodes if it doesn't + // match, but this would be inversed by 'unless'. + BoundNodesTreeBuilder Discard(*Builder); + return !InnerMatchers[0].matches(DynNode, Finder, &Discard); +} + bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h index ae0c300d09..2f9db9c56b 100644 --- a/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/lib/ASTMatchers/Dynamic/Marshallers.h @@ -347,12 +347,22 @@ private: class VariadicOperatorMatcherCreateCallback : public MatcherCreateCallback { public: typedef ast_matchers::internal::VariadicOperatorFunction VarFunc; - VariadicOperatorMatcherCreateCallback(VarFunc Func, StringRef MatcherName) - : Func(Func), MatcherName(MatcherName) {} + VariadicOperatorMatcherCreateCallback(unsigned MinCount, unsigned MaxCount, + VarFunc Func, StringRef MatcherName) + : MinCount(MinCount), MaxCount(MaxCount), Func(Func), + MatcherName(MatcherName) {} virtual VariantMatcher run(const SourceRange &NameRange, ArrayRef Args, Diagnostics *Error) const { + if (Args.size() < MinCount || MaxCount < Args.size()) { + const std::string MaxStr = + (MaxCount == UINT_MAX ? "" : Twine(MaxCount)).str(); + Error->addError(NameRange, Error->ET_RegistryWrongArgCount) + << ("(" + Twine(MinCount) + ", " + MaxStr + ")") << Args.size(); + return VariantMatcher(); + } + std::vector InnerArgs; for (size_t i = 0, e = Args.size(); i != e; ++i) { const ParserValue &Arg = Args[i]; @@ -368,6 +378,8 @@ public: } private: + const unsigned MinCount; + const unsigned MaxCount; const VarFunc Func; const StringRef MatcherName; }; @@ -439,10 +451,13 @@ AdaptativeOverloadCollector::collect( } /// \brief Variadic operator overload. -MatcherCreateCallback *makeMatcherAutoMarshall( - ast_matchers::internal::VariadicOperatorMatcherFunc Func, - StringRef MatcherName) { - return new VariadicOperatorMatcherCreateCallback(Func.Func, MatcherName); +template +MatcherCreateCallback * +makeMatcherAutoMarshall(ast_matchers::internal::VariadicOperatorMatcherFunc< + MinCount, MaxCount> Func, + StringRef MatcherName) { + return new VariadicOperatorMatcherCreateCallback(MinCount, MaxCount, + Func.Func, MatcherName); } } // namespace internal diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index 70e956e654..a19cdc06e9 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -76,7 +76,6 @@ RegistryMaps::RegistryMaps() { // ofKind // // Polymorphic + argument overload: - // unless // findAll // // Other: @@ -285,6 +284,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(typedefType); REGISTER_MATCHER(unaryExprOrTypeTraitExpr); REGISTER_MATCHER(unaryOperator); + REGISTER_MATCHER(unless); REGISTER_MATCHER(userDefinedLiteral); REGISTER_MATCHER(usingDecl); REGISTER_MATCHER(varDecl); diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp index e716484e20..dad9499ad4 100644 --- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -295,6 +295,17 @@ TEST_F(RegistryTest, VariadicOp) { EXPECT_FALSE(matches("int i = 0;", D)); EXPECT_TRUE(matches("class Bar{};", D)); EXPECT_FALSE(matches("class OtherBar{};", D)); + + D = constructMatcher( + "recordDecl", + constructMatcher( + "unless", + constructMatcher("namedDecl", + constructMatcher("hasName", std::string("Bar"))))) + .getTypedMatcher(); + + EXPECT_FALSE(matches("class Bar{};", D)); + EXPECT_TRUE(matches("class OtherBar{};", D)); } TEST_F(RegistryTest, Errors) { @@ -307,6 +318,15 @@ TEST_F(RegistryTest, Errors) { EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).isNull()); EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)", Error->toString()); + Error.reset(new Diagnostics()); + EXPECT_TRUE(constructMatcher("anyOf", Error.get()).isNull()); + EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)", + Error->toString()); + Error.reset(new Diagnostics()); + EXPECT_TRUE(constructMatcher("unless", std::string(), std::string(), + Error.get()).isNull()); + EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)", + Error->toString()); // Bad argument type Error.reset(new Diagnostics()); @@ -324,7 +344,8 @@ TEST_F(RegistryTest, Errors) { // Bad argument type with variadic. Error.reset(new Diagnostics()); - EXPECT_TRUE(constructMatcher("anyOf", std::string(), Error.get()).isNull()); + EXPECT_TRUE(constructMatcher("anyOf", std::string(), std::string(), + Error.get()).isNull()); EXPECT_EQ( "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)", Error->toString());