Index: include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- include/clang/ASTMatchers/ASTMatchersInternal.h +++ include/clang/ASTMatchers/ASTMatchersInternal.h @@ -342,6 +342,17 @@ /// This version enables \c tryBind() on the \c DynTypedMatcher. template inline DynTypedMatcher(const BindableMatcher &M); + /// \brief Construct from a variadic function. + typedef bool (*VariadicOperatorFunction)( + const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers); + static DynTypedMatcher + constructVariadic(VariadicOperatorFunction Func, + ArrayRef InnerMatchers) { + assert(InnerMatchers.size() > 0 && "Array must not be empty."); + return DynTypedMatcher(new VariadicStorage(Func, InnerMatchers)); + } + /// \brief Returns true if the matcher matches the given \c DynNode. bool matches(const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { @@ -372,9 +383,9 @@ /// This method verifies that the underlying matcher in \c Other can process /// nodes of types T. template bool canConvertTo() const { - return getSupportedKind().isBaseOf( - ast_type_traits::ASTNodeKind::getFromNodeKind()); + return canConvertTo(ast_type_traits::ASTNodeKind::getFromNodeKind()); } + bool canConvertTo(ast_type_traits::ASTNodeKind To) const; /// \brief Construct a \c Matcher interface around the dynamic matcher. /// @@ -416,9 +427,35 @@ const uint64_t ID; }; + class VariadicStorage : public MatcherStorage { + public: + VariadicStorage(VariadicOperatorFunction Func, + ArrayRef InnerMatchers) + : MatcherStorage(InnerMatchers[0].getSupportedKind(), + reinterpret_cast(this)), + Func(Func), InnerMatchers(InnerMatchers) {} + + bool matches(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return Func(DynNode, Finder, Builder, InnerMatchers); + } + + llvm::Optional tryBind(StringRef ID) const override { + return llvm::None; + } + + private: + VariadicOperatorFunction Func; + std::vector InnerMatchers; + }; + /// \brief Typed implementation of \c MatcherStorage. template class TypedMatcherStorage; + /// \brief Internal constructor for \c constructVariadic. + DynTypedMatcher(MatcherStorage *Storage) : Storage(Storage) {} + IntrusiveRefCntPtr Storage; }; @@ -460,16 +497,8 @@ /// \brief Specialization of the conversion functions for QualType. /// -/// These specializations provide the Matcher->Matcher +/// This specialization provides the Matcher->Matcher /// conversion that the static API does. -template <> inline bool DynTypedMatcher::canConvertTo() const { - const ast_type_traits::ASTNodeKind SourceKind = getSupportedKind(); - return SourceKind.isSame( - ast_type_traits::ASTNodeKind::getFromNodeKind()) || - SourceKind.isSame( - ast_type_traits::ASTNodeKind::getFromNodeKind()); -} - template <> inline Matcher DynTypedMatcher::convertTo() const { assert(canConvertTo()); Index: include/clang/ASTMatchers/Dynamic/VariantValue.h =================================================================== --- include/clang/ASTMatchers/Dynamic/VariantValue.h +++ include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -93,13 +93,25 @@ /// \brief Methods that depend on T from hasTypedMatcher/getTypedMatcher. class MatcherOps { public: - virtual ~MatcherOps(); - virtual bool canConstructFrom(const DynTypedMatcher &Matcher, - bool &IsExactMatch) const = 0; - virtual void constructFrom(const DynTypedMatcher &Matcher) = 0; - virtual void constructVariadicOperator( + MatcherOps(ast_type_traits::ASTNodeKind NodeKind) : NodeKind(NodeKind) {} + + bool canConstructFrom(const DynTypedMatcher &Matcher, + bool &IsExactMatch) const; + + /// \brief Convert \p Matcher the destination type and return it as a new + /// DynTypedMatcher. + virtual DynTypedMatcher + convertMatcher(const DynTypedMatcher &Matcher) const = 0; + + /// \brief Constructs a variadic typed matcher from \p InnerMatchers. + /// Will try to convert each inner matcher to the destination type and + /// return llvm::None if it fails to do so. + llvm::Optional constructVariadicOperator( ast_matchers::internal::VariadicOperatorFunction Func, - ArrayRef InnerMatchers) = 0; + ArrayRef InnerMatchers) const; + + private: + ast_type_traits::ASTNodeKind NodeKind; }; /// \brief Payload interface to be specialized by each matcher type. @@ -110,7 +122,8 @@ virtual ~Payload(); virtual llvm::Optional getSingleMatcher() const = 0; virtual std::string getTypeAsString() const = 0; - virtual void makeTypedMatcher(MatcherOps &Ops) const = 0; + virtual llvm::Optional + getTypedMatcher(const MatcherOps &Ops) const = 0; virtual bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity) const = 0; }; @@ -158,9 +171,8 @@ /// that can, the result would be ambiguous and false is returned. template bool hasTypedMatcher() const { - TypedMatcherOps Ops; - if (Value) Value->makeTypedMatcher(Ops); - return Ops.hasMatcher(); + if (!Value) return false; + return Value->getTypedMatcher(TypedMatcherOps()).hasValue(); } /// \brief Determines if the contained matcher can be converted to \p Kind. @@ -182,10 +194,9 @@ /// Asserts that \c hasTypedMatcher() is true. template ast_matchers::internal::Matcher getTypedMatcher() const { - TypedMatcherOps Ops; - Value->makeTypedMatcher(Ops); - assert(Ops.hasMatcher() && "hasTypedMatcher() == false"); - return Ops.matcher(); + assert(hasTypedMatcher() && "hasTypedMatcher() == false"); + return Value->getTypedMatcher(TypedMatcherOps()) + ->template convertTo(); } /// \brief String representation of the type of the value. @@ -197,51 +208,25 @@ private: explicit VariantMatcher(Payload *Value) : Value(Value) {} + template struct TypedMatcherOps; + class SinglePayload; class PolymorphicPayload; class VariadicOpPayload; - template - class TypedMatcherOps : public MatcherOps { - public: - typedef ast_matchers::internal::Matcher MatcherT; - - virtual bool canConstructFrom(const DynTypedMatcher &Matcher, - bool &IsExactMatch) const { - IsExactMatch = Matcher.getSupportedKind().isSame( - ast_type_traits::ASTNodeKind::getFromNodeKind()); - return Matcher.canConvertTo(); - } - - virtual void constructFrom(const DynTypedMatcher& Matcher) { - Out.reset(new MatcherT(Matcher.convertTo())); - } - - virtual void constructVariadicOperator( - ast_matchers::internal::VariadicOperatorFunction Func, - ArrayRef InnerMatchers) { - std::vector DynMatchers; - for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { - // Abort if any of the inner matchers can't be converted to - // Matcher. - if (!InnerMatchers[i].hasTypedMatcher()) { - return; - } - DynMatchers.push_back(InnerMatchers[i].getTypedMatcher()); - } - Out.reset(new MatcherT( - new ast_matchers::internal::VariadicOperatorMatcherInterface( - Func, DynMatchers))); - } - - bool hasMatcher() const { return Out.get() != nullptr; } - const MatcherT &matcher() const { return *Out; } + IntrusiveRefCntPtr Value; +}; - private: - std::unique_ptr Out; - }; +template +struct VariantMatcher::TypedMatcherOps : VariantMatcher::MatcherOps { + TypedMatcherOps() + : MatcherOps(ast_type_traits::ASTNodeKind::getFromNodeKind()) {} + typedef ast_matchers::internal::Matcher MatcherT; - IntrusiveRefCntPtr Value; + DynTypedMatcher + convertMatcher(const DynTypedMatcher &Matcher) const override { + return DynTypedMatcher(Matcher.convertTo()); + } }; /// \brief Variant value class. Index: lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- lib/ASTMatchers/ASTMatchersInternal.cpp +++ lib/ASTMatchers/ASTMatchersInternal.cpp @@ -26,6 +26,16 @@ } } +bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const { + const auto SourceKind = getSupportedKind(); + auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind(); + auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind(); + if (To.isSame(QualKind)) { + return SourceKind.isSame(TypeKind) || SourceKind.isSame(QualKind); + } + return SourceKind.isBaseOf(To); +} + DynTypedMatcher::MatcherStorage::~MatcherStorage() {} void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) { Index: lib/ASTMatchers/Dynamic/VariantValue.cpp =================================================================== --- lib/ASTMatchers/Dynamic/VariantValue.cpp +++ lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -49,7 +49,32 @@ return true; } -VariantMatcher::MatcherOps::~MatcherOps() {} +bool +VariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher, + bool &IsExactMatch) const { + IsExactMatch = Matcher.getSupportedKind().isSame(NodeKind); + return Matcher.canConvertTo(NodeKind); +} + +llvm::Optional +VariantMatcher::MatcherOps::constructVariadicOperator( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef InnerMatchers) const { + std::vector DynMatchers; + for (const auto &InnerMatcher : InnerMatchers) { + // Abort if any of the inner matchers can't be converted to + // Matcher. + if (!InnerMatcher.Value) + return llvm::None; + llvm::Optional Inner = + InnerMatcher.Value->getTypedMatcher(*this); + if (!Inner) + return llvm::None; + DynMatchers.push_back(*Inner); + } + return DynTypedMatcher::constructVariadic(Func, DynMatchers); +} + VariantMatcher::Payload::~Payload() {} class VariantMatcher::SinglePayload : public VariantMatcher::Payload { @@ -65,10 +90,12 @@ .str(); } - void makeTypedMatcher(MatcherOps &Ops) const override { + llvm::Optional + getTypedMatcher(const MatcherOps &Ops) const override { bool Ignore; if (Ops.canConstructFrom(Matcher, Ignore)) - Ops.constructFrom(Matcher); + return Matcher; + return llvm::None; } bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, @@ -104,7 +131,8 @@ return (Twine("Matcher<") + Inner + ">").str(); } - void makeTypedMatcher(MatcherOps &Ops) const override { + llvm::Optional + getTypedMatcher(const MatcherOps &Ops) const override { bool FoundIsExact = false; const DynTypedMatcher *Found = nullptr; int NumFound = 0; @@ -124,7 +152,8 @@ } // We only succeed if we found exactly one, or if we found an exact match. if (Found && (FoundIsExact || NumFound == 1)) - Ops.constructFrom(*Found); + return *Found; + return llvm::None; } bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, @@ -165,8 +194,9 @@ return Inner; } - void makeTypedMatcher(MatcherOps &Ops) const override { - Ops.constructVariadicOperator(Func, Args); + llvm::Optional + getTypedMatcher(const MatcherOps &Ops) const override { + return Ops.constructVariadicOperator(Func, Args); } bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,