https://github.com/dzbarsky updated https://github.com/llvm/llvm-project/pull/202941
>From 2ee7226716f7b240eeee4bd290f5a059d46b0a0d Mon Sep 17 00:00:00 2001 From: David Zbarsky <[email protected]> Date: Wed, 10 Jun 2026 07:35:54 -0400 Subject: [PATCH] [clang][ASTMatchers] Share variadic dyn-cast matcher marshalling Replace the templated DynCastAllOfMatcherDescriptor implementation with one descriptor that stores the base and derived AST node kinds. Keep the typed conversion and dyn-cast operations in the shared implementation, including the derived-kind restriction needed for adaptive matchers. This removes 209 marshaller specializations from Registry.cpp.o. In an arm64 Release build, the two affected objects shrink by 768,528 bytes, including 551,176 bytes of loaded sections and 9,495 relocations. clang-query shrinks by 785,664 bytes unstripped and 721,456 bytes stripped, with linked text down 531,856 bytes and dyld fixups down 209. All 39 Dynamic AST matcher unit tests and all six clang-query tests pass. Behavior and command-line diagnostic corpora are byte-identical. Randomized paired benchmarks found construction 8.2% faster, parsing statistically neutral, and matcher execution neutral at +0.8% with a 95% confidence interval of -1.5% to +3.1%. --- clang/lib/ASTMatchers/Dynamic/Marshallers.cpp | 53 +++++++++++++++++++ clang/lib/ASTMatchers/Dynamic/Marshallers.h | 50 ++++++++--------- .../ASTMatchers/Dynamic/RegistryTest.cpp | 9 ++++ 3 files changed, 84 insertions(+), 28 deletions(-) diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp b/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp index 37c91abb5c839..1c4fbf6b106d6 100644 --- a/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp @@ -13,6 +13,59 @@ #include <optional> #include <string> +namespace clang::ast_matchers::dynamic::internal { + +VariantMatcher DynCastAllOfMatcherDescriptor::create(SourceRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) const { + std::vector<ast_matchers::internal::DynTypedMatcher> InnerMatchers; + InnerMatchers.reserve(Args.size()); + for (size_t I = 0; I != Args.size(); ++I) { + const ParserValue &Arg = Args[I]; + if (!Arg.Value.isMatcher() || + !Arg.Value.getMatcher().hasTypedMatcher(DerivedKind)) { + Error->addError(Arg.Range, Error->ET_RegistryWrongArgType) + << (I + 1) << ArgKind::MakeMatcherArg(DerivedKind).asString() + << Arg.Value.getTypeAsString(); + return {}; + } + InnerMatchers.push_back(Arg.Value.getMatcher() + .getTypedMatcher(DerivedKind) + .dynCastTo(DerivedKind)); + } + + ast_matchers::internal::DynTypedMatcher Result = + InnerMatchers.empty() + ? ast_matchers::internal::DynTypedMatcher::trueMatcher(DerivedKind) + : InnerMatchers.size() == 1 + ? InnerMatchers.front() + : ast_matchers::internal::DynTypedMatcher::constructVariadic( + ast_matchers::internal::DynTypedMatcher::VO_AllOf, DerivedKind, + std::move(InnerMatchers)); + Result = Result.dynCastTo(BaseKind); + Result.setAllowBind(true); + return VariantMatcher::SingleMatcher(Result); +} + +bool DynCastAllOfMatcherDescriptor::isConvertibleTo( + ASTNodeKind Kind, unsigned *Specificity, + ASTNodeKind *LeastDerivedKind) const { + if (!isRetKindConvertibleTo(ArrayRef(BaseKind), Kind, Specificity, + LeastDerivedKind)) + return false; + + // If Kind is not a base of DerivedKind, either DerivedKind is a base of Kind + // (in which case the match will always succeed) or Kind and DerivedKind are + // unrelated (in which case it will always fail), so set Specificity to 0. + if (Kind.isSame(DerivedKind) || !Kind.isBaseOf(DerivedKind)) { + if (Specificity) + *Specificity = 0; + } + return true; +} + +} // namespace clang::ast_matchers::dynamic::internal + static std::optional<std::string> getBestGuess(llvm::StringRef Search, llvm::ArrayRef<llvm::StringRef> Allowed, llvm::StringRef DropPrefix = "", unsigned MaxEditDistance = 3) { diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/clang/lib/ASTMatchers/Dynamic/Marshallers.h index 8c0ee465b3eb3..669245f5fd07a 100644 --- a/clang/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h @@ -584,37 +584,30 @@ class VariadicFuncMatcherDescriptor : public MatcherDescriptor { const ArgKind ArgsKind; }; -/// Return CK_Trivial when appropriate for VariadicDynCastAllOfMatchers. -class DynCastAllOfMatcherDescriptor : public VariadicFuncMatcherDescriptor { +/// Matcher descriptor for VariadicDynCastAllOfMatchers. +class DynCastAllOfMatcherDescriptor : public MatcherDescriptor { public: - template <typename BaseT, typename DerivedT> - DynCastAllOfMatcherDescriptor( - ast_matchers::internal::VariadicDynCastAllOfMatcher<BaseT, DerivedT> Func, - StringRef MatcherName) - : VariadicFuncMatcherDescriptor(Func, MatcherName), - DerivedKind(ASTNodeKind::getFromNodeKind<DerivedT>()) {} + DynCastAllOfMatcherDescriptor(ASTNodeKind BaseKind, ASTNodeKind DerivedKind) + : BaseKind(BaseKind), DerivedKind(DerivedKind) {} - bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity, - ASTNodeKind *LeastDerivedKind) const override { - // If Kind is not a base of DerivedKind, either DerivedKind is a base of - // Kind (in which case the match will always succeed) or Kind and - // DerivedKind are unrelated (in which case it will always fail), so set - // Specificity to 0. - if (VariadicFuncMatcherDescriptor::isConvertibleTo(Kind, Specificity, - LeastDerivedKind)) { - if (Kind.isSame(DerivedKind) || !Kind.isBaseOf(DerivedKind)) { - if (Specificity) - *Specificity = 0; - } - return true; - } else { - return false; - } + VariantMatcher create(SourceRange NameRange, ArrayRef<ParserValue> Args, + Diagnostics *Error) const override; + + bool isVariadic() const override { return true; } + unsigned getNumArgs() const override { return 0; } + + void getArgKinds(ASTNodeKind, unsigned, + std::vector<ArgKind> &Kinds) const override { + Kinds.push_back(ArgKind::MakeMatcherArg(DerivedKind)); } + bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity, + ASTNodeKind *LeastDerivedKind) const override; + ASTNodeKind nodeMatcherType() const override { return DerivedKind; } private: + const ASTNodeKind BaseKind; const ASTNodeKind DerivedKind; }; @@ -1110,10 +1103,11 @@ std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall( /// completion results for that type of matcher. template <typename BaseT, typename DerivedT> std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall( - ast_matchers::internal::VariadicDynCastAllOfMatcher<BaseT, DerivedT> - VarFunc, - StringRef MatcherName) { - return std::make_unique<DynCastAllOfMatcherDescriptor>(VarFunc, MatcherName); + ast_matchers::internal::VariadicDynCastAllOfMatcher<BaseT, DerivedT>, + StringRef) { + return std::make_unique<DynCastAllOfMatcherDescriptor>( + ASTNodeKind::getFromNodeKind<BaseT>(), + ASTNodeKind::getFromNodeKind<DerivedT>()); } /// Argument adaptative overload. diff --git a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp index 013bb912dfb8c..be9bfa9d5986b 100644 --- a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -287,6 +287,15 @@ TEST_F(RegistryTest, PolymorphicMatchers) { matches("class Foo { public: Foo(); }; Foo foo = Foo();", ConstructExpr)); } +TEST_F(RegistryTest, DynCastAllOfConvertsArgumentsToDerivedKind) { + VariantMatcher AnyDecl = VariantMatcher::SingleMatcher(decl()); + Matcher<Decl> Record = + constructMatcher("recordDecl", AnyDecl).getTypedMatcher<Decl>(); + + EXPECT_TRUE(matches("struct X {};", Record)); + EXPECT_FALSE(matches("void f();", Record)); +} + TEST_F(RegistryTest, TemplateArgument) { Matcher<Decl> HasTemplateArgument = constructMatcher( "classTemplateSpecializationDecl", _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
