[clang] 11983bf - [clang][ASTMatchers] Share variadic dyn-cast matcher marshalling (#202941)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 1 07:58:25 PDT 2026
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 <aaron at aaronballman.com>
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",
More information about the cfe-commits
mailing list