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

Reply via email to