[Lldb-commits] [lldb] [lldb][Formatters] Add --pointer-match-depth option to `type summary add` command. (PR #138209)
Zequan Wu via lldb-commits
lldb-commits at lists.llvm.org
Thu May 1 15:30:56 PDT 2025
https://github.com/ZequanWu created https://github.com/llvm/llvm-project/pull/138209
Currently, the type `T`'s summary formatter will be matched for `T`, `T*`, `T**` and so on. This is unexpected in many data formatters. Such unhandled cases could cause the data formatter to crash. An example would be the lldb's built-in data formatter for `std::optional`:
```
$ cat main.cpp
#include <optional>
int main() {
std::optional<int> o_null;
auto po_null = &o_null;
auto ppo_null = &po_null;
auto pppo_null = &ppo_null;
return 0;
}
$ clang++ -g main.cpp && lldb -o "b 8" -o "r" -o "v pppo_null"
[lldb crash]
```
This change adds an options `--pointer-match-depth` to `type summary add` command to allow users to specify how many layer of pointers can be dereferenced at most when matching a summary formatter of type `T`, as Jim suggested [here](https://github.com/llvm/llvm-project/pull/124048/#issuecomment-2611164133). By default, this option has value 1 which means summary formatter for `T` could also be used for `T*` but not `T**` nor beyond. This option is no-op when `--skip-pointers` is set as well.
I didn't add such option for `type synthetic add`, `type format add`, `type filter add`, because it useful for those command. Instead, they all have the pointer match depth of 1. When printing a type `T*`, lldb never print the children of `T` even if there is a synthetic formatter registered for `T`.
>From dcb5b2596267d908dea1474164a1fadf1cd23aef Mon Sep 17 00:00:00 2001
From: Zequan Wu <zequanwu at google.com>
Date: Thu, 1 May 2025 14:51:24 -0700
Subject: [PATCH] [lldb][Formatters] Add --pointer-match-depth option to "type
summary add" command.
---
lldb/include/lldb/API/SBTypeSummary.h | 4 +
.../lldb/DataFormatters/FormatClasses.h | 10 +-
.../lldb/DataFormatters/FormatManager.h | 3 +-
.../lldb/DataFormatters/FormattersContainer.h | 8 +-
lldb/include/lldb/DataFormatters/TypeFormat.h | 5 +
.../include/lldb/DataFormatters/TypeSummary.h | 17 ++-
.../lldb/DataFormatters/TypeSynthetic.h | 5 +
lldb/source/API/SBTypeSummary.cpp | 16 +++
lldb/source/Commands/CommandObjectType.cpp | 27 +++--
lldb/source/Commands/Options.td | 4 +
lldb/source/DataFormatters/FormatManager.cpp | 40 ++++---
.../source/DataFormatters/TypeCategoryMap.cpp | 5 +-
lldb/source/DataFormatters/TypeSummary.cpp | 37 ++++---
.../data-formatter-ptr-matching/Makefile | 4 +
.../TestDataFormatterPtrMatching.py | 101 ++++++++++++++++++
.../data-formatter-ptr-matching/main.cpp | 32 ++++++
16 files changed, 266 insertions(+), 52 deletions(-)
create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/Makefile
create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py
create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp
diff --git a/lldb/include/lldb/API/SBTypeSummary.h b/lldb/include/lldb/API/SBTypeSummary.h
index 40fa146b4e31b..b6869e53a39e7 100644
--- a/lldb/include/lldb/API/SBTypeSummary.h
+++ b/lldb/include/lldb/API/SBTypeSummary.h
@@ -109,6 +109,10 @@ class SBTypeSummary {
void SetFunctionCode(const char *data);
+ uint32_t GetPtrMatchDepth();
+
+ void SetPtrMatchDepth(uint32_t ptr_match_depth);
+
uint32_t GetOptions();
void SetOptions(uint32_t);
diff --git a/lldb/include/lldb/DataFormatters/FormatClasses.h b/lldb/include/lldb/DataFormatters/FormatClasses.h
index a6bc3a3542536..89d74649ecc64 100644
--- a/lldb/include/lldb/DataFormatters/FormatClasses.h
+++ b/lldb/include/lldb/DataFormatters/FormatClasses.h
@@ -76,9 +76,10 @@ class FormattersMatchCandidate {
FormattersMatchCandidate(ConstString name,
ScriptInterpreter *script_interpreter, TypeImpl type,
- Flags flags)
+ Flags flags, uint32_t ptr_stripped_depth = 0)
: m_type_name(name), m_script_interpreter(script_interpreter),
- m_type(type), m_flags(flags) {}
+ m_type(type), m_flags(flags), m_ptr_stripped_depth(ptr_stripped_depth) {
+ }
~FormattersMatchCandidate() = default;
@@ -96,6 +97,8 @@ class FormattersMatchCandidate {
bool DidStripTypedef() const { return m_flags.stripped_typedef; }
+ uint32_t GetPtrStrippedDepth() const { return m_ptr_stripped_depth; }
+
template <class Formatter>
bool IsMatch(const std::shared_ptr<Formatter> &formatter_sp) const {
if (!formatter_sp)
@@ -104,6 +107,8 @@ class FormattersMatchCandidate {
return false;
if (formatter_sp->SkipsPointers() && DidStripPointer())
return false;
+ if (formatter_sp->GetPtrMatchDepth() < GetPtrStrippedDepth())
+ return false;
if (formatter_sp->SkipsReferences() && DidStripReference())
return false;
return true;
@@ -116,6 +121,7 @@ class FormattersMatchCandidate {
ScriptInterpreter *m_script_interpreter;
TypeImpl m_type;
Flags m_flags;
+ uint32_t m_ptr_stripped_depth;
};
typedef std::vector<FormattersMatchCandidate> FormattersMatchVector;
diff --git a/lldb/include/lldb/DataFormatters/FormatManager.h b/lldb/include/lldb/DataFormatters/FormatManager.h
index db2fe99c44caf..9e24f7b722407 100644
--- a/lldb/include/lldb/DataFormatters/FormatManager.h
+++ b/lldb/include/lldb/DataFormatters/FormatManager.h
@@ -180,7 +180,8 @@ class FormatManager : public IFormatChangeListener {
lldb::DynamicValueType use_dynamic,
FormattersMatchVector &entries,
FormattersMatchCandidate::Flags current_flags,
- bool root_level = false);
+ bool root_level = false,
+ uint32_t ptr_stripped_depth = 0);
std::atomic<uint32_t> m_last_revision;
FormatCache m_format_cache;
diff --git a/lldb/include/lldb/DataFormatters/FormattersContainer.h b/lldb/include/lldb/DataFormatters/FormattersContainer.h
index 7898621fd18af..f7465fc65538d 100644
--- a/lldb/include/lldb/DataFormatters/FormattersContainer.h
+++ b/lldb/include/lldb/DataFormatters/FormattersContainer.h
@@ -193,12 +193,10 @@ template <typename ValueType> class FormattersContainer {
bool Get(const FormattersMatchVector &candidates, ValueSP &entry) {
for (const FormattersMatchCandidate &candidate : candidates) {
if (Get(candidate, entry)) {
- if (candidate.IsMatch(entry) == false) {
- entry.reset();
- continue;
- } else {
+ if (candidate.IsMatch(entry))
return true;
- }
+ entry.reset();
+ continue;
}
}
return false;
diff --git a/lldb/include/lldb/DataFormatters/TypeFormat.h b/lldb/include/lldb/DataFormatters/TypeFormat.h
index 63d4765bdf270..d242f9083d608 100644
--- a/lldb/include/lldb/DataFormatters/TypeFormat.h
+++ b/lldb/include/lldb/DataFormatters/TypeFormat.h
@@ -133,6 +133,10 @@ class TypeFormatImpl {
void SetOptions(uint32_t value) { m_flags.SetValue(value); }
+ uint32_t GetPtrMatchDepth() { return m_ptr_match_depth; }
+
+ void SetPtrMatchDepth(uint32_t value) { m_ptr_match_depth = value; }
+
uint32_t &GetRevision() { return m_my_revision; }
enum class Type { eTypeUnknown, eTypeFormat, eTypeEnum };
@@ -150,6 +154,7 @@ class TypeFormatImpl {
protected:
Flags m_flags;
uint32_t m_my_revision = 0;
+ uint32_t m_ptr_match_depth = 1;
private:
TypeFormatImpl(const TypeFormatImpl &) = delete;
diff --git a/lldb/include/lldb/DataFormatters/TypeSummary.h b/lldb/include/lldb/DataFormatters/TypeSummary.h
index f4d5563516ecb..589f68c2ce314 100644
--- a/lldb/include/lldb/DataFormatters/TypeSummary.h
+++ b/lldb/include/lldb/DataFormatters/TypeSummary.h
@@ -253,6 +253,10 @@ class TypeSummaryImpl {
void SetOptions(uint32_t value) { m_flags.SetValue(value); }
+ uint32_t GetPtrMatchDepth() { return m_ptr_match_depth; }
+
+ void SetPtrMatchDepth(uint32_t value) { m_ptr_match_depth = value; }
+
// we are using a ValueObject* instead of a ValueObjectSP because we do not
// need to hold on to this for extended periods of time and we trust the
// ValueObject to stay around for as long as it is required for us to
@@ -278,10 +282,12 @@ class TypeSummaryImpl {
uint32_t m_my_revision = 0;
Flags m_flags;
- TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags);
+ TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags,
+ uint32_t ptr_match_depth = 1);
private:
Kind m_kind;
+ uint32_t m_ptr_match_depth = 1;
TypeSummaryImpl(const TypeSummaryImpl &) = delete;
const TypeSummaryImpl &operator=(const TypeSummaryImpl &) = delete;
};
@@ -292,7 +298,8 @@ struct StringSummaryFormat : public TypeSummaryImpl {
FormatEntity::Entry m_format;
Status m_error;
- StringSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *f);
+ StringSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *f,
+ uint32_t ptr_match_depth = 1);
~StringSummaryFormat() override = default;
@@ -328,7 +335,8 @@ struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
std::string m_description;
CXXFunctionSummaryFormat(const TypeSummaryImpl::Flags &flags, Callback impl,
- const char *description);
+ const char *description,
+ uint32_t ptr_match_depth = 1);
~CXXFunctionSummaryFormat() override = default;
@@ -373,7 +381,8 @@ struct ScriptSummaryFormat : public TypeSummaryImpl {
ScriptSummaryFormat(const TypeSummaryImpl::Flags &flags,
const char *function_name,
- const char *python_script = nullptr);
+ const char *python_script = nullptr,
+ uint32_t ptr_match_depth = 1);
~ScriptSummaryFormat() override = default;
diff --git a/lldb/include/lldb/DataFormatters/TypeSynthetic.h b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
index c8d7d15588065..37f02fb8f7ce5 100644
--- a/lldb/include/lldb/DataFormatters/TypeSynthetic.h
+++ b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
@@ -273,9 +273,14 @@ class SyntheticChildren {
uint32_t &GetRevision() { return m_my_revision; }
+ uint32_t GetPtrMatchDepth() { return m_ptr_match_depth; }
+
+ void SetPtrMatchDepth(uint32_t value) { m_ptr_match_depth = value; }
+
protected:
uint32_t m_my_revision = 0;
Flags m_flags;
+ uint32_t m_ptr_match_depth = 1;
private:
SyntheticChildren(const SyntheticChildren &) = delete;
diff --git a/lldb/source/API/SBTypeSummary.cpp b/lldb/source/API/SBTypeSummary.cpp
index 856ee0ed3175b..d7acb0670018a 100644
--- a/lldb/source/API/SBTypeSummary.cpp
+++ b/lldb/source/API/SBTypeSummary.cpp
@@ -230,6 +230,22 @@ const char *SBTypeSummary::GetData() {
return nullptr;
}
+uint32_t SBTypeSummary::GetPtrMatchDepth() {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (!IsValid())
+ return 0;
+ return m_opaque_sp->GetPtrMatchDepth();
+}
+
+void SBTypeSummary::SetPtrMatchDepth(uint32_t ptr_match_depth) {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (!IsValid())
+ return;
+ return m_opaque_sp->SetPtrMatchDepth(ptr_match_depth);
+}
+
uint32_t SBTypeSummary::GetOptions() {
LLDB_INSTRUMENT_VA(this);
diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp
index 41630b61c2f0e..19cd3ff2972e9 100644
--- a/lldb/source/Commands/CommandObjectType.cpp
+++ b/lldb/source/Commands/CommandObjectType.cpp
@@ -51,12 +51,13 @@ class ScriptAddOptions {
FormatterMatchType m_match_type;
ConstString m_name;
std::string m_category;
+ uint32_t m_ptr_match_depth;
ScriptAddOptions(const TypeSummaryImpl::Flags &flags,
FormatterMatchType match_type, ConstString name,
- std::string catg)
+ std::string catg, uint32_t m_ptr_match_depth)
: m_flags(flags), m_match_type(match_type), m_name(name),
- m_category(catg) {}
+ m_category(catg), m_ptr_match_depth(m_ptr_match_depth) {}
typedef std::shared_ptr<ScriptAddOptions> SharedPointer;
};
@@ -146,6 +147,7 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
std::string m_python_function;
bool m_is_add_script = false;
std::string m_category;
+ uint32_t m_ptr_match_depth = 1;
};
CommandOptions m_options;
@@ -211,7 +213,7 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
TypeSummaryImplSP script_format;
script_format = std::make_shared<ScriptSummaryFormat>(
options->m_flags, funct_name_str.c_str(),
- lines.CopyList(" ").c_str());
+ lines.CopyList(" ").c_str(), options->m_ptr_match_depth);
Status error;
@@ -1178,6 +1180,13 @@ Status CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue(
case 'p':
m_flags.SetSkipPointers(true);
break;
+ case 'd':
+ if (option_arg.getAsInteger(0, m_ptr_match_depth)) {
+ error = Status::FromErrorStringWithFormat(
+ "invalid integer value for option '%c': %s", short_option,
+ option_arg.data());
+ }
+ break;
case 'r':
m_flags.SetSkipReferences(true);
break;
@@ -1266,7 +1275,8 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary(
(" " + m_options.m_python_function + "(valobj,internal_dict)");
script_format = std::make_shared<ScriptSummaryFormat>(
- m_options.m_flags, funct_name, code.c_str());
+ m_options.m_flags, funct_name, code.c_str(),
+ m_options.m_ptr_match_depth);
ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
@@ -1300,12 +1310,13 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary(
std::string code = " " + m_options.m_python_script;
script_format = std::make_shared<ScriptSummaryFormat>(
- m_options.m_flags, funct_name_str.c_str(), code.c_str());
+ m_options.m_flags, funct_name_str.c_str(), code.c_str(),
+ m_options.m_ptr_match_depth);
} else {
// Use an IOHandler to grab Python code from the user
auto options = std::make_unique<ScriptAddOptions>(
m_options.m_flags, m_options.m_match_type, m_options.m_name,
- m_options.m_category);
+ m_options.m_category, m_options.m_ptr_match_depth);
for (auto &entry : command.entries()) {
if (entry.ref().empty()) {
@@ -1380,8 +1391,8 @@ bool CommandObjectTypeSummaryAdd::Execute_StringSummary(
return false;
}
- std::unique_ptr<StringSummaryFormat> string_format(
- new StringSummaryFormat(m_options.m_flags, format_cstr));
+ std::unique_ptr<StringSummaryFormat> string_format(new StringSummaryFormat(
+ m_options.m_flags, format_cstr, m_options.m_ptr_match_depth));
if (!string_format) {
result.AppendError("summary creation failed");
return false;
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 53864ff29327d..9dd7467b4269c 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1240,6 +1240,10 @@ let Command = "type summary add" in {
Desc<"Don't show the value, just show the summary, for this type.">;
def type_summary_add_skip_pointers : Option<"skip-pointers", "p">,
Desc<"Don't use this format for pointers-to-type objects.">;
+ def type_summary_add_pointer_match_depth : Option<"pointer-match-depth", "d">,
+ Arg<"UnsignedInteger">,
+ Desc<"Specify the maximum pointer depth that this format can be apply to "
+ "(default to 1). It's only effective when --skip-pointers is not set.">;
def type_summary_add_skip_references : Option<"skip-references", "r">,
Desc<"Don't use this format for references-to-type objects.">;
def type_summary_add_regex : Option<"regex", "x">,
diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp
index 3b891cecb1c8b..122f2304ead24 100644
--- a/lldb/source/DataFormatters/FormatManager.cpp
+++ b/lldb/source/DataFormatters/FormatManager.cpp
@@ -174,7 +174,8 @@ void FormatManager::DisableAllCategories() {
void FormatManager::GetPossibleMatches(
ValueObject &valobj, CompilerType compiler_type,
lldb::DynamicValueType use_dynamic, FormattersMatchVector &entries,
- FormattersMatchCandidate::Flags current_flags, bool root_level) {
+ FormattersMatchCandidate::Flags current_flags, bool root_level,
+ uint32_t ptr_stripped_depth) {
compiler_type = compiler_type.GetTypeForFormatters();
ConstString type_name(compiler_type.GetTypeName());
// A ValueObject that couldn't be made correctly won't necessarily have a
@@ -190,46 +191,51 @@ void FormatManager::GetPossibleMatches(
sstring.Printf("%s:%d", type_name.AsCString(), valobj.GetBitfieldBitSize());
ConstString bitfieldname(sstring.GetString());
entries.push_back({bitfieldname, script_interpreter,
- TypeImpl(compiler_type), current_flags});
+ TypeImpl(compiler_type), current_flags,
+ ptr_stripped_depth});
}
if (!compiler_type.IsMeaninglessWithoutDynamicResolution()) {
entries.push_back({type_name, script_interpreter, TypeImpl(compiler_type),
- current_flags});
+ current_flags, ptr_stripped_depth});
ConstString display_type_name(compiler_type.GetTypeName());
if (display_type_name != type_name)
entries.push_back({display_type_name, script_interpreter,
- TypeImpl(compiler_type), current_flags});
+ TypeImpl(compiler_type), current_flags,
+ ptr_stripped_depth});
}
for (bool is_rvalue_ref = true, j = true;
j && compiler_type.IsReferenceType(nullptr, &is_rvalue_ref); j = false) {
CompilerType non_ref_type = compiler_type.GetNonReferenceType();
GetPossibleMatches(valobj, non_ref_type, use_dynamic, entries,
- current_flags.WithStrippedReference());
+ current_flags.WithStrippedReference(), root_level,
+ ptr_stripped_depth);
if (non_ref_type.IsTypedefType()) {
CompilerType deffed_referenced_type = non_ref_type.GetTypedefedType();
deffed_referenced_type =
is_rvalue_ref ? deffed_referenced_type.GetRValueReferenceType()
: deffed_referenced_type.GetLValueReferenceType();
// this is not exactly the usual meaning of stripping typedefs
- GetPossibleMatches(
- valobj, deffed_referenced_type,
- use_dynamic, entries, current_flags.WithStrippedTypedef());
+ GetPossibleMatches(valobj, deffed_referenced_type, use_dynamic, entries,
+ current_flags.WithStrippedTypedef(), root_level,
+ ptr_stripped_depth);
}
}
if (compiler_type.IsPointerType()) {
CompilerType non_ptr_type = compiler_type.GetPointeeType();
GetPossibleMatches(valobj, non_ptr_type, use_dynamic, entries,
- current_flags.WithStrippedPointer());
+ current_flags.WithStrippedPointer(), root_level,
+ ptr_stripped_depth + 1);
if (non_ptr_type.IsTypedefType()) {
CompilerType deffed_pointed_type =
non_ptr_type.GetTypedefedType().GetPointerType();
// this is not exactly the usual meaning of stripping typedefs
GetPossibleMatches(valobj, deffed_pointed_type, use_dynamic, entries,
- current_flags.WithStrippedTypedef());
+ current_flags.WithStrippedTypedef(), root_level,
+ ptr_stripped_depth + 1);
}
}
@@ -246,9 +252,9 @@ void FormatManager::GetPossibleMatches(
CompilerType deffed_array_type =
element_type.GetTypedefedType().GetArrayType(array_size);
// this is not exactly the usual meaning of stripping typedefs
- GetPossibleMatches(
- valobj, deffed_array_type,
- use_dynamic, entries, current_flags.WithStrippedTypedef());
+ GetPossibleMatches(valobj, deffed_array_type, use_dynamic, entries,
+ current_flags.WithStrippedTypedef(), root_level,
+ ptr_stripped_depth);
}
}
@@ -266,7 +272,8 @@ void FormatManager::GetPossibleMatches(
if (compiler_type.IsTypedefType()) {
CompilerType deffed_type = compiler_type.GetTypedefedType();
GetPossibleMatches(valobj, deffed_type, use_dynamic, entries,
- current_flags.WithStrippedTypedef());
+ current_flags.WithStrippedTypedef(), root_level,
+ ptr_stripped_depth);
}
if (root_level) {
@@ -281,7 +288,8 @@ void FormatManager::GetPossibleMatches(
if (unqual_compiler_ast_type.GetOpaqueQualType() !=
compiler_type.GetOpaqueQualType())
GetPossibleMatches(valobj, unqual_compiler_ast_type, use_dynamic,
- entries, current_flags);
+ entries, current_flags, root_level,
+ ptr_stripped_depth);
} while (false);
// if all else fails, go to static type
@@ -290,7 +298,7 @@ void FormatManager::GetPossibleMatches(
if (static_value_sp)
GetPossibleMatches(*static_value_sp.get(),
static_value_sp->GetCompilerType(), use_dynamic,
- entries, current_flags, true);
+ entries, current_flags, true, ptr_stripped_depth);
}
}
}
diff --git a/lldb/source/DataFormatters/TypeCategoryMap.cpp b/lldb/source/DataFormatters/TypeCategoryMap.cpp
index ce2cf369b5be5..8682e4b7435e4 100644
--- a/lldb/source/DataFormatters/TypeCategoryMap.cpp
+++ b/lldb/source/DataFormatters/TypeCategoryMap.cpp
@@ -185,12 +185,13 @@ void TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) {
for (auto match : match_data.GetMatchesVector()) {
LLDB_LOGF(
log,
- "[%s] candidate match = %s %s %s %s",
+ "[%s] candidate match = %s %s %s %s ptr-stripped-depth=%u",
__FUNCTION__,
match.GetTypeName().GetCString(),
match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers",
match.DidStripReference() ? "strip-reference" : "no-strip-reference",
- match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef");
+ match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef",
+ match.GetPtrStrippedDepth());
}
}
diff --git a/lldb/source/DataFormatters/TypeSummary.cpp b/lldb/source/DataFormatters/TypeSummary.cpp
index 18bf81aedf2cb..6aa290698cd12 100644
--- a/lldb/source/DataFormatters/TypeSummary.cpp
+++ b/lldb/source/DataFormatters/TypeSummary.cpp
@@ -43,8 +43,9 @@ TypeSummaryOptions::SetCapping(lldb::TypeSummaryCapping cap) {
return *this;
}
-TypeSummaryImpl::TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags)
- : m_flags(flags), m_kind(kind) {}
+TypeSummaryImpl::TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags,
+ uint32_t ptr_match_depth)
+ : m_flags(flags), m_kind(kind), m_ptr_match_depth(ptr_match_depth) {}
std::string TypeSummaryImpl::GetSummaryKindName() {
switch (m_kind) {
@@ -63,8 +64,10 @@ std::string TypeSummaryImpl::GetSummaryKindName() {
}
StringSummaryFormat::StringSummaryFormat(const TypeSummaryImpl::Flags &flags,
- const char *format_cstr)
- : TypeSummaryImpl(Kind::eSummaryString, flags), m_format_str() {
+ const char *format_cstr,
+ uint32_t ptr_match_depth)
+ : TypeSummaryImpl(Kind::eSummaryString, flags, ptr_match_depth),
+ m_format_str() {
SetSummaryString(format_cstr);
}
@@ -117,7 +120,7 @@ bool StringSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval,
std::string StringSummaryFormat::GetDescription() {
StreamString sstr;
- sstr.Printf("`%s`%s%s%s%s%s%s%s%s%s", m_format_str.c_str(),
+ sstr.Printf("`%s`%s%s%s%s%s%s%s%s%s ptr-match-depth=%u", m_format_str.c_str(),
m_error.Fail() ? " error: " : "",
m_error.Fail() ? m_error.AsCString() : "",
Cascades() ? "" : " (not cascading)",
@@ -126,15 +129,17 @@ std::string StringSummaryFormat::GetDescription() {
IsOneLiner() ? " (one-line printout)" : "",
SkipsPointers() ? " (skip pointers)" : "",
SkipsReferences() ? " (skip references)" : "",
- HideNames(nullptr) ? " (hide member names)" : "");
+ HideNames(nullptr) ? " (hide member names)" : "",
+ GetPtrMatchDepth());
return std::string(sstr.GetString());
}
std::string StringSummaryFormat::GetName() { return m_format_str; }
CXXFunctionSummaryFormat::CXXFunctionSummaryFormat(
- const TypeSummaryImpl::Flags &flags, Callback impl, const char *description)
- : TypeSummaryImpl(Kind::eCallback, flags), m_impl(impl),
+ const TypeSummaryImpl::Flags &flags, Callback impl, const char *description,
+ uint32_t ptr_match_depth)
+ : TypeSummaryImpl(Kind::eCallback, flags, ptr_match_depth), m_impl(impl),
m_description(description ? description : "") {}
bool CXXFunctionSummaryFormat::FormatObject(ValueObject *valobj,
@@ -150,14 +155,15 @@ bool CXXFunctionSummaryFormat::FormatObject(ValueObject *valobj,
std::string CXXFunctionSummaryFormat::GetDescription() {
StreamString sstr;
- sstr.Printf("%s%s%s%s%s%s%s %s", Cascades() ? "" : " (not cascading)",
+ sstr.Printf("%s%s%s%s%s%s%s ptr-match-depth=%u %s",
+ Cascades() ? "" : " (not cascading)",
!DoesPrintChildren(nullptr) ? "" : " (show children)",
!DoesPrintValue(nullptr) ? " (hide value)" : "",
IsOneLiner() ? " (one-line printout)" : "",
SkipsPointers() ? " (skip pointers)" : "",
SkipsReferences() ? " (skip references)" : "",
HideNames(nullptr) ? " (hide member names)" : "",
- m_description.c_str());
+ GetPtrMatchDepth(), m_description.c_str());
return std::string(sstr.GetString());
}
@@ -165,8 +171,9 @@ std::string CXXFunctionSummaryFormat::GetName() { return m_description; }
ScriptSummaryFormat::ScriptSummaryFormat(const TypeSummaryImpl::Flags &flags,
const char *function_name,
- const char *python_script)
- : TypeSummaryImpl(Kind::eScript, flags), m_function_name(),
+ const char *python_script,
+ uint32_t ptr_match_depth)
+ : TypeSummaryImpl(Kind::eScript, flags, ptr_match_depth), m_function_name(),
m_python_script(), m_script_function_sp() {
// Take preference in the python script name over the function name.
if (function_name) {
@@ -211,13 +218,15 @@ bool ScriptSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval,
std::string ScriptSummaryFormat::GetDescription() {
StreamString sstr;
- sstr.Printf("%s%s%s%s%s%s%s\n ", Cascades() ? "" : " (not cascading)",
+ sstr.Printf("%s%s%s%s%s%s%s ptr-match-depth=%u\n ",
+ Cascades() ? "" : " (not cascading)",
!DoesPrintChildren(nullptr) ? "" : " (show children)",
!DoesPrintValue(nullptr) ? " (hide value)" : "",
IsOneLiner() ? " (one-line printout)" : "",
SkipsPointers() ? " (skip pointers)" : "",
SkipsReferences() ? " (skip references)" : "",
- HideNames(nullptr) ? " (hide member names)" : "");
+ HideNames(nullptr) ? " (hide member names)" : "",
+ GetPtrMatchDepth());
if (m_python_script.empty()) {
if (m_function_name.empty()) {
sstr.PutCString("no backing script");
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/Makefile
new file mode 100644
index 0000000000000..a149c7f81bfab
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+
+CXXFLAGS_EXTRAS := -O0
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py
new file mode 100644
index 0000000000000..f960526466076
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py
@@ -0,0 +1,101 @@
+"""
+Test lldb data formatter subsystem.
+"""
+
+import os
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class PtrMatchingDataFormatterTestCase(TestBase):
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ # Find the line number to break at.
+ self.line = line_number("main.cpp", "// Set break point at this line.")
+
+ def test_summary_with_command(self):
+ """Test "type summary add" command line option "--pointer-match-depth"."""
+ self.build()
+ self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
+
+ lldbutil.run_break_set_by_file_and_line(
+ self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True
+ )
+
+ self.runCmd("run", RUN_SUCCEEDED)
+
+ # This is the function to remove the custom formats in order to have a
+ # clean slate for the next test case.
+ def cleanup():
+ self.runCmd("type format clear", check=False)
+ self.runCmd("type summary clear", check=False)
+
+ # Execute the cleanup function during test case tear down.
+ self.addTearDownHook(cleanup)
+
+ # By default, --pointer-match-depth is 1.
+ self.runCmd('type summary add --cascade true -s "MyInt" "Int"')
+ self.expect("frame variable", patterns=[
+ r".* i = MyInt\n",
+ r".* i_p = 0x.* MyInt\n",
+ r".* i_pp = 0x[0-9a-f]+\n",
+ r".* i_ppp = 0x[0-9a-f]+\n",
+ r".* f = MyInt\n",
+ r".* f_p = 0x[0-9a-f]+ MyInt\n",
+ r".* f_pp = 0x[0-9a-f]+\n",
+ r".* f_ppp = 0x[0-9a-f]+\n",
+ r".* fp = 0x[0-9a-f]+ MyInt\n",
+ r".* fp_p = 0x[0-9a-f]+\n",
+ r".* fp_pp = 0x[0-9a-f]+\n",
+ r".* b = MyInt\n",
+ r".* b_p = 0x[0-9a-f]+ MyInt\n",
+ r".* b_pp = 0x[0-9a-f]+\n",
+ r".* bp = 0x[0-9a-f]+ MyInt\n",
+ r".* bp_p = 0x[0-9a-f]+\n",
+ r".* bp_pp = 0x[0-9a-f]+\n",
+ ])
+
+ self.runCmd('type summary delete "Int"')
+ self.runCmd(
+ 'type summary add --cascade true --pointer-match-depth 2 -s "MyInt" "Int"')
+ self.expect("frame variable", patterns=[
+ r".* i = MyInt\n",
+ r".* i_p = 0x.* MyInt\n",
+ r".* i_pp = 0x[0-9a-f]+ MyInt\n",
+ r".* i_ppp = 0x[0-9a-f]+\n",
+ r".* f = MyInt\n",
+ r".* f_p = 0x[0-9a-f]+ MyInt\n",
+ r".* f_pp = 0x[0-9a-f]+ MyInt\n",
+ r".* f_ppp = 0x[0-9a-f]+\n",
+ r".* fp = 0x[0-9a-f]+ MyInt\n",
+ r".* fp_p = 0x[0-9a-f]+ MyInt\n",
+ r".* fp_pp = 0x[0-9a-f]+\n",
+ r".* b = MyInt\n",
+ r".* b_p = 0x[0-9a-f]+ MyInt\n",
+ r".* b_pp = 0x[0-9a-f]+ MyInt\n",
+ r".* bp = 0x[0-9a-f]+ MyInt\n",
+ r".* bp_p = 0x[0-9a-f]+ MyInt\n",
+ r".* bp_pp = 0x[0-9a-f]+\n",
+ ])
+
+ self.runCmd('type summary delete "Int"')
+ self.runCmd(
+ 'type summary add --cascade true --pointer-match-depth 2 -s "MyFoo" "Foo"')
+ self.expect("frame variable", patterns=[
+ r".* f = MyFoo\n",
+ r".* f_p = 0x[0-9a-f]+ MyFoo\n",
+ r".* f_pp = 0x[0-9a-f]+ MyFoo\n",
+ r".* f_ppp = 0x[0-9a-f]+\n",
+ r".* fp = 0x[0-9a-f]+\n",
+ r".* fp_p = 0x[0-9a-f]+\n",
+ r".* fp_pp = 0x[0-9a-f]+\n",
+ r".* b = MyFoo\n",
+ r".* b_p = 0x[0-9a-f]+ MyFoo\n",
+ r".* b_pp = 0x[0-9a-f]+ MyFoo\n",
+ r".* bp = 0x[0-9a-f]+ MyFoo\n",
+ r".* bp_p = 0x[0-9a-f]+ MyFoo\n",
+ r".* bp_pp = 0x[0-9a-f]+\n",
+ ])
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp
new file mode 100644
index 0000000000000..5fafae53d1c21
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp
@@ -0,0 +1,32 @@
+struct Int {
+ int i;
+};
+typedef Int Foo;
+typedef Int* FooP;
+typedef Foo Bar;
+typedef Foo* BarP;
+
+int main() {
+ Int i = {42};
+ Int* i_p = &i;
+ Int** i_pp = &i_p;
+ Int*** i_ppp = &i_pp;
+
+ Foo f = i;
+ Foo* f_p = &f;
+ Foo** f_pp = &f_p;
+ Foo*** f_ppp = &f_pp;
+
+ FooP fp = f_p;
+ FooP* fp_p = &fp;
+ FooP** fp_pp = &fp_p;
+
+ Bar b = i;
+ Bar* b_p = &b;
+ Bar** b_pp = &b_p;
+
+ BarP bp = b_p;
+ BarP* bp_p = &bp;
+ BarP** bp_pp = &bp_p;
+ return 0; // Set break point at this line.
+}
More information about the lldb-commits
mailing list