From: Samuel Benzaquen Date: Wed, 28 Aug 2013 18:42:04 +0000 (+0000) Subject: Add support for eachOf/allOf/anyOf variadic matchers in the dynamic layer. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a735090449197f1edcdc85a6080eebc0304a31dd;p=clang Add support for eachOf/allOf/anyOf variadic matchers in the dynamic layer. Summary: Add support for eachOf/allOf/anyOf variadic matchers in the dynamic layer. These function require some late binding behavior for the type conversions, thus changes in VariadicValue's MatcherList. Second try. This time with a fix for C++11 builds. Reviewers: klimek CC: cfe-commits, revane Differential Revision: http://llvm-reviews.chandlerc.com/D1536 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@189500 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h index bee5d661db..e58e1c7af1 100644 --- a/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -50,6 +50,10 @@ class VariantMatcher { public: virtual ~MatcherOps(); virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const = 0; + virtual void constructFrom(const DynTypedMatcher &Matcher) = 0; + virtual void constructVariadicOperator( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef InnerMatchers) = 0; }; /// \brief Payload interface to be specialized by each matcher type. @@ -60,9 +64,7 @@ class VariantMatcher { virtual ~Payload(); virtual bool getSingleMatcher(const DynTypedMatcher *&Out) const = 0; virtual std::string getTypeAsString() const = 0; - virtual bool hasTypedMatcher(const MatcherOps &Ops) const = 0; - virtual const DynTypedMatcher * - getTypedMatcher(const MatcherOps &Ops) const = 0; + virtual void makeTypedMatcher(MatcherOps &Ops) const = 0; }; public: @@ -78,6 +80,13 @@ public: static VariantMatcher PolymorphicMatcher(ArrayRef Matchers); + /// \brief Creates a 'variadic' operator matcher. + /// + /// It will bind to the appropriate type on getTypedMatcher(). + static VariantMatcher VariadicOperatorMatcher( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef Args); + /// \brief Makes the matcher the "null" matcher. void reset(); @@ -101,8 +110,9 @@ public: /// that can, the result would be ambiguous and false is returned. template bool hasTypedMatcher() const { - if (Value) return Value->hasTypedMatcher(TypedMatcherOps()); - return false; + TypedMatcherOps Ops; + if (Value) Value->makeTypedMatcher(Ops); + return Ops.hasMatcher(); } /// \brief Return this matcher as a \c Matcher. @@ -111,9 +121,10 @@ public: /// Asserts that \c hasTypedMatcher() is true. template ast_matchers::internal::Matcher getTypedMatcher() const { - assert(hasTypedMatcher()); - return ast_matchers::internal::Matcher::constructFrom( - *Value->getTypedMatcher(TypedMatcherOps())); + TypedMatcherOps Ops; + Value->makeTypedMatcher(Ops); + assert(Ops.hasMatcher() && "hasTypedMatcher() == false"); + return Ops.matcher(); } /// \brief String representation of the type of the value. @@ -127,13 +138,50 @@ private: class SinglePayload; class PolymorphicPayload; + class VariadicOpPayload; template class TypedMatcherOps : public MatcherOps { public: + typedef ast_matchers::internal::Matcher MatcherT; + virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const { - return ast_matchers::internal::Matcher::canConstructFrom(Matcher); + return MatcherT::canConstructFrom(Matcher); + } + + virtual void constructFrom(const DynTypedMatcher& Matcher) { + Out.reset(new MatcherT(MatcherT::constructFrom(Matcher))); } + + virtual void constructVariadicOperator( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef InnerMatchers) { + const size_t NumArgs = InnerMatchers.size(); + MatcherT **InnerArgs = new MatcherT *[NumArgs](); + bool HasError = false; + for (size_t i = 0; i != NumArgs; ++i) { + // Abort if any of the inner matchers can't be converted to + // Matcher. + if (!InnerMatchers[i].hasTypedMatcher()) { + HasError = true; + break; + } + InnerArgs[i] = new MatcherT(InnerMatchers[i].getTypedMatcher()); + } + if (!HasError) { + Out.reset(new MatcherT( + new ast_matchers::internal::VariadicOperatorMatcherInterface( + Func, ArrayRef(InnerArgs, NumArgs)))); + } + std::for_each(InnerArgs, InnerArgs + NumArgs, llvm::deleter); + delete[] InnerArgs; + } + + bool hasMatcher() const { return Out.get() != NULL; } + const MatcherT &matcher() const { return *Out; } + + private: + OwningPtr Out; }; IntrusiveRefCntPtr Value; diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h index 94b95b10d5..902fdc364b 100644 --- a/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/lib/ASTMatchers/Dynamic/Marshallers.h @@ -348,6 +348,36 @@ private: std::vector Overloads; }; +/// \brief Variadic operator marshaller function. +class VariadicOperatorMatcherCreateCallback : public MatcherCreateCallback { +public: + typedef ast_matchers::internal::VariadicOperatorFunction VarFunc; + VariadicOperatorMatcherCreateCallback(VarFunc Func, StringRef MatcherName) + : Func(Func), MatcherName(MatcherName) {} + + virtual VariantMatcher run(const SourceRange &NameRange, + ArrayRef Args, + Diagnostics *Error) const { + std::vector InnerArgs; + for (size_t i = 0, e = Args.size(); i != e; ++i) { + const ParserValue &Arg = Args[i]; + const VariantValue &Value = Arg.Value; + if (!Value.isMatcher()) { + Error->addError(Arg.Range, Error->ET_RegistryWrongArgType) + << (i + 1) << "Matcher<>" << Value.getTypeAsString(); + return VariantMatcher(); + } + InnerArgs.push_back(Value.getMatcher()); + } + return VariantMatcher::VariadicOperatorMatcher(Func, InnerArgs); + } + +private: + const VarFunc Func; + const StringRef MatcherName; +}; + + /// Helper functions to select the appropriate marshaller functions. /// They detect the number of arguments, arguments types and return type. @@ -410,6 +440,13 @@ AdaptativeOverloadCollector::collect( collect(typename FromTypeList::tail()); } +/// \brief Variadic operator overload. +MatcherCreateCallback *makeMatcherAutoMarshall( + ast_matchers::internal::VariadicOperatorMatcherFunc Func, + StringRef MatcherName) { + return new VariadicOperatorMatcherCreateCallback(Func.Func, MatcherName); +} + } // namespace internal } // namespace dynamic } // namespace ast_matchers diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index 55763b0efe..3f8e7d4cd9 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -77,9 +77,6 @@ RegistryMaps::RegistryMaps() { // // Polymorphic + argument overload: // unless - // eachOf - // anyOf - // allOf // findAll // // Other: @@ -99,6 +96,8 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(accessSpecDecl); REGISTER_MATCHER(alignOfExpr); + REGISTER_MATCHER(allOf); + REGISTER_MATCHER(anyOf); REGISTER_MATCHER(anything); REGISTER_MATCHER(argumentCountIs); REGISTER_MATCHER(arraySubscriptExpr); @@ -141,6 +140,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(destructorDecl); REGISTER_MATCHER(doStmt); REGISTER_MATCHER(dynamicCastExpr); + REGISTER_MATCHER(eachOf); REGISTER_MATCHER(elaboratedType); REGISTER_MATCHER(enumConstantDecl); REGISTER_MATCHER(enumDecl); diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp index 87aca7da85..c350d78aa1 100644 --- a/lib/ASTMatchers/Dynamic/VariantValue.cpp +++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -38,13 +38,9 @@ public: .str(); } - virtual bool hasTypedMatcher(const MatcherOps &Ops) const { - return Ops.canConstructFrom(*Matcher); - } - - virtual const DynTypedMatcher *getTypedMatcher(const MatcherOps &Ops) const { - assert(hasTypedMatcher(Ops)); - return Matcher.get(); + virtual void makeTypedMatcher(MatcherOps &Ops) const { + if (Ops.canConstructFrom(*Matcher)) + Ops.constructFrom(*Matcher); } private: @@ -80,25 +76,51 @@ public: return (Twine("Matcher<") + Inner + ">").str(); } - virtual bool hasTypedMatcher(const MatcherOps &Ops) const { - return getTypedMatcher(Ops) != NULL; - } - - virtual const DynTypedMatcher *getTypedMatcher(const MatcherOps &Ops) const { - const DynTypedMatcher* Found = NULL; + virtual void makeTypedMatcher(MatcherOps &Ops) const { + const DynTypedMatcher *Found = NULL; for (size_t i = 0, e = Matchers.size(); i != e; ++i) { if (Ops.canConstructFrom(*Matchers[i])) { - if (Found) return NULL; + if (Found) + return; Found = Matchers[i]; } } - return Found; + if (Found) + Ops.constructFrom(*Found); } -private: std::vector Matchers; }; +class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload { +public: + VariadicOpPayload(ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef Args) + : Func(Func), Args(Args) {} + + virtual bool getSingleMatcher(const DynTypedMatcher *&Out) const { + return false; + } + + virtual std::string getTypeAsString() const { + std::string Inner; + for (size_t i = 0, e = Args.size(); i != e; ++i) { + if (i != 0) + Inner += "&"; + Inner += Args[i].getTypeAsString(); + } + return Inner; + } + + virtual void makeTypedMatcher(MatcherOps &Ops) const { + Ops.constructVariadicOperator(Func, Args); + } + +private: + const ast_matchers::internal::VariadicOperatorFunction Func; + const std::vector Args; +}; + VariantMatcher::VariantMatcher() {} VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) { @@ -110,6 +132,12 @@ VariantMatcher::PolymorphicMatcher(ArrayRef Matchers) { return VariantMatcher(new PolymorphicPayload(Matchers)); } +VariantMatcher VariantMatcher::VariadicOperatorMatcher( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef Args) { + return VariantMatcher(new VariadicOpPayload(Func, Args)); +} + bool VariantMatcher::getSingleMatcher(const DynTypedMatcher *&Out) const { if (Value) return Value->getSingleMatcher(Out); return false; diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp index 71b0f87e02..9116ab8a9f 100644 --- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp +++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp @@ -137,9 +137,9 @@ bool matchesRange(const SourceRange &Range, unsigned StartLine, Range.Start.Column == StartColumn && Range.End.Column == EndColumn; } -const DynTypedMatcher *getSingleMatcher(const VariantValue &value) { +const DynTypedMatcher *getSingleMatcher(const VariantValue &Value) { const DynTypedMatcher *Out; - EXPECT_TRUE(value.getMatcher().getSingleMatcher(Out)); + EXPECT_TRUE(Value.getMatcher().getSingleMatcher(Out)); return Out; } diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp index 55490a5bab..874a4f35a0 100644 --- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -261,6 +261,33 @@ TEST_F(RegistryTest, Adaptative) { EXPECT_FALSE(matches("void foo() { if (true) return; }", S)); } +TEST_F(RegistryTest, VariadicOp) { + Matcher D = constructMatcher( + "anyOf", constructMatcher("recordDecl"), + constructMatcher("namedDecl", + constructMatcher("hasName", std::string("foo")))) + .getTypedMatcher(); + + EXPECT_TRUE(matches("void foo(){}", D)); + EXPECT_TRUE(matches("struct Foo{};", D)); + EXPECT_FALSE(matches("int i = 0;", D)); + + D = constructMatcher( + "allOf", constructMatcher("recordDecl"), + constructMatcher( + "namedDecl", + constructMatcher("anyOf", + constructMatcher("hasName", std::string("Foo")), + constructMatcher("hasName", std::string("Bar"))))) + .getTypedMatcher(); + + EXPECT_FALSE(matches("void foo(){}", D)); + EXPECT_TRUE(matches("struct Foo{};", D)); + EXPECT_FALSE(matches("int i = 0;", D)); + EXPECT_TRUE(matches("class Bar{};", D)); + EXPECT_FALSE(matches("class OtherBar{};", D)); +} + TEST_F(RegistryTest, Errors) { // Incorrect argument count. OwningPtr Error(new Diagnostics()); @@ -285,6 +312,24 @@ TEST_F(RegistryTest, Errors) { EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher) != " "(Actual = Matcher)", Error->toString()); + + // Bad argument type with variadic. + Error.reset(new Diagnostics()); + EXPECT_TRUE(constructMatcher("anyOf", std::string(), Error.get()).isNull()); + EXPECT_EQ( + "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)", + Error->toString()); + Error.reset(new Diagnostics()); + EXPECT_TRUE(constructMatcher( + "recordDecl", + constructMatcher("allOf", + constructMatcher("isDerivedFrom", std::string("FOO")), + constructMatcher("isArrow")), + Error.get()).isNull()); + EXPECT_EQ("Incorrect type for arg 1. " + "(Expected = Matcher) != " + "(Actual = Matcher&Matcher)", + Error->toString()); } } // end anonymous namespace