Index: include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- include/clang/ASTMatchers/ASTMatchersInternal.h +++ include/clang/ASTMatchers/ASTMatchersInternal.h @@ -372,9 +372,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. /// @@ -460,16 +460,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 @@ -90,16 +90,36 @@ /// - hasTypedMatcher()/getTypedMatcher(): These calls will determine if /// the underlying matcher(s) can unambiguously return a Matcher. class VariantMatcher { + /// \brief VTable used for type specific logic. + struct UntypedOps { + /// \brief Constructs a typed matcher from \p M. + /// Returns a Matcher* as a void*. + void *(*ConstructFrom)(const DynTypedMatcher &M); + /// \brief Constructs a variadic typed matcher from \p M. + /// Returns a Matcher* as a void*. + void *(*ConstructVariadicOperator)( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef M); + /// \brief Constructs a DynTypedMatcher out of \p M. + /// \p M is a Matcher* as a void* and will be deleted by this function. + DynTypedMatcher (*DynamicConstructFromConsume)(void *M); + ast_type_traits::ASTNodeKind NodeKind; + }; + /// \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(const UntypedOps &Ops) : Ops(Ops) {} + + bool canConstructFrom(const DynTypedMatcher &Matcher, + bool &IsExactMatch) const; + void *constructFrom(const DynTypedMatcher &Matcher); + void *constructVariadicOperator( ast_matchers::internal::VariadicOperatorFunction Func, - ArrayRef InnerMatchers) = 0; + ArrayRef InnerMatchers); + + private: + const UntypedOps Ops; }; /// \brief Payload interface to be specialized by each matcher type. @@ -110,7 +130,7 @@ virtual ~Payload(); virtual llvm::Optional getSingleMatcher() const = 0; virtual std::string getTypeAsString() const = 0; - virtual void makeTypedMatcher(MatcherOps &Ops) const = 0; + virtual void* makeTypedMatcher(MatcherOps &Ops) const = 0; virtual bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity) const = 0; }; @@ -158,9 +178,10 @@ /// 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(); + auto *M = maybeGetTypedMatcher(); + bool Result = M != nullptr; + delete M; + return Result; } /// \brief Determines if the contained matcher can be converted to \p Kind. @@ -182,10 +203,11 @@ /// 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(); + auto *M = maybeGetTypedMatcher(); + assert(M != nullptr && "hasTypedMatcher() == false"); + auto Result = *M; + delete M; + return Result; } /// \brief String representation of the type of the value. @@ -197,51 +219,49 @@ private: explicit VariantMatcher(Payload *Value) : Value(Value) {} + template struct TypedOps; + + template + ast_matchers::internal::Matcher* maybeGetTypedMatcher() const { + if (!Value) return nullptr; + MatcherOps Ops((TypedOps())); + return static_cast *>( + Value->makeTypedMatcher(Ops)); + } + 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(); - } + IntrusiveRefCntPtr Value; +}; - virtual void constructFrom(const DynTypedMatcher& Matcher) { - Out.reset(new MatcherT(Matcher.convertTo())); - } +template +struct VariantMatcher::TypedOps : VariantMatcher::UntypedOps { + TypedOps() + : UntypedOps{&constructFrom, &constructVariadicOperator, + &dynamicConstructFromConsume, + ast_type_traits::ASTNodeKind::getFromNodeKind()} {} + typedef ast_matchers::internal::Matcher MatcherT; - 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; } + static void* constructFrom(const DynTypedMatcher &Matcher) { + return new MatcherT(Matcher.convertTo()); + } - private: - std::unique_ptr Out; - }; + static DynTypedMatcher dynamicConstructFromConsume(void *M) { + MatcherT *TypedM = static_cast(M); + DynTypedMatcher Out = *TypedM; + delete TypedM; + return Out; + } - IntrusiveRefCntPtr Value; + static void* constructVariadicOperator( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef InnerMatchers) { + return new MatcherT( + new ast_matchers::internal::VariadicOperatorMatcherInterface( + Func, InnerMatchers)); + } }; /// \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,35 @@ return true; } -VariantMatcher::MatcherOps::~MatcherOps() {} +bool +VariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher, + bool &IsExactMatch) const { + IsExactMatch = Matcher.getSupportedKind().isSame(Ops.NodeKind); + return Matcher.canConvertTo(Ops.NodeKind); +} + +void * +VariantMatcher::MatcherOps::constructFrom(const DynTypedMatcher &Matcher) { + return Ops.ConstructFrom(Matcher); +} + +void *VariantMatcher::MatcherOps::constructVariadicOperator( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef InnerMatchers) { + 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 nullptr; + void* Inner = InnerMatcher.Value->makeTypedMatcher(*this); + if (!Inner) + return nullptr; + DynMatchers.push_back(Ops.DynamicConstructFromConsume(Inner)); + } + return Ops.ConstructVariadicOperator(Func, DynMatchers); +} + VariantMatcher::Payload::~Payload() {} class VariantMatcher::SinglePayload : public VariantMatcher::Payload { @@ -65,10 +93,11 @@ .str(); } - void makeTypedMatcher(MatcherOps &Ops) const override { + void* makeTypedMatcher(MatcherOps &Ops) const override { bool Ignore; if (Ops.canConstructFrom(Matcher, Ignore)) - Ops.constructFrom(Matcher); + return Ops.constructFrom(Matcher); + return nullptr; } bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, @@ -104,7 +133,7 @@ return (Twine("Matcher<") + Inner + ">").str(); } - void makeTypedMatcher(MatcherOps &Ops) const override { + void* makeTypedMatcher(MatcherOps &Ops) const override { bool FoundIsExact = false; const DynTypedMatcher *Found = nullptr; int NumFound = 0; @@ -124,7 +153,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 Ops.constructFrom(*Found); + return nullptr; } bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, @@ -165,8 +195,8 @@ return Inner; } - void makeTypedMatcher(MatcherOps &Ops) const override { - Ops.constructVariadicOperator(Func, Args); + void* makeTypedMatcher(MatcherOps &Ops) const override { + return Ops.constructVariadicOperator(Func, Args); } bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,