Author: David Zbarsky Date: 2026-10-01T14:58:13Z New Revision: 11983bf00b67b377070742ea20d0fb7fa0414179
URL: https://github.com/llvm/llvm-project/commit/11983bf00b67b377070742ea20d0fb7fa0414179 DIFF: https://github.com/llvm/llvm-project/commit/11983bf00b67b377070742ea20d0fb7fa0414179.diff LOG: [clang][ASTMatchers] Share variadic dyn-cast matcher marshalling (#202941) Replace the templated variadic dyn-cast matcher descriptor with one implementation parameterized by base and derived AST node kinds, while preserving the typed conversion and derived-kind restriction. On arm64 Release builds, this reduces stripped `clang-query` by 721,456 bytes, the affected objects by 768,528 bytes, and object relocations by 9,495. Work towards #202616 AI tool disclosure: Co-authored with OpenAI Codex. Co-authored-by: Aaron Ballman <[email protected]> Added: Modified: clang/lib/ASTMatchers/Dynamic/Marshallers.cpp clang/lib/ASTMatchers/Dynamic/Marshallers.h clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Removed: ################################################################################ diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp b/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp index b34ae525f67fd..616c61e531808 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 b2eb51b5da2f7..1ea938d1b089f 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
