Skip to content

[lldb/DataFormatters] Display null C++ pointers as nullptr #2240

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lldb/include/lldb/Target/Language.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ class Language : public PluginInterface {
// nil/null object, this method returns true
virtual bool IsNilReference(ValueObject &valobj);

/// Returns the summary string for ValueObjects for which IsNilReference() is
/// true.
virtual llvm::StringRef GetNilReferenceSummaryString() { return {}; }

// for a ValueObject of some "reference type", if the language provides a
// technique to decide whether the reference has ever been assigned to some
// object, this method will return true if such detection is possible, and if
Expand Down
47 changes: 30 additions & 17 deletions lldb/source/DataFormatters/ValueObjectPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,22 +355,33 @@ void ValueObjectPrinter::GetValueSummaryError(std::string &value,
if (err_cstr)
error.assign(err_cstr);

if (ShouldPrintValueObject()) {
if (IsNil())
summary.assign("nil");
else if (IsUninitialized())
summary.assign("<uninitialized>");
else if (m_options.m_omit_summary_depth == 0) {
TypeSummaryImpl *entry = GetSummaryFormatter();
if (entry)
m_valobj->GetSummaryAsCString(entry, summary,
m_options.m_varformat_language);
else {
const char *sum_cstr =
m_valobj->GetSummaryAsCString(m_options.m_varformat_language);
if (sum_cstr)
summary.assign(sum_cstr);
}
if (!ShouldPrintValueObject())
return;

if (IsNil()) {
lldb::LanguageType lang_type =
(m_options.m_varformat_language == lldb::eLanguageTypeUnknown)
? m_valobj->GetPreferredDisplayLanguage()
: m_options.m_varformat_language;
if (Language *lang_plugin = Language::FindPlugin(lang_type)) {
summary.assign(lang_plugin->GetNilReferenceSummaryString().str());
} else {
// We treat C as the fallback language rather than as a separate Language
// plugin.
summary.assign("NULL");
}
} else if (IsUninitialized()) {
summary.assign("<uninitialized>");
} else if (m_options.m_omit_summary_depth == 0) {
TypeSummaryImpl *entry = GetSummaryFormatter();
if (entry) {
m_valobj->GetSummaryAsCString(entry, summary,
m_options.m_varformat_language);
} else {
const char *sum_cstr =
m_valobj->GetSummaryAsCString(m_options.m_varformat_language);
if (sum_cstr)
summary.assign(sum_cstr);
}
}
}
Expand Down Expand Up @@ -403,7 +414,9 @@ bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed,
// this thing is nil (but show the value if the user passes a format
// explicitly)
TypeSummaryImpl *entry = GetSummaryFormatter();
if (!IsNil() && !IsUninitialized() && !m_value.empty() &&
const bool has_nil_or_uninitialized_summary =
(IsNil() || IsUninitialized()) && !m_summary.empty();
if (!has_nil_or_uninitialized_summary && !m_value.empty() &&
(entry == nullptr ||
(entry->DoesPrintValue(m_valobj) ||
m_options.m_format != eFormatDefault) ||
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Expression/UserExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx,
} else {
if (expr_result) {
result_valobj_sp = expr_result->GetValueObject();
result_valobj_sp->SetPreferredDisplayLanguage(language);

LLDB_LOG(log,
"== [UserExpression::Evaluate] Execution completed "
Expand Down
9 changes: 9 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,15 @@ CPlusPlusLanguage::GetHardcodedSynthetics() {
return g_formatters;
}

bool CPlusPlusLanguage::IsNilReference(ValueObject &valobj) {
if (!Language::LanguageIsCPlusPlus(valobj.GetObjectRuntimeLanguage()) ||
!valobj.IsPointerType())
return false;
bool canReadValue = true;
bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0;
return canReadValue && isZero;
}

bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const {
const auto suffixes = {".cpp", ".cxx", ".c++", ".cc", ".c",
".h", ".hh", ".hpp", ".hxx", ".h++"};
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ class CPlusPlusLanguage : public Language {
HardcodedFormatters::HardcodedSyntheticFinder
GetHardcodedSynthetics() override;

bool IsNilReference(ValueObject &valobj) override;

llvm::StringRef GetNilReferenceSummaryString() override { return "nullptr"; }

bool IsSourceFile(llvm::StringRef file_path) const override;

const Highlighter *GetHighlighter() const override { return &m_highlighter; }
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ class ObjCLanguage : public Language {

bool IsNilReference(ValueObject &valobj) override;

llvm::StringRef GetNilReferenceSummaryString() override { return "nil"; }

bool IsSourceFile(llvm::StringRef file_path) const override;

const Highlighter *GetHighlighter() const override { return &m_highlighter; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class ObjCPlusPlusLanguage : public Language {
return lldb::eLanguageTypeObjC_plus_plus;
}

llvm::StringRef GetNilReferenceSummaryString() override { return "nil"; }

bool IsSourceFile(llvm::StringRef file_path) const override;

const Highlighter *GetHighlighter() const override { return &m_highlighter; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ def test(self):
# Both `std::vector` and the type of the member have forward
# declarations before their definitions.
self.expect("expr --raw -- v",
substrs=['(std::__1::vector<int>) $0 = {', 'f = 0x', '}'])
substrs=['(std::__1::vector<int>) $0 = {', 'f = nullptr', '}'])
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def cleanup():
'(%s::u32string) u32_empty = ""'%ns,
'(%s::basic_string<unsigned char, %s::char_traits<unsigned char>, '
'%s::allocator<unsigned char> >) uchar = "aaaaa"'%(ns,ns,ns),
'(%s::string *) null_str = nullptr'%ns,
])

self.runCmd("n")
Expand Down Expand Up @@ -114,6 +115,7 @@ def cleanup():
'(%s::u32string) u32_empty = ""'%ns,
'(%s::basic_string<unsigned char, %s::char_traits<unsigned char>, '
'%s::allocator<unsigned char> >) uchar = "aaaaa"'%(ns,ns,ns),
'(%s::string *) null_str = nullptr'%ns,
])

# The test assumes that std::string is in its cap-size-data layout.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ int main()
std::u32string u32_string(U"🍄🍅🍆🍌");
std::u32string u32_empty(U"");
std::basic_string<unsigned char> uchar(5, 'a');
std::string *null_str = nullptr;

#if _LIBCPP_ABI_VERSION == 1
std::string garbage1, garbage2, garbage3, garbage4, garbage5;
Expand Down
2 changes: 1 addition & 1 deletion lldb/test/API/lang/c/anonymous/TestAnonymous.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def test_expr_parent(self):

# These should display correctly.
self.expect("expression pz", VARIABLES_DISPLAYED_CORRECTLY,
substrs=["(type_z *) $", " = 0x0000"])
substrs=["(type_z *) $", " = NULL"])

self.expect("expression z.y", VARIABLES_DISPLAYED_CORRECTLY,
substrs=["(type_y) $", "dummy = 2"])
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""Test that the expression parser doesn't get confused by 'id' and 'Class'"""



import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
Expand All @@ -22,7 +20,6 @@ def setUp(self):

@skipUnlessDarwin
@add_test_categories(['pyapi'])
#<rdar://problem/10591460> [regression] Can't print ivar value: error: reference to 'id' is ambiguous
def test_with_python_api(self):
"""Test expression parser respect for ObjC built-in types."""
self.build()
Expand Down Expand Up @@ -58,4 +55,7 @@ def test_with_python_api(self):

self.expect("expr (foo)", patterns=["\(ns::id\) \$.* = 0"])

self.expect("expr id my_id = 0; my_id", patterns=["\(id\) \$.* = nil"])
self.expect("expr --language Objective-C++ -- id my_id = 0; my_id",
patterns=["\(id\) \$.* = nil"])
self.expect("expr --language C++ -- id my_id = 0; my_id",
patterns=["\(id\) \$.* = nullptr"])