[ASTMatchers] Add traversal-kind support to DynTypedMatcher
Summary: 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. Reviewers: gribozavr, steveire Subscribers: hokein, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D80685
This commit is contained in:
parent
8e325cfc14
commit
04a96aa3e4
4 changed files with 74 additions and 0 deletions
|
@ -395,6 +395,12 @@ public:
|
|||
/// 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 &DynNode, ASTMatchFinder *Finder,
|
||||
BoundNodesTreeBuilder *Builder) const;
|
||||
|
@ -458,6 +464,14 @@ public:
|
|||
/// If it is not compatible, then this matcher will never match anything.
|
||||
template <typename T> Matcher<T> 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 llvm::None is returned.
|
||||
llvm::Optional<clang::TraversalKind> getTraversalKind() const {
|
||||
return Implementation->TraversalKind();
|
||||
}
|
||||
|
||||
private:
|
||||
DynTypedMatcher(ASTNodeKind SupportedKind, ASTNodeKind RestrictKind,
|
||||
IntrusiveRefCntPtr<DynMatcherInterface> Implementation)
|
||||
|
|
|
@ -136,6 +136,31 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// 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<DynMatcherInterface> InnerMatcher)
|
||||
: TK(TK), InnerMatcher(std::move(InnerMatcher)) {}
|
||||
|
||||
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 TK;
|
||||
}
|
||||
|
||||
private:
|
||||
clang::TraversalKind TK;
|
||||
IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance;
|
||||
|
@ -204,6 +229,14 @@ DynTypedMatcher::constructRestrictedWrapper(const DynTypedMatcher &InnerMatcher,
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -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 @@ TEST(Matcher, matchOverEntireASTContext) {
|
|||
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"))));
|
||||
|
|
|
@ -30,4 +30,9 @@ clang_target_link_libraries(ASTMatchersTests
|
|||
clangTooling
|
||||
)
|
||||
|
||||
target_link_libraries(ASTMatchersTests
|
||||
PRIVATE
|
||||
LLVMTestingSupport
|
||||
)
|
||||
|
||||
add_subdirectory(Dynamic)
|
||||
|
|
Loading…
Reference in a new issue