[PATCH] D80685: [ASTMatchers] Add traversal-kind support to `DynTypedMatcher`
This revision was automatically updated to reflect the committed changes. ymandel marked an inline comment as done. Closed by commit rG04a96aa3e430: [ASTMatchers] Add traversal-kind support to `DynTypedMatcher` (authored by ymandel). Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D80685/new/ https://reviews.llvm.org/D80685 Files: clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/lib/ASTMatchers/ASTMatchersInternal.cpp clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp clang/unittests/ASTMatchers/CMakeLists.txt Index: clang/unittests/ASTMatchers/CMakeLists.txt === --- clang/unittests/ASTMatchers/CMakeLists.txt +++ clang/unittests/ASTMatchers/CMakeLists.txt @@ -30,4 +30,9 @@ clangTooling ) +target_link_libraries(ASTMatchersTests + PRIVATE + LLVMTestingSupport +) + add_subdirectory(Dynamic) Index: clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp === --- clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp @@ -13,10 +13,12 @@ #include "clang/Tooling/Tooling.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Host.h" +#include "llvm/Testing/Support/SupportHelpers.h" #include "gtest/gtest.h" namespace clang { namespace ast_matchers { +using internal::DynTypedMatcher; #if GTEST_HAS_DEATH_TEST TEST(HasNameDeathTest, DiesOnEmptyName) { @@ -171,6 +173,26 @@ EXPECT_NE(nullptr, PT); } +TEST(DynTypedMatcherTest, TraversalKindForwardsToImpl) { + auto M = DynTypedMatcher(decl()); + EXPECT_FALSE(M.getTraversalKind().hasValue()); + + M = DynTypedMatcher(traverse(TK_AsIs, decl())); + EXPECT_THAT(M.getTraversalKind(), llvm::ValueIs(TK_AsIs)); +} + +TEST(DynTypedMatcherTest, ConstructWithTraversalKindSetsTK) { + auto M = DynTypedMatcher(decl()).withTraversalKind(TK_AsIs); + EXPECT_THAT(M.getTraversalKind(), llvm::ValueIs(TK_AsIs)); +} + +TEST(DynTypedMatcherTest, ConstructWithTraversalKindOverridesNestedTK) { + auto M = DynTypedMatcher(decl()).withTraversalKind(TK_AsIs).withTraversalKind( + TK_IgnoreUnlessSpelledInSource); + EXPECT_THAT(M.getTraversalKind(), + llvm::ValueIs(TK_IgnoreUnlessSpelledInSource)); +} + TEST(IsInlineMatcher, IsInline) { EXPECT_TRUE(matches("void g(); inline void f();", functionDecl(isInline(), hasName("f"; Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp === --- clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -136,6 +136,31 @@ } }; +/// A matcher that specifies a particular \c TraversalKind. +/// +/// The kind provided to the constructor overrides any kind that may be +/// specified by the `InnerMatcher`. +class DynTraversalMatcherImpl : public DynMatcherInterface { +public: + explicit DynTraversalMatcherImpl( + clang::TraversalKind TK, + IntrusiveRefCntPtr InnerMatcher) + : TK(TK), InnerMatcher(std::move(InnerMatcher)) {} + + bool dynMatches(const DynTypedNode , ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { +return this->InnerMatcher->dynMatches(DynNode, Finder, Builder); + } + + llvm::Optional TraversalKind() const override { +return TK; + } + +private: + clang::TraversalKind TK; + IntrusiveRefCntPtr InnerMatcher; +}; + } // namespace static llvm::ManagedStatic TrueMatcherInstance; @@ -204,6 +229,14 @@ return Copy; } +DynTypedMatcher +DynTypedMatcher::withTraversalKind(ast_type_traits::TraversalKind TK) { + auto Copy = *this; + Copy.Implementation = + new DynTraversalMatcherImpl(TK, std::move(Copy.Implementation)); + return Copy; +} + DynTypedMatcher DynTypedMatcher::trueMatcher(ASTNodeKind NodeKind) { return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance); } Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h === --- clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -395,6 +395,12 @@ /// restricts the node types for \p Kind. DynTypedMatcher dynCastTo(const ASTNodeKind Kind) const; + /// Return a matcher that that points to the same implementation, but sets the + /// traversal kind. + /// + /// If the traversal kind is already set, then \c TK overrides it. + DynTypedMatcher withTraversalKind(TraversalKind TK); + /// Returns true if the matcher matches the given \c DynNode. bool matches(const DynTypedNode , ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const; @@ -458,6 +464,14 @@ /// If it is not compatible, then this matcher will never match anything. template Matcher unconditionalConvertTo() const; + /// Returns the \c
[PATCH] D80685: [ASTMatchers] Add traversal-kind support to `DynTypedMatcher`
ymandel marked 2 inline comments as done. ymandel added inline comments. Comment at: clang/lib/ASTMatchers/ASTMatchersInternal.cpp:234 +DynTypedMatcher::constructWithTraversalKind(DynTypedMatcher InnerMatcher, +ast_type_traits::TraversalKind TK) { + InnerMatcher.Implementation = gribozavr2 wrote: > It might read better as an instance method on `DynTypedMatcher`: > `DynTypedMatcher::withTraversalKind()`. It is not unprecedented, see > `dynCastTo()`. Agreed, thanks for the suggestion. Comment at: clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp:182 + EXPECT_TRUE(TK.hasValue()); + EXPECT_EQ(*TK, TK_AsIs); +} gribozavr2 wrote: > Please use `EXPECT_THAT(M.getTraversalKind(), llvm::ValueIs(TK_AsIs));` (also > in tests below). > > You'll need to include `llvm/Testing/Support/SupportHelpers.h`. Thanks! This cleaned up the tests quite nicely. I also updated the CMake file. Please let me know if that looks right to you. Cargo-culted from other cmake files... Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D80685/new/ https://reviews.llvm.org/D80685 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D80685: [ASTMatchers] Add traversal-kind support to `DynTypedMatcher`
ymandel updated this revision to Diff 266828. ymandel marked 2 inline comments as done. ymandel added a comment. Herald added a subscriber: mgorny. updated per comments Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D80685/new/ https://reviews.llvm.org/D80685 Files: clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/lib/ASTMatchers/ASTMatchersInternal.cpp clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp clang/unittests/ASTMatchers/CMakeLists.txt Index: clang/unittests/ASTMatchers/CMakeLists.txt === --- clang/unittests/ASTMatchers/CMakeLists.txt +++ clang/unittests/ASTMatchers/CMakeLists.txt @@ -30,4 +30,9 @@ clangTooling ) +target_link_libraries(ASTMatchersTests + PRIVATE + LLVMTestingSupport +) + add_subdirectory(Dynamic) Index: clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp === --- clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp @@ -13,10 +13,12 @@ #include "clang/Tooling/Tooling.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Host.h" +#include "llvm/Testing/Support/SupportHelpers.h" #include "gtest/gtest.h" namespace clang { namespace ast_matchers { +using internal::DynTypedMatcher; #if GTEST_HAS_DEATH_TEST TEST(HasNameDeathTest, DiesOnEmptyName) { @@ -171,6 +173,26 @@ EXPECT_NE(nullptr, PT); } +TEST(DynTypedMatcherTest, TraversalKindForwardsToImpl) { + auto M = DynTypedMatcher(decl()); + EXPECT_FALSE(M.getTraversalKind().hasValue()); + + M = DynTypedMatcher(traverse(TK_AsIs, decl())); + EXPECT_THAT(M.getTraversalKind(), llvm::ValueIs(TK_AsIs)); +} + +TEST(DynTypedMatcherTest, ConstructWithTraversalKindSetsTK) { + auto M = DynTypedMatcher(decl()).withTraversalKind(TK_AsIs); + EXPECT_THAT(M.getTraversalKind(), llvm::ValueIs(TK_AsIs)); +} + +TEST(DynTypedMatcherTest, ConstructWithTraversalKindOverridesNestedTK) { + auto M = DynTypedMatcher(decl()).withTraversalKind(TK_AsIs).withTraversalKind( + TK_IgnoreUnlessSpelledInSource); + EXPECT_THAT(M.getTraversalKind(), + llvm::ValueIs(TK_IgnoreUnlessSpelledInSource)); +} + TEST(IsInlineMatcher, IsInline) { EXPECT_TRUE(matches("void g(); inline void f();", functionDecl(isInline(), hasName("f"; Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp === --- clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -136,6 +136,31 @@ } }; +/// A matcher that specifies a particular \c TraversalKind. +/// +/// The kind provided to the constructor overrides any kind that may be +/// specified by the `InnerMatcher`. +class DynTraversalMatcherImpl : public DynMatcherInterface { +public: + explicit DynTraversalMatcherImpl( + clang::TraversalKind TK, + IntrusiveRefCntPtr InnerMatcher) + : TK(TK), InnerMatcher(std::move(InnerMatcher)) {} + + bool dynMatches(const DynTypedNode , ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { +return this->InnerMatcher->dynMatches(DynNode, Finder, Builder); + } + + llvm::Optional TraversalKind() const override { +return TK; + } + +private: + clang::TraversalKind TK; + IntrusiveRefCntPtr InnerMatcher; +}; + } // namespace static llvm::ManagedStatic TrueMatcherInstance; @@ -204,6 +229,14 @@ return Copy; } +DynTypedMatcher +DynTypedMatcher::withTraversalKind(ast_type_traits::TraversalKind TK) { + auto Copy = *this; + Copy.Implementation = + new DynTraversalMatcherImpl(TK, std::move(Copy.Implementation)); + return Copy; +} + DynTypedMatcher DynTypedMatcher::trueMatcher(ASTNodeKind NodeKind) { return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance); } Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h === --- clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -395,6 +395,12 @@ /// restricts the node types for \p Kind. DynTypedMatcher dynCastTo(const ASTNodeKind Kind) const; + /// Return a matcher that that points to the same implementation, but sets the + /// traversal kind. + /// + /// If the traversal kind is already set, then \c TK overrides it. + DynTypedMatcher withTraversalKind(TraversalKind TK); + /// Returns true if the matcher matches the given \c DynNode. bool matches(const DynTypedNode , ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const; @@ -458,6 +464,14 @@ /// If it is not compatible, then this matcher will never match anything. template Matcher unconditionalConvertTo() const; + /// Returns the \c TraversalKind respected by calls to `match()`, if any. + /// +
[PATCH] D80685: [ASTMatchers] Add traversal-kind support to `DynTypedMatcher`
gribozavr2 accepted this revision. gribozavr2 added inline comments. This revision is now accepted and ready to land. Comment at: clang/lib/ASTMatchers/ASTMatchersInternal.cpp:234 +DynTypedMatcher::constructWithTraversalKind(DynTypedMatcher InnerMatcher, +ast_type_traits::TraversalKind TK) { + InnerMatcher.Implementation = It might read better as an instance method on `DynTypedMatcher`: `DynTypedMatcher::withTraversalKind()`. It is not unprecedented, see `dynCastTo()`. Comment at: clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp:182 + EXPECT_TRUE(TK.hasValue()); + EXPECT_EQ(*TK, TK_AsIs); +} Please use `EXPECT_THAT(M.getTraversalKind(), llvm::ValueIs(TK_AsIs));` (also in tests below). You'll need to include `llvm/Testing/Support/SupportHelpers.h`. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D80685/new/ https://reviews.llvm.org/D80685 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D80685: [ASTMatchers] Add traversal-kind support to `DynTypedMatcher`
ymandel created this revision. ymandel added reviewers: gribozavr, steveire. Herald added a project: clang. This patch exposes `TraversalKind` support in the `DynTypedMatcher` API. While previously, the `match` method supported traversal logic, it was not possible to set or get the traversal kind. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D80685 Files: clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/lib/ASTMatchers/ASTMatchersInternal.cpp clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp Index: clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp === --- clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp @@ -17,6 +17,7 @@ namespace clang { namespace ast_matchers { +using internal::DynTypedMatcher; #if GTEST_HAS_DEATH_TEST TEST(HasNameDeathTest, DiesOnEmptyName) { @@ -171,6 +172,34 @@ EXPECT_NE(nullptr, PT); } +TEST(DynTypedMatcherTest, TraversalKindForwardsToImpl) { + auto M = DynTypedMatcher(decl()); + EXPECT_FALSE(M.getTraversalKind().hasValue()); + + M = DynTypedMatcher(traverse(TK_AsIs, decl())); + llvm::Optional TK = M.getTraversalKind(); + EXPECT_TRUE(TK.hasValue()); + EXPECT_EQ(*TK, TK_AsIs); +} + +TEST(DynTypedMatcherTest, ConstructWithTraversalKindSetsTK) { + auto M = DynTypedMatcher::constructWithTraversalKind(DynTypedMatcher(decl()), + TK_AsIs); + llvm::Optional TK = M.getTraversalKind(); + EXPECT_TRUE(TK.hasValue()); + EXPECT_EQ(*TK, TK_AsIs); +} + +TEST(DynTypedMatcherTest, ConstructWithTraversalKindOverridesNestedTK) { + auto M = DynTypedMatcher::constructWithTraversalKind(DynTypedMatcher(decl()), + TK_AsIs); + auto M2 = DynTypedMatcher::constructWithTraversalKind( + M, TK_IgnoreUnlessSpelledInSource); + llvm::Optional TK = M2.getTraversalKind(); + EXPECT_TRUE(TK.hasValue()); + EXPECT_EQ(*TK, TK_IgnoreUnlessSpelledInSource); +} + TEST(IsInlineMatcher, IsInline) { EXPECT_TRUE(matches("void g(); inline void f();", functionDecl(isInline(), hasName("f"; Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp === --- clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -136,6 +136,31 @@ } }; +/// A matcher that specifies a particular \c TraversalKind. +/// +/// The kind provided to the constructor overrides any kind that may be +/// specified by the `InnerMatcher`. +class DynTraversalMatcherImpl : public DynMatcherInterface { +public: + explicit DynTraversalMatcherImpl( + clang::TraversalKind TK, + IntrusiveRefCntPtr InnerMatcher) + : TK(TK), InnerMatcher(std::move(InnerMatcher)) {} + + bool dynMatches(const DynTypedNode , ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { +return this->InnerMatcher->dynMatches(DynNode, Finder, Builder); + } + + llvm::Optional TraversalKind() const override { +return TK; + } + +private: + clang::TraversalKind TK; + IntrusiveRefCntPtr InnerMatcher; +}; + } // namespace static llvm::ManagedStatic TrueMatcherInstance; @@ -204,6 +229,14 @@ return Copy; } +DynTypedMatcher +DynTypedMatcher::constructWithTraversalKind(DynTypedMatcher InnerMatcher, +ast_type_traits::TraversalKind TK) { + InnerMatcher.Implementation = + new DynTraversalMatcherImpl(TK, std::move(InnerMatcher.Implementation)); + return InnerMatcher; +} + DynTypedMatcher DynTypedMatcher::trueMatcher(ASTNodeKind NodeKind) { return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance); } Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h === --- clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -379,6 +379,12 @@ constructRestrictedWrapper(const DynTypedMatcher , ASTNodeKind RestrictKind); + /// Creates a new matcher that is identical to the old one, but sets the + /// traversal kind. If `InnerMatcher` had already set a traversal kind, then + /// the new one overrides it. + static DynTypedMatcher + constructWithTraversalKind(DynTypedMatcher InnerMatcher, TraversalKind TK); + /// Get a "true" matcher for \p NodeKind. /// /// It only checks that the node is of the right kind. @@ -458,6 +464,14 @@ /// If it is not compatible, then this matcher will never match anything. template Matcher unconditionalConvertTo() const; + /// Returns the \c TraversalKind respected by calls to `match()`, if any. + /// + /// Most matchers will not have a traversal kind set, instead relying on the + /// surrounding context. For those, \c