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 @@ -93,13 +93,26 @@ /// \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; + virtual void *constructFrom(const DynTypedMatcher &Matcher) const = 0; + void *constructVariadicOperator( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef InnerMatchers); + + private: + /// \brief Constructs a variadic typed matcher from \p M. + /// Returns a Matcher* as a void*. + virtual void *constructVariadicOperator( ast_matchers::internal::VariadicOperatorFunction Func, - ArrayRef InnerMatchers) = 0; + ArrayRef M) const = 0; + /// \brief Constructs a DynTypedMatcher out of \p M. + /// \p M is a Matcher* as a void* and will be deleted by this function. + virtual DynTypedMatcher dynamicConstructFromConsume(void *M) const = 0; + + ast_type_traits::ASTNodeKind NodeKind; }; /// \brief Payload interface to be specialized by each matcher type. @@ -110,7 +123,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 +171,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 +196,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 +212,47 @@ private: explicit VariantMatcher(Payload *Value) : Value(Value) {} + template struct TypedMatcherOps; + + template + ast_matchers::internal::Matcher* maybeGetTypedMatcher() const { + if (!Value) return nullptr; + TypedMatcherOps Ops; + 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::TypedMatcherOps : VariantMatcher::MatcherOps { + TypedMatcherOps() + : MatcherOps(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; } + void *constructFrom(const DynTypedMatcher &Matcher) const override { + return new MatcherT(Matcher.convertTo()); + } - private: - std::unique_ptr Out; - }; + DynTypedMatcher dynamicConstructFromConsume(void *M) const override { + MatcherT *TypedM = static_cast(M); + DynTypedMatcher Out = *TypedM; + delete TypedM; + return Out; + } - IntrusiveRefCntPtr Value; + void *constructVariadicOperator( + ast_matchers::internal::VariadicOperatorFunction Func, + ArrayRef InnerMatchers) const override { + 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,30 @@ return true; } -VariantMatcher::MatcherOps::~MatcherOps() {} +bool +VariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher, + bool &IsExactMatch) const { + IsExactMatch = Matcher.getSupportedKind().isSame(NodeKind); + return Matcher.canConvertTo(NodeKind); +} + +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(dynamicConstructFromConsume(Inner)); + } + return constructVariadicOperator(Func, DynMatchers); +} + VariantMatcher::Payload::~Payload() {} class VariantMatcher::SinglePayload : public VariantMatcher::Payload { @@ -65,10 +88,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 +128,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 +148,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 +190,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,