[lldb] Add filter option to AST dump command (#142164)
Depends on https://github.com/llvm/llvm-project/pull/142163 This patch makes the `-ast-dump-filter` Clang option available to the `target modules dump ast` command. This allows us to selectively dump parts of the AST by name. The AST can quickly grow way too large to skim on the console. This will aid in debugging AST related issues. Example: ``` (lldb) target modules dump ast --filter func Dumping clang ast for 48 modules. Dumping func: FunctionDecl 0xc4b785008 <<invalid sloc>> <invalid sloc> func 'void (int)' extern |-ParmVarDecl 0xc4b7853d8 <<invalid sloc>> <invalid sloc> x 'int' `-AsmLabelAttr 0xc4b785358 <<invalid sloc>> Implicit "_Z4funcIiEvT_" Dumping func<int>: FunctionDecl 0xc4b7850b8 <<invalid sloc>> <invalid sloc> func<int> 'void (int)' implicit_instantiation extern |-TemplateArgument type 'int' | `-BuiltinType 0xc4b85b110 'int' `-ParmVarDecl 0xc4b7853d8 <<invalid sloc>> <invalid sloc> x 'int' ``` The majority of this patch is adjust the `Dump` API. The main change in behaviour is in `TypeSystemClang::Dump`, where we now use the `ASTPrinter` for dumping the `TranslationUnitDecl`. This is where the `-ast-dump-filter` functionality lives in Clang.
This commit is contained in:
parent
b5cf030332
commit
0f7e10b027
@ -296,7 +296,7 @@ public:
|
||||
lldb::SymbolContextItem resolve_scope,
|
||||
SymbolContextList &sc_list);
|
||||
|
||||
virtual void DumpClangAST(Stream &s) {}
|
||||
virtual void DumpClangAST(Stream &s, llvm::StringRef filter) {}
|
||||
virtual void FindGlobalVariables(ConstString name,
|
||||
const CompilerDeclContext &parent_decl_ctx,
|
||||
uint32_t max_matches,
|
||||
|
@ -127,7 +127,7 @@ public:
|
||||
lldb_private::SymbolContextList &sc_list) override;
|
||||
|
||||
void Dump(lldb_private::Stream &s) override;
|
||||
void DumpClangAST(lldb_private::Stream &s) override;
|
||||
void DumpClangAST(lldb_private::Stream &s, llvm::StringRef filter) override;
|
||||
|
||||
void
|
||||
FindGlobalVariables(lldb_private::ConstString name,
|
||||
|
@ -443,7 +443,11 @@ public:
|
||||
/// given stream.
|
||||
///
|
||||
/// This should not modify the state of the TypeSystem if possible.
|
||||
virtual void Dump(llvm::raw_ostream &output) = 0;
|
||||
///
|
||||
/// \param[out] output Stream to dup the AST into.
|
||||
/// \param[in] filter If empty, dump whole AST. If non-empty, will only
|
||||
/// dump decls whose names contain \c filter.
|
||||
virtual void Dump(llvm::raw_ostream &output, llvm::StringRef filter) = 0;
|
||||
|
||||
/// This is used by swift.
|
||||
virtual bool IsRuntimeGeneratedType(lldb::opaque_compiler_type_t type) = 0;
|
||||
|
@ -2235,11 +2235,23 @@ public:
|
||||
: CommandObjectTargetModulesModuleAutoComplete(
|
||||
interpreter, "target modules dump ast",
|
||||
"Dump the clang ast for a given module's symbol file.",
|
||||
//"target modules dump ast [<file1> ...]")
|
||||
nullptr, eCommandRequiresTarget) {}
|
||||
"target modules dump ast [--filter <name>] [<file1> ...]",
|
||||
eCommandRequiresTarget),
|
||||
m_filter(LLDB_OPT_SET_1, false, "filter", 'f', 0, eArgTypeName,
|
||||
"Dump only the decls whose names contain the specified filter "
|
||||
"string.",
|
||||
/*default_value=*/"") {
|
||||
m_option_group.Append(&m_filter, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
|
||||
m_option_group.Finalize();
|
||||
}
|
||||
|
||||
Options *GetOptions() override { return &m_option_group; }
|
||||
|
||||
~CommandObjectTargetModulesDumpClangAST() override = default;
|
||||
|
||||
OptionGroupOptions m_option_group;
|
||||
OptionGroupString m_filter;
|
||||
|
||||
protected:
|
||||
void DoExecute(Args &command, CommandReturnObject &result) override {
|
||||
Target &target = GetTarget();
|
||||
@ -2251,6 +2263,8 @@ protected:
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::StringRef filter = m_filter.GetOptionValue().GetCurrentValueAsRef();
|
||||
|
||||
if (command.GetArgumentCount() == 0) {
|
||||
// Dump all ASTs for all modules images
|
||||
result.GetOutputStream().Format("Dumping clang ast for {0} modules.\n",
|
||||
@ -2259,7 +2273,7 @@ protected:
|
||||
if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted dumping clang ast"))
|
||||
break;
|
||||
if (SymbolFile *sf = module_sp->GetSymbolFile())
|
||||
sf->DumpClangAST(result.GetOutputStream());
|
||||
sf->DumpClangAST(result.GetOutputStream(), filter);
|
||||
}
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
return;
|
||||
@ -2288,7 +2302,7 @@ protected:
|
||||
|
||||
Module *m = module_list.GetModulePointerAtIndex(i);
|
||||
if (SymbolFile *sf = m->GetSymbolFile())
|
||||
sf->DumpClangAST(result.GetOutputStream());
|
||||
sf->DumpClangAST(result.GetOutputStream(), filter);
|
||||
}
|
||||
}
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
@ -5272,7 +5286,7 @@ protected:
|
||||
// Go over every scratch TypeSystem and dump to the command output.
|
||||
for (lldb::TypeSystemSP ts : GetTarget().GetScratchTypeSystems())
|
||||
if (ts)
|
||||
ts->Dump(result.GetOutputStream().AsRawOstream());
|
||||
ts->Dump(result.GetOutputStream().AsRawOstream(), "");
|
||||
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
}
|
||||
|
@ -4127,7 +4127,7 @@ void SymbolFileDWARF::Dump(lldb_private::Stream &s) {
|
||||
m_index->Dump(s);
|
||||
}
|
||||
|
||||
void SymbolFileDWARF::DumpClangAST(Stream &s) {
|
||||
void SymbolFileDWARF::DumpClangAST(Stream &s, llvm::StringRef filter) {
|
||||
auto ts_or_err = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
|
||||
if (!ts_or_err)
|
||||
return;
|
||||
@ -4135,7 +4135,7 @@ void SymbolFileDWARF::DumpClangAST(Stream &s) {
|
||||
TypeSystemClang *clang = llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
|
||||
if (!clang)
|
||||
return;
|
||||
clang->Dump(s.AsRawOstream());
|
||||
clang->Dump(s.AsRawOstream(), filter);
|
||||
}
|
||||
|
||||
bool SymbolFileDWARF::GetSeparateDebugInfo(StructuredData::Dictionary &d,
|
||||
|
@ -276,7 +276,7 @@ public:
|
||||
|
||||
void Dump(Stream &s) override;
|
||||
|
||||
void DumpClangAST(Stream &s) override;
|
||||
void DumpClangAST(Stream &s, llvm::StringRef filter) override;
|
||||
|
||||
/// List separate dwo files.
|
||||
bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
|
||||
|
@ -1267,9 +1267,9 @@ CompilerDeclContext SymbolFileDWARFDebugMap::FindNamespace(
|
||||
return matching_namespace;
|
||||
}
|
||||
|
||||
void SymbolFileDWARFDebugMap::DumpClangAST(Stream &s) {
|
||||
ForEachSymbolFile("Dumping clang AST", [&s](SymbolFileDWARF &oso_dwarf) {
|
||||
oso_dwarf.DumpClangAST(s);
|
||||
void SymbolFileDWARFDebugMap::DumpClangAST(Stream &s, llvm::StringRef filter) {
|
||||
ForEachSymbolFile("Dumping clang AST", [&](SymbolFileDWARF &oso_dwarf) {
|
||||
oso_dwarf.DumpClangAST(s, filter);
|
||||
// The underlying assumption is that DumpClangAST(...) will obtain the
|
||||
// AST from the underlying TypeSystem and therefore we only need to do
|
||||
// this once and can stop after the first iteration hence we return true.
|
||||
|
@ -129,7 +129,7 @@ public:
|
||||
std::vector<std::unique_ptr<CallEdge>>
|
||||
ParseCallEdgesInFunction(UserID func_id) override;
|
||||
|
||||
void DumpClangAST(Stream &s) override;
|
||||
void DumpClangAST(Stream &s, llvm::StringRef filter) override;
|
||||
|
||||
/// List separate oso files.
|
||||
bool GetSeparateDebugInfo(StructuredData::Dictionary &d,
|
||||
|
@ -1449,6 +1449,6 @@ PdbAstBuilder::FromCompilerDeclContext(CompilerDeclContext context) {
|
||||
return static_cast<clang::DeclContext *>(context.GetOpaqueDeclContext());
|
||||
}
|
||||
|
||||
void PdbAstBuilder::Dump(Stream &stream) {
|
||||
m_clang.Dump(stream.AsRawOstream());
|
||||
void PdbAstBuilder::Dump(Stream &stream, llvm::StringRef filter) {
|
||||
m_clang.Dump(stream.AsRawOstream(), filter);
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ public:
|
||||
TypeSystemClang &clang() { return m_clang; }
|
||||
ClangASTImporter &GetClangASTImporter() { return m_importer; }
|
||||
|
||||
void Dump(Stream &stream);
|
||||
void Dump(Stream &stream, llvm::StringRef filter);
|
||||
|
||||
private:
|
||||
clang::Decl *TryGetDecl(PdbSymUid uid) const;
|
||||
|
@ -1630,7 +1630,7 @@ size_t SymbolFileNativePDB::ParseSymbolArrayInScope(
|
||||
return count;
|
||||
}
|
||||
|
||||
void SymbolFileNativePDB::DumpClangAST(Stream &s) {
|
||||
void SymbolFileNativePDB::DumpClangAST(Stream &s, llvm::StringRef filter) {
|
||||
auto ts_or_err = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
|
||||
if (!ts_or_err)
|
||||
return;
|
||||
@ -1638,7 +1638,7 @@ void SymbolFileNativePDB::DumpClangAST(Stream &s) {
|
||||
TypeSystemClang *clang = llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
|
||||
if (!clang)
|
||||
return;
|
||||
clang->GetNativePDBParser()->Dump(s);
|
||||
clang->GetNativePDBParser()->Dump(s, filter);
|
||||
}
|
||||
|
||||
void SymbolFileNativePDB::FindGlobalVariables(
|
||||
|
@ -157,7 +157,7 @@ public:
|
||||
|
||||
PdbIndex &GetIndex() { return *m_index; };
|
||||
|
||||
void DumpClangAST(Stream &s) override;
|
||||
void DumpClangAST(Stream &s, llvm::StringRef filter) override;
|
||||
|
||||
std::optional<llvm::codeview::TypeIndex>
|
||||
GetParentType(llvm::codeview::TypeIndex ti);
|
||||
|
@ -1431,7 +1431,7 @@ void SymbolFilePDB::AddSymbols(lldb_private::Symtab &symtab) {
|
||||
symtab.Finalize();
|
||||
}
|
||||
|
||||
void SymbolFilePDB::DumpClangAST(Stream &s) {
|
||||
void SymbolFilePDB::DumpClangAST(Stream &s, llvm::StringRef filter) {
|
||||
auto type_system_or_err =
|
||||
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
|
||||
if (auto err = type_system_or_err.takeError()) {
|
||||
@ -1445,7 +1445,7 @@ void SymbolFilePDB::DumpClangAST(Stream &s) {
|
||||
llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
|
||||
if (!clang_type_system)
|
||||
return;
|
||||
clang_type_system->Dump(s.AsRawOstream());
|
||||
clang_type_system->Dump(s.AsRawOstream(), filter);
|
||||
}
|
||||
|
||||
void SymbolFilePDB::FindTypesByRegex(
|
||||
|
@ -157,7 +157,7 @@ public:
|
||||
|
||||
const llvm::pdb::IPDBSession &GetPDBSession() const;
|
||||
|
||||
void DumpClangAST(lldb_private::Stream &s) override;
|
||||
void DumpClangAST(lldb_private::Stream &s, llvm::StringRef filter) override;
|
||||
|
||||
private:
|
||||
struct SecContribInfo {
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/Frontend/ASTConsumers.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/FormatAdapters.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
@ -8499,8 +8500,16 @@ TypeSystemClang::dump(lldb::opaque_compiler_type_t type) const {
|
||||
}
|
||||
#endif
|
||||
|
||||
void TypeSystemClang::Dump(llvm::raw_ostream &output) {
|
||||
GetTranslationUnitDecl()->dump(output);
|
||||
void TypeSystemClang::Dump(llvm::raw_ostream &output, llvm::StringRef filter) {
|
||||
auto consumer =
|
||||
clang::CreateASTDumper(output, filter,
|
||||
/*DumpDecls=*/true,
|
||||
/*Deserialize=*/false,
|
||||
/*DumpLookups=*/false,
|
||||
/*DumpDeclTypes=*/false, clang::ADOF_Default);
|
||||
assert(consumer);
|
||||
assert(m_ast_up);
|
||||
consumer->HandleTranslationUnit(*m_ast_up);
|
||||
}
|
||||
|
||||
void TypeSystemClang::DumpFromSymbolFile(Stream &s,
|
||||
@ -9625,10 +9634,11 @@ GetNameForIsolatedASTKind(ScratchTypeSystemClang::IsolatedASTKind kind) {
|
||||
llvm_unreachable("Unimplemented IsolatedASTKind?");
|
||||
}
|
||||
|
||||
void ScratchTypeSystemClang::Dump(llvm::raw_ostream &output) {
|
||||
void ScratchTypeSystemClang::Dump(llvm::raw_ostream &output,
|
||||
llvm::StringRef filter) {
|
||||
// First dump the main scratch AST.
|
||||
output << "State of scratch Clang type system:\n";
|
||||
TypeSystemClang::Dump(output);
|
||||
TypeSystemClang::Dump(output, filter);
|
||||
|
||||
// Now sort the isolated sub-ASTs.
|
||||
typedef std::pair<IsolatedASTKey, TypeSystem *> KeyAndTS;
|
||||
@ -9643,7 +9653,7 @@ void ScratchTypeSystemClang::Dump(llvm::raw_ostream &output) {
|
||||
static_cast<ScratchTypeSystemClang::IsolatedASTKind>(a.first);
|
||||
output << "State of scratch Clang type subsystem "
|
||||
<< GetNameForIsolatedASTKind(kind) << ":\n";
|
||||
a.second->Dump(output);
|
||||
a.second->Dump(output, filter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1074,7 +1074,7 @@ public:
|
||||
#endif
|
||||
|
||||
/// \see lldb_private::TypeSystem::Dump
|
||||
void Dump(llvm::raw_ostream &output) override;
|
||||
void Dump(llvm::raw_ostream &output, llvm::StringRef filter) override;
|
||||
|
||||
/// Dump clang AST types from the symbol file.
|
||||
///
|
||||
@ -1318,7 +1318,7 @@ public:
|
||||
}
|
||||
|
||||
/// \see lldb_private::TypeSystem::Dump
|
||||
void Dump(llvm::raw_ostream &output) override;
|
||||
void Dump(llvm::raw_ostream &output, llvm::StringRef filter) override;
|
||||
|
||||
UserExpression *GetUserExpression(llvm::StringRef expr,
|
||||
llvm::StringRef prefix,
|
||||
|
@ -305,13 +305,14 @@ void SymbolFileOnDemand::Dump(lldb_private::Stream &s) {
|
||||
return m_sym_file_impl->Dump(s);
|
||||
}
|
||||
|
||||
void SymbolFileOnDemand::DumpClangAST(lldb_private::Stream &s) {
|
||||
void SymbolFileOnDemand::DumpClangAST(lldb_private::Stream &s,
|
||||
llvm::StringRef filter) {
|
||||
if (!m_debug_info_enabled) {
|
||||
LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(),
|
||||
__FUNCTION__);
|
||||
return;
|
||||
}
|
||||
return m_sym_file_impl->DumpClangAST(s);
|
||||
return m_sym_file_impl->DumpClangAST(s, filter);
|
||||
}
|
||||
|
||||
void SymbolFileOnDemand::FindGlobalVariables(const RegularExpression ®ex,
|
||||
|
70
lldb/test/Shell/Commands/command-image-dump-ast.test
Normal file
70
lldb/test/Shell/Commands/command-image-dump-ast.test
Normal file
@ -0,0 +1,70 @@
|
||||
# Test `image dump ast` command.
|
||||
|
||||
# RUN: split-file %s %t
|
||||
# RUN: %clang_host -g -gdwarf %t/main.cpp -o %t.out
|
||||
# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
|
||||
# RUN: | FileCheck %s
|
||||
|
||||
#--- main.cpp
|
||||
|
||||
void A() {}
|
||||
void A1() {}
|
||||
void BA1() {}
|
||||
void AB() {}
|
||||
|
||||
int main() {
|
||||
A();
|
||||
A1();
|
||||
BA1();
|
||||
AB();
|
||||
}
|
||||
|
||||
#--- commands.input
|
||||
|
||||
break set -n main
|
||||
run
|
||||
expr A(); A1(); BA1(); AB()
|
||||
|
||||
image dump ast
|
||||
|
||||
# CHECK: image dump ast
|
||||
# CHECK-DAG: FunctionDecl {{.*}} main
|
||||
# CHECK-DAG: FunctionDecl {{.*}} A
|
||||
# CHECK-DAG: FunctionDecl {{.*}} A1
|
||||
# CHECK-DAG: FunctionDecl {{.*}} BA1
|
||||
# CHECK-DAG: FunctionDecl {{.*}} AB
|
||||
|
||||
image dump ast --filter A
|
||||
|
||||
# CHECK: image dump ast --filter A
|
||||
# CHECK: Dumping A
|
||||
# CHECK-NOT: FunctionDecl {{.*}} main
|
||||
# CHECK-DAG: FunctionDecl {{.*}} A1
|
||||
# CHECK-DAG: FunctionDecl {{.*}} BA1
|
||||
# CHECK-DAG: FunctionDecl {{.*}} AB
|
||||
|
||||
image dump ast --filter A1
|
||||
|
||||
# CHECK: image dump ast --filter A1
|
||||
# CHECK: Dumping A
|
||||
# CHECK-NOT: FunctionDecl {{.*}} main
|
||||
# CHECK-NOT: FunctionDecl {{.*}} AB
|
||||
# CHECK-DAG: FunctionDecl {{.*}} A1
|
||||
# CHECK-DAG: FunctionDecl {{.*}} BA1
|
||||
|
||||
image dump ast --filter ""
|
||||
|
||||
# CHECK: image dump ast --filter ""
|
||||
# CHECK-DAG: FunctionDecl {{.*}} main
|
||||
# CHECK-DAG: FunctionDecl {{.*}} AB
|
||||
# CHECK-DAG: FunctionDecl {{.*}} A1
|
||||
# CHECK-DAG: FunctionDecl {{.*}} BA1
|
||||
|
||||
image dump ast -f AB
|
||||
|
||||
# CHECK: image dump ast -f AB
|
||||
# CHECK: Dumping AB
|
||||
# CHECK-NOT: FunctionDecl {{.*}} main
|
||||
# CHECK-NOT: FunctionDecl {{.*}} A1
|
||||
# CHECK-NOT: FunctionDecl {{.*}} BA1
|
||||
# CHECK: FunctionDecl {{.*}} AB
|
Loading…
x
Reference in New Issue
Block a user