Author: Stephen Kelly Date: 2021-02-07T15:36:15Z New Revision: 45e210dbebfae916b213e52be15c276032aeb60d
URL: https://github.com/llvm/llvm-project/commit/45e210dbebfae916b213e52be15c276032aeb60d DIFF: https://github.com/llvm/llvm-project/commit/45e210dbebfae916b213e52be15c276032aeb60d.diff LOG: [ASTMatchers] Make it possible to build mapAnyOf through the registry Added: Modified: clang/include/clang/ASTMatchers/Dynamic/Registry.h clang/lib/ASTMatchers/Dynamic/Marshallers.h clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Removed: ################################################################################ diff --git a/clang/include/clang/ASTMatchers/Dynamic/Registry.h b/clang/include/clang/ASTMatchers/Dynamic/Registry.h index 9ce77c33d6d8..f91f5fe01c4e 100644 --- a/clang/include/clang/ASTMatchers/Dynamic/Registry.h +++ b/clang/include/clang/ASTMatchers/Dynamic/Registry.h @@ -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 @@ class Registry { 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 diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/clang/lib/ASTMatchers/Dynamic/Marshallers.h index 71d7443c91ca..3ffa0d6af217 100644 --- a/clang/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h @@ -311,6 +311,14 @@ class MatcherDescriptor { 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 @@ class MapAnyOfMatcherDescriptor : public MatcherDescriptor { } }; +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. diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 908a9ee8ae62..ef5fd64a3666 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -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); diff --git a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp index 386fd523bb24..a7368d819ccd 100644 --- a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -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()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits