[clang] [lldb] [clang] Add -ast-dump-filter-path to filter AST dump by file path (PR #194266)
Taufiq Rahman via cfe-commits
cfe-commits at lists.llvm.org
Thu May 7 20:03:57 PDT 2026
https://github.com/Inconnu08 updated https://github.com/llvm/llvm-project/pull/194266
>From 8f40a567340e4ba298b5dae0d315993a87e1f0bf Mon Sep 17 00:00:00 2001
From: inconnu08 <taufiqrx8 at gmail.com>
Date: Sun, 26 Apr 2026 16:41:03 -0400
Subject: [PATCH 1/2] [clang] Add -ast-dump-filter-path to filter AST dump by
file path
---
clang/include/clang/Frontend/ASTConsumers.h | 11 ++--
.../include/clang/Frontend/FrontendOptions.h | 3 +
clang/include/clang/Options/Options.td | 7 ++
clang/lib/Frontend/ASTConsumers.cpp | 65 ++++++++++++++-----
clang/lib/Frontend/FrontendActions.cpp | 6 +-
clang/tools/clang-check/ClangCheck.cpp | 1 +
.../clang-import-test/clang-import-test.cpp | 2 +-
.../TypeSystem/Clang/TypeSystemClang.cpp | 1 +
8 files changed, 70 insertions(+), 26 deletions(-)
diff --git a/clang/include/clang/Frontend/ASTConsumers.h b/clang/include/clang/Frontend/ASTConsumers.h
index 890701b6ff188..0650f16df3aab 100644
--- a/clang/include/clang/Frontend/ASTConsumers.h
+++ b/clang/include/clang/Frontend/ASTConsumers.h
@@ -32,13 +32,14 @@ std::unique_ptr<ASTConsumer> CreateASTPrinter(std::unique_ptr<raw_ostream> OS,
// stream, or stdout if OS is nullptr.
std::unique_ptr<ASTConsumer>
CreateASTDumper(std::unique_ptr<raw_ostream> OS, StringRef FilterString,
- bool DumpDecls, bool Deserialize, bool DumpLookups,
- bool DumpDeclTypes, ASTDumpOutputFormat Format);
+ StringRef FilterPath, bool DumpDecls, bool Deserialize,
+ bool DumpLookups, bool DumpDeclTypes,
+ ASTDumpOutputFormat Format);
std::unique_ptr<ASTConsumer>
-CreateASTDumper(raw_ostream &OS, StringRef FilterString, bool DumpDecls,
- bool Deserialize, bool DumpLookups, bool DumpDeclTypes,
- ASTDumpOutputFormat Format);
+CreateASTDumper(raw_ostream &OS, StringRef FilterString, StringRef FilterPath,
+ bool DumpDecls, bool Deserialize, bool DumpLookups,
+ bool DumpDeclTypes, ASTDumpOutputFormat Format);
// AST Decl node lister: prints qualified names of all filterable AST Decl
// nodes.
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index f7f51bc37c98d..0da947bc57741 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -451,6 +451,9 @@ class FrontendOptions {
/// If given, filter dumped AST Decl nodes by this substring.
std::string ASTDumpFilter;
+ /// If given, filter dumped AST Decl nodes by source file path (glob pattern).
+ std::string ASTDumpFilterPath;
+
/// If given, enable code completion at the provided location.
ParsedSourceLocation CodeCompletionAt;
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index c16c41ad4057d..10c52e3eb7855 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -8700,6 +8700,13 @@ def ast_dump_filter : Separate<["-"], "ast-dump-filter">,
MarshallingInfoString<FrontendOpts<"ASTDumpFilter">>;
def ast_dump_filter_EQ : Joined<["-"], "ast-dump-filter=">,
Alias<ast_dump_filter>;
+def ast_dump_filter_path : Separate<["-"], "ast-dump-filter-path">,
+ MetaVarName<"<path_filter>">,
+ HelpText<"Use with -ast-dump or -ast-print to dump/print only AST declaration"
+ " nodes whose source file path matches a glob pattern.">,
+ MarshallingInfoString<FrontendOpts<"ASTDumpFilterPath">>;
+def ast_dump_filter_path_EQ : Joined<["-"], "ast-dump-filter-path=">,
+ Alias<ast_dump_filter_path>;
def fno_modules_global_index : Flag<["-"], "fno-modules-global-index">,
HelpText<"Do not automatically generate or update the global module index">,
MarshallingInfoNegativeFlag<FrontendOpts<"UseGlobalModuleIndex">>;
diff --git a/clang/lib/Frontend/ASTConsumers.cpp b/clang/lib/Frontend/ASTConsumers.cpp
index 67c8761511e0c..31f114910a722 100644
--- a/clang/lib/Frontend/ASTConsumers.cpp
+++ b/clang/lib/Frontend/ASTConsumers.cpp
@@ -17,8 +17,11 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Diagnostic.h"
-#include "llvm/Support/Timer.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/GlobPattern.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Timer.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -33,22 +36,24 @@ namespace {
enum Kind { DumpFull, Dump, Print, None };
ASTPrinter(std::unique_ptr<raw_ostream> Out, Kind K,
ASTDumpOutputFormat Format, StringRef FilterString,
- bool DumpLookups = false, bool DumpDeclTypes = false)
+ StringRef FilterPath, bool DumpLookups = false,
+ bool DumpDeclTypes = false)
: Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)),
OutputKind(K), OutputFormat(Format), FilterString(FilterString),
- DumpLookups(DumpLookups), DumpDeclTypes(DumpDeclTypes) {}
+ FilterPath(FilterPath), DumpLookups(DumpLookups),
+ DumpDeclTypes(DumpDeclTypes) {}
ASTPrinter(raw_ostream &Out, Kind K, ASTDumpOutputFormat Format,
- StringRef FilterString, bool DumpLookups = false,
- bool DumpDeclTypes = false)
+ StringRef FilterString, StringRef FilterPath,
+ bool DumpLookups = false, bool DumpDeclTypes = false)
: Out(Out), OwnedOut(nullptr), OutputKind(K), OutputFormat(Format),
- FilterString(FilterString), DumpLookups(DumpLookups),
- DumpDeclTypes(DumpDeclTypes) {}
+ FilterString(FilterString), FilterPath(FilterPath),
+ DumpLookups(DumpLookups), DumpDeclTypes(DumpDeclTypes) {}
void HandleTranslationUnit(ASTContext &Context) override {
TranslationUnitDecl *D = Context.getTranslationUnitDecl();
- if (FilterString.empty())
+ if (FilterString.empty() && FilterPath.empty())
return print(D);
TraverseDecl(D);
@@ -83,7 +88,28 @@ namespace {
return "";
}
bool filterMatches(Decl *D) {
- return getName(D).find(FilterString) != std::string::npos;
+ if (!FilterString.empty() &&
+ getName(D).find(FilterString) == std::string::npos)
+ return false;
+
+ if (!FilterPath.empty()) {
+ const SourceManager &SM = D->getASTContext().getSourceManager();
+
+ SourceLocation Loc = SM.getSpellingLoc(D->getLocation());
+ if (Loc.isInvalid())
+ return false;
+
+ auto Pattern = llvm::GlobPattern::create(FilterPath);
+ if (!Pattern) {
+ llvm::consumeError(Pattern.takeError());
+ return false;
+ }
+
+ if (!Pattern->match(SM.getFilename(Loc)))
+ return false;
+ }
+
+ return true;
}
void print(Decl *D) {
if (DumpLookups) {
@@ -132,6 +158,9 @@ namespace {
/// Which declarations or DeclContexts to display.
std::string FilterString;
+ /// Which source file paths to display.
+ std::string FilterPath;
+
/// Whether the primary output is lookup results or declarations. Individual
/// results will be output with a format determined by OutputKind. This is
/// incompatible with OutputKind == Print.
@@ -168,32 +197,34 @@ std::unique_ptr<ASTConsumer>
clang::CreateASTPrinter(std::unique_ptr<raw_ostream> Out,
StringRef FilterString) {
return std::make_unique<ASTPrinter>(std::move(Out), ASTPrinter::Print,
- ADOF_Default, FilterString);
+ ADOF_Default, FilterString, "");
}
std::unique_ptr<ASTConsumer>
clang::CreateASTDumper(std::unique_ptr<raw_ostream> Out, StringRef FilterString,
- bool DumpDecls, bool Deserialize, bool DumpLookups,
+ StringRef FilterPath, bool DumpDecls,
+ bool Deserialize, bool DumpLookups,
bool DumpDeclTypes, ASTDumpOutputFormat Format) {
assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");
return std::make_unique<ASTPrinter>(
std::move(Out),
Deserialize ? ASTPrinter::DumpFull
: DumpDecls ? ASTPrinter::Dump : ASTPrinter::None,
- Format, FilterString, DumpLookups, DumpDeclTypes);
+ Format, FilterString, FilterPath, DumpLookups, DumpDeclTypes);
}
std::unique_ptr<ASTConsumer>
-clang::CreateASTDumper(raw_ostream &Out, StringRef FilterString, bool DumpDecls,
- bool Deserialize, bool DumpLookups, bool DumpDeclTypes,
- ASTDumpOutputFormat Format) {
+clang::CreateASTDumper(raw_ostream &Out, StringRef FilterString,
+ StringRef FilterPath, bool DumpDecls,
+ bool Deserialize, bool DumpLookups,
+ bool DumpDeclTypes, ASTDumpOutputFormat Format) {
assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");
return std::make_unique<ASTPrinter>(Out,
Deserialize ? ASTPrinter::DumpFull
: DumpDecls ? ASTPrinter::Dump
: ASTPrinter::None,
- Format, FilterString, DumpLookups,
- DumpDeclTypes);
+ Format, FilterString, FilterPath,
+ DumpLookups, DumpDeclTypes);
}
std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() {
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index 007393fa857e1..852391e135558 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -105,9 +105,9 @@ std::unique_ptr<ASTConsumer>
ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
const FrontendOptions &Opts = CI.getFrontendOpts();
return CreateASTDumper(nullptr /*Dump to stdout.*/, Opts.ASTDumpFilter,
- Opts.ASTDumpDecls, Opts.ASTDumpAll,
- Opts.ASTDumpLookups, Opts.ASTDumpDeclTypes,
- Opts.ASTDumpFormat);
+ Opts.ASTDumpFilterPath, Opts.ASTDumpDecls,
+ Opts.ASTDumpAll, Opts.ASTDumpLookups,
+ Opts.ASTDumpDeclTypes, Opts.ASTDumpFormat);
}
std::unique_ptr<ASTConsumer>
diff --git a/clang/tools/clang-check/ClangCheck.cpp b/clang/tools/clang-check/ClangCheck.cpp
index 7672b59b35482..eee50759671bc 100644
--- a/clang/tools/clang-check/ClangCheck.cpp
+++ b/clang/tools/clang-check/ClangCheck.cpp
@@ -178,6 +178,7 @@ class ClangCheckActionFactory {
return clang::CreateASTDeclNodeLister();
if (ASTDump)
return clang::CreateASTDumper(nullptr /*Dump to stdout.*/, ASTDumpFilter,
+ /*FilterPath=*/"",
/*DumpDecls=*/true,
/*Deserialize=*/false,
/*DumpLookups=*/false,
diff --git a/clang/tools/clang-import-test/clang-import-test.cpp b/clang/tools/clang-import-test/clang-import-test.cpp
index 8e83687d3e96a..489651953e1d4 100644
--- a/clang/tools/clang-import-test/clang-import-test.cpp
+++ b/clang/tools/clang-import-test/clang-import-test.cpp
@@ -325,7 +325,7 @@ llvm::Expected<CIAndOrigins> Parse(const std::string &Path,
auto &CG = *static_cast<CodeGenerator *>(ASTConsumers.back().get());
if (ShouldDumpAST)
- ASTConsumers.push_back(CreateASTDumper(nullptr /*Dump to stdout.*/, "",
+ ASTConsumers.push_back(CreateASTDumper(nullptr /*Dump to stdout.*/, "", "",
true, false, false, false,
clang::ADOF_Default));
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index e63d247c01d11..d83878eb08b6b 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -8493,6 +8493,7 @@ void TypeSystemClang::Dump(llvm::raw_ostream &output, llvm::StringRef filter,
auto consumer =
clang::CreateASTDumper(output, filter,
+ /*FilterPath=*/"",
/*DumpDecls=*/true,
/*Deserialize=*/false,
/*DumpLookups=*/false,
>From a0f074bff54297f9bc0a5e803a0f34a2c8d07d92 Mon Sep 17 00:00:00 2001
From: inconnu08 <taufiqrx8 at gmail.com>
Date: Thu, 7 May 2026 23:03:39 -0400
Subject: [PATCH 2/2] [clang] Address review feedback: use presumed loc, add
tests and release note
---
clang/docs/ReleaseNotes.rst | 5 +++++
clang/include/clang/Options/Options.td | 2 +-
clang/lib/Frontend/ASTConsumers.cpp | 11 ++++++++---
clang/test/AST/ast-dump-filter-path-include.c | 7 +++++++
clang/test/AST/ast-dump-filter-path.c | 8 ++++++++
clang/test/AST/filter-header.h | 1 +
6 files changed, 30 insertions(+), 4 deletions(-)
create mode 100644 clang/test/AST/ast-dump-filter-path-include.c
create mode 100644 clang/test/AST/ast-dump-filter-path.c
create mode 100644 clang/test/AST/filter-header.h
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index c5c8c1fa12e7a..9d2bf095262d2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -457,6 +457,11 @@ Improvements to Clang's diagnostics
- Removed the body of lambdas from some diagnostic messages.
+- Added a new ``-ast-dump-filter-path`` option to filter AST dump output
+ based on the source file path of declarations. The filter uses glob-style
+ matching on the presumed source location (accounting for macro expansions
+ and ``#line`` directives).
+
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 10c52e3eb7855..f6b26d34aac95 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -8702,7 +8702,7 @@ def ast_dump_filter_EQ : Joined<["-"], "ast-dump-filter=">,
Alias<ast_dump_filter>;
def ast_dump_filter_path : Separate<["-"], "ast-dump-filter-path">,
MetaVarName<"<path_filter>">,
- HelpText<"Use with -ast-dump or -ast-print to dump/print only AST declaration"
+ HelpText<"Use with '-ast-dump' or '-ast-print' to dump/print only AST declaration"
" nodes whose source file path matches a glob pattern.">,
MarshallingInfoString<FrontendOpts<"ASTDumpFilterPath">>;
def ast_dump_filter_path_EQ : Joined<["-"], "ast-dump-filter-path=">,
diff --git a/clang/lib/Frontend/ASTConsumers.cpp b/clang/lib/Frontend/ASTConsumers.cpp
index 31f114910a722..1c9f8c3198487 100644
--- a/clang/lib/Frontend/ASTConsumers.cpp
+++ b/clang/lib/Frontend/ASTConsumers.cpp
@@ -95,17 +95,22 @@ namespace {
if (!FilterPath.empty()) {
const SourceManager &SM = D->getASTContext().getSourceManager();
- SourceLocation Loc = SM.getSpellingLoc(D->getLocation());
+ SourceLocation Loc = D->getLocation();
if (Loc.isInvalid())
return false;
- auto Pattern = llvm::GlobPattern::create(FilterPath);
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+ if (PLoc.isInvalid())
+ return false;
+
+ llvm::Expected<llvm::GlobPattern> Pattern =
+ llvm::GlobPattern::create(FilterPath);
if (!Pattern) {
llvm::consumeError(Pattern.takeError());
return false;
}
- if (!Pattern->match(SM.getFilename(Loc)))
+ if (!Pattern->match(PLoc.getFilename()))
return false;
}
diff --git a/clang/test/AST/ast-dump-filter-path-include.c b/clang/test/AST/ast-dump-filter-path-include.c
new file mode 100644
index 0000000000000..97a82302285d7
--- /dev/null
+++ b/clang/test/AST/ast-dump-filter-path-include.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -ast-dump -ast-dump-filter-path %s %s | FileCheck %s
+
+#include "filter-header.h"
+
+MAKE_VAR(z)
+
+// CHECK: VarDecl {{.*}} z
diff --git a/clang/test/AST/ast-dump-filter-path.c b/clang/test/AST/ast-dump-filter-path.c
new file mode 100644
index 0000000000000..d24eeea52d3b1
--- /dev/null
+++ b/clang/test/AST/ast-dump-filter-path.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -ast-dump -ast-dump-filter-path "*ast-dump-filter-path.c" %s | FileCheck %s
+
+int x;
+// CHECK: VarDecl {{.*}} x
+
+#define MAKE_VAR(name) int name;
+MAKE_VAR(y)
+// CHECK: VarDecl {{.*}} y
\ No newline at end of file
diff --git a/clang/test/AST/filter-header.h b/clang/test/AST/filter-header.h
new file mode 100644
index 0000000000000..8b54743ed8692
--- /dev/null
+++ b/clang/test/AST/filter-header.h
@@ -0,0 +1 @@
+#define MAKE_VAR(name) int name;
More information about the cfe-commits
mailing list