[ASTMatchers] Make it possible to build mapAnyOf through the registry

This commit is contained in:
Stephen Kelly 2021-02-07 00:09:41 +00:00
parent d3bccdcd50
commit 45e210dbeb
4 changed files with 120 additions and 0 deletions

View File

@ -33,6 +33,23 @@ namespace internal {
class MatcherDescriptor;
/// A smart (owning) pointer for MatcherDescriptor. We can't use unique_ptr
/// because MatcherDescriptor is forward declared
class MatcherDescriptorPtr {
public:
explicit MatcherDescriptorPtr(MatcherDescriptor *);
~MatcherDescriptorPtr();
MatcherDescriptorPtr(MatcherDescriptorPtr &&) = default;
MatcherDescriptorPtr &operator=(MatcherDescriptorPtr &&) = default;
MatcherDescriptorPtr(const MatcherDescriptorPtr &) = delete;
MatcherDescriptorPtr &operator=(const MatcherDescriptorPtr &) = delete;
MatcherDescriptor *get() { return Ptr; }
private:
MatcherDescriptor *Ptr;
};
} // namespace internal
using MatcherCtor = const internal::MatcherDescriptor *;
@ -68,6 +85,12 @@ public:
static ASTNodeKind nodeMatcherType(MatcherCtor);
static bool isBuilderMatcher(MatcherCtor Ctor);
static internal::MatcherDescriptorPtr
buildMatcherCtor(MatcherCtor, SourceRange NameRange,
ArrayRef<ParserValue> Args, Diagnostics *Error);
/// Look up a matcher in the registry by name,
///
/// \return An opaque value which may be used to refer to the matcher

View File

@ -311,6 +311,14 @@ public:
virtual ASTNodeKind nodeMatcherType() const { return ASTNodeKind(); }
virtual bool isBuilderMatcher() const { return false; }
virtual std::unique_ptr<MatcherDescriptor>
buildMatcherCtor(SourceRange NameRange, ArrayRef<ParserValue> Args,
Diagnostics *Error) const {
return {};
}
/// Returns whether the matcher is variadic. Variadic matchers can take any
/// number of arguments, but they must be of the same type.
virtual bool isVariadic() const = 0;
@ -996,6 +1004,62 @@ public:
}
};
class MapAnyOfBuilderDescriptor : public MatcherDescriptor {
public:
VariantMatcher create(SourceRange, ArrayRef<ParserValue>,
Diagnostics *) const override {
return {};
}
bool isBuilderMatcher() const override { return true; }
std::unique_ptr<MatcherDescriptor>
buildMatcherCtor(SourceRange, ArrayRef<ParserValue> Args,
Diagnostics *) const override {
std::vector<ASTNodeKind> NodeKinds;
for (auto Arg : Args) {
if (!Arg.Value.isNodeKind())
return {};
NodeKinds.push_back(Arg.Value.getNodeKind());
}
if (NodeKinds.empty())
return {};
ASTNodeKind CladeNodeKind = NodeKinds.front().getCladeKind();
for (auto NK : NodeKinds)
{
if (!NK.getCladeKind().isSame(CladeNodeKind))
return {};
}
return std::make_unique<MapAnyOfMatcherDescriptor>(CladeNodeKind,
NodeKinds);
}
bool isVariadic() const override { return true; }
unsigned getNumArgs() const override { return 0; }
void getArgKinds(ASTNodeKind ThisKind, unsigned,
std::vector<ArgKind> &ArgKinds) const override {
ArgKinds.push_back(ArgKind::MakeNodeArg(ThisKind));
return;
}
bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity = nullptr,
ASTNodeKind *LeastDerivedKind = nullptr) const override {
if (Specificity)
*Specificity = 1;
if (LeastDerivedKind)
*LeastDerivedKind = Kind;
return true;
}
bool isPolymorphic() const override { return false; }
};
/// Helper functions to select the appropriate marshaller functions.
/// They detect the number of arguments, arguments types and return type.

View File

@ -102,6 +102,9 @@ RegistryMaps::RegistryMaps() {
// Other:
// equalsNode
registerMatcher("mapAnyOf",
std::make_unique<internal::MapAnyOfBuilderDescriptor>());
REGISTER_OVERLOADED_2(callee);
REGISTER_OVERLOADED_2(hasAnyCapture);
REGISTER_OVERLOADED_2(hasPrefix);
@ -566,6 +569,22 @@ ASTNodeKind Registry::nodeMatcherType(MatcherCtor Ctor) {
return Ctor->nodeMatcherType();
}
internal::MatcherDescriptorPtr::MatcherDescriptorPtr(MatcherDescriptor *Ptr)
: Ptr(Ptr) {}
internal::MatcherDescriptorPtr::~MatcherDescriptorPtr() { delete Ptr; }
bool Registry::isBuilderMatcher(MatcherCtor Ctor) {
return Ctor->isBuilderMatcher();
}
internal::MatcherDescriptorPtr
Registry::buildMatcherCtor(MatcherCtor Ctor, SourceRange NameRange,
ArrayRef<ParserValue> Args, Diagnostics *Error) {
return internal::MatcherDescriptorPtr(
Ctor->buildMatcherCtor(NameRange, Args, Error).release());
}
// static
llvm::Optional<MatcherCtor> Registry::lookupMatcherCtor(StringRef MatcherName) {
auto it = RegistryData->constructors().find(MatcherName);

View File

@ -497,6 +497,20 @@ TEST_F(RegistryTest, Completion) {
"Matcher<CXXRecordDecl> isSameOrDerivedFrom(string|Matcher<NamedDecl>)"));
}
TEST_F(RegistryTest, MatcherBuilder) {
auto Ctor = *lookupMatcherCtor("mapAnyOf");
EXPECT_TRUE(Registry::isBuilderMatcher(Ctor));
auto BuiltCtor = Registry::buildMatcherCtor(Ctor, {}, Args(ASTNodeKind::getFromNodeKind<WhileStmt>(), ASTNodeKind::getFromNodeKind<ForStmt>()), nullptr);
EXPECT_TRUE(BuiltCtor.get());
auto LoopMatcher = Registry::constructMatcher(BuiltCtor.get(), SourceRange(), Args(), nullptr).getTypedMatcher<Stmt>();
EXPECT_TRUE(matches("void f() { for (;;) {} }", LoopMatcher));
EXPECT_TRUE(matches("void f() { while (true) {} }", LoopMatcher));
EXPECT_FALSE(matches("void f() { if (true) {} }", LoopMatcher));
auto NotBuiltCtor = Registry::buildMatcherCtor(Ctor, {}, Args(ASTNodeKind::getFromNodeKind<FunctionDecl>(), ASTNodeKind::getFromNodeKind<ForStmt>()), nullptr);
EXPECT_FALSE(NotBuiltCtor.get());
}
TEST_F(RegistryTest, NodeType) {
EXPECT_TRUE(Registry::nodeMatcherType(*lookupMatcherCtor("callExpr")).isSame(ASTNodeKind::getFromNodeKind<CallExpr>()));
EXPECT_TRUE(Registry::nodeMatcherType(*lookupMatcherCtor("has")).isNone());