steveire created this revision. steveire added a reviewer: ymandel. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D80654 Files: clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/include/clang/ASTMatchers/Dynamic/VariantValue.h clang/lib/ASTMatchers/ASTMatchersInternal.cpp clang/lib/ASTMatchers/Dynamic/Marshallers.h clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/lib/ASTMatchers/Dynamic/VariantValue.cpp clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
Index: clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp =================================================================== --- clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -505,6 +505,25 @@ EXPECT_FALSE(matches("struct X {};", Value)); } +TEST_F(RegistryTest, Traverse) { + EXPECT_TRUE( + matches(R"cpp( +int foo() +{ + double d = 0; + return d; +} +)cpp", + constructMatcher( + "returnStmt", + constructMatcher( + "hasReturnValue", + constructMatcher("traverse", + StringRef("IgnoreUnlessSpelledInSource"), + constructMatcher("declRefExpr")))) + .getTypedMatcher<Stmt>())); +} + TEST_F(RegistryTest, ParenExpr) { Matcher<Stmt> Value = constructMatcher("parenExpr").getTypedMatcher<Stmt>(); EXPECT_TRUE( Index: clang/lib/ASTMatchers/Dynamic/VariantValue.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/VariantValue.cpp +++ clang/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -80,6 +80,44 @@ VariantMatcher::Payload::~Payload() {} +class VariantMatcher::TraversalPayload : public VariantMatcher::Payload { +public: + TraversalPayload(ast_type_traits::TraversalKind TK, + const DynTypedMatcher &Matcher) + : TK(TK), Matcher(Matcher) {} + + llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { + return Matcher; + } + + std::string getTypeAsString() const override { + return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">") + .str(); + } + + llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const override { + // llvm::errs() << "TraversalCode" << "\n"; + // std::terminate(); + + bool Ignore; + if (Ops.canConstructFrom(Matcher, Ignore)) { + return DynTypedMatcher::constructTraversalWrapper(Matcher, TK); + } + return llvm::None; + } + + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const override { + return ArgKind(Matcher.getSupportedKind()) + .isConvertibleTo(Kind, Specificity); + } + +private: + ast_type_traits::TraversalKind TK; + const DynTypedMatcher Matcher; +}; + class VariantMatcher::SinglePayload : public VariantMatcher::Payload { public: SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {} @@ -219,6 +257,12 @@ return VariantMatcher(std::make_shared<SinglePayload>(Matcher)); } +VariantMatcher +VariantMatcher::TraversalMatcher(ast_type_traits::TraversalKind TK, + const DynTypedMatcher &Matcher) { + return VariantMatcher(std::make_shared<TraversalPayload>(TK, Matcher)); +} + VariantMatcher VariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) { return VariantMatcher( Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -101,6 +101,9 @@ // Other: // equalsNode + registerMatcher("traverse", + std::make_unique<internal::TraverseMatcherDescriptor>()); + REGISTER_OVERLOADED_2(callee); REGISTER_OVERLOADED_2(hasAnyCapture); REGISTER_OVERLOADED_2(hasPrefix); Index: clang/lib/ASTMatchers/Dynamic/Marshallers.h =================================================================== --- clang/lib/ASTMatchers/Dynamic/Marshallers.h +++ clang/lib/ASTMatchers/Dynamic/Marshallers.h @@ -244,6 +244,31 @@ static llvm::Optional<std::string> getBestGuess(const VariantValue &Value); }; +template <> struct ArgTypeTraits<ast_type_traits::TraversalKind> { +private: + static Optional<ast_type_traits::TraversalKind> + getTraversalKind(llvm::StringRef TK) { + return llvm::StringSwitch<Optional<ast_type_traits::TraversalKind>>(TK) + .Case("TK::AsIs", ast_type_traits::TK_AsIs) + .Case("TK::IgnoreUnlessSpelledInSource", + ast_type_traits::TK_IgnoreUnlessSpelledInSource) + .Case("TK::IgnoreImplicitCastsAndParentheses", + ast_type_traits::TK_IgnoreImplicitCastsAndParentheses) + .Default(llvm::None); + } + +public: + static bool is(const VariantValue &Value) { + return Value.isString() && getTraversalKind(Value.getString()); + } + + static ast_type_traits::TraversalKind get(const VariantValue &Value) { + return *getTraversalKind(Value.getString()); + } + + static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } +}; + /// Matcher descriptor interface. /// /// Provides a \c create() method that constructs the matcher from the provided @@ -299,6 +324,64 @@ return false; } +class TraverseMatcherDescriptor : public MatcherDescriptor { +public: + TraverseMatcherDescriptor() {} + + VariantMatcher create(SourceRange NameRange, ArrayRef<ParserValue> Args, + Diagnostics *Error) const override { + if (Args.size() != 2) + return {}; + auto TraversalArg = Args[0].Value; + if (!TraversalArg.isString()) + return {}; + auto TraversalCode = + llvm::StringSwitch<unsigned>(TraversalArg.getString()) + .Case("AsIs", ast_type_traits::TK_AsIs) + .Case("IgnoreImplicitCastsAndParentheses", + ast_type_traits::TK_IgnoreImplicitCastsAndParentheses) + .Case("IgnoreUnlessSpelledInSource", + ast_type_traits::TK_IgnoreUnlessSpelledInSource) + .Default(~0u); + if (TraversalCode == ~0u) { + return {}; + } + auto MatcherArg = Args[1].Value; + if (!MatcherArg.isMatcher()) + return {}; + auto M = MatcherArg.getMatcher(); + if (M.isNull()) + return {}; + auto SM = M.getSingleMatcher(); + if (!SM) + return {}; + return VariantMatcher::TraversalMatcher( + static_cast<ast_type_traits::TraversalKind>(TraversalCode), *SM); + } + + bool isVariadic() const override { return false; } + unsigned getNumArgs() const override { return 2; } + + void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, + std::vector<ArgKind> &Kinds) const override { + if (ArgNo == 0) { + Kinds.push_back(ArgKind::AK_String); + return; + } + Kinds.push_back(ThisKind); + } + + bool isConvertibleTo( + ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, + ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { + return true; + // return isRetKindConvertibleTo(RetKinds, Kind, Specificity, + // LeastDerivedKind); + } + +private: +}; + /// Simple callback implementation. Marshaller and function are provided. /// /// This class wraps a function of arbitrary signature and a marshaller Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -204,6 +204,36 @@ return Copy; } +class DynTraversalMatcher : public DynMatcherInterface { +public: + explicit DynTraversalMatcher( + clang::TraversalKind TK, + IntrusiveRefCntPtr<DynMatcherInterface> ChildMatcher) + : Traversal(TK), InnerMatcher(ChildMatcher) {} + + bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return this->InnerMatcher->dynMatches(DynNode, Finder, Builder); + } + + llvm::Optional<clang::TraversalKind> TraversalKind() const override { + return Traversal; + } + +private: + clang::TraversalKind Traversal; + IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher; +}; + +DynTypedMatcher +DynTypedMatcher::constructTraversalWrapper(const DynTypedMatcher &InnerMatcher, + TraversalKind TK) { + DynTypedMatcher Copy = InnerMatcher; + Copy.Implementation = + new DynTraversalMatcher(TK, std::move(Copy.Implementation)); + return Copy; +} + DynTypedMatcher DynTypedMatcher::trueMatcher(ASTNodeKind NodeKind) { return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance); } Index: clang/include/clang/ASTMatchers/Dynamic/VariantValue.h =================================================================== --- clang/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ clang/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -138,6 +138,9 @@ /// Clones the provided matcher. static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher); + static VariantMatcher TraversalMatcher(ast_type_traits::TraversalKind TK, + const DynTypedMatcher &Matcher); + /// Clones the provided matchers. /// /// They should be the result of a polymorphic matcher. @@ -214,6 +217,7 @@ template <typename T> struct TypedMatcherOps; class SinglePayload; + class TraversalPayload; class PolymorphicPayload; class VariadicOpPayload; Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -379,6 +379,10 @@ constructRestrictedWrapper(const DynTypedMatcher &InnerMatcher, ASTNodeKind RestrictKind); + static DynTypedMatcher + constructTraversalWrapper(const DynTypedMatcher &InnerMatcher, + ast_type_traits::TraversalKind TK); + /// Get a "true" matcher for \p NodeKind. /// /// It only checks that the node is of the right kind.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits