diff --git a/lldb/include/lldb/Target/Language.h b/lldb/include/lldb/Target/Language.h --- a/lldb/include/lldb/Target/Language.h +++ b/lldb/include/lldb/Target/Language.h @@ -211,6 +211,10 @@ // 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 diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp --- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp +++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp @@ -355,22 +355,33 @@ if (err_cstr) error.assign(err_cstr); - if (ShouldPrintValueObject()) { - if (IsNil()) - summary.assign("nil"); - else if (IsUninitialized()) - summary.assign(""); - 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(""); + } 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); } } } @@ -403,7 +414,9 @@ // 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) || diff --git a/lldb/source/Expression/UserExpression.cpp b/lldb/source/Expression/UserExpression.cpp --- a/lldb/source/Expression/UserExpression.cpp +++ b/lldb/source/Expression/UserExpression.cpp @@ -358,6 +358,7 @@ } else { if (expr_result) { result_valobj_sp = expr_result->GetValueObject(); + result_valobj_sp->SetPreferredDisplayLanguage(language); LLDB_LOG(log, "== [UserExpression::Evaluate] Execution completed " diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h @@ -88,6 +88,10 @@ 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; } diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -1134,6 +1134,15 @@ 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++"}; diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h --- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h +++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h @@ -119,6 +119,8 @@ 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; } diff --git a/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h b/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h --- a/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h +++ b/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h @@ -27,6 +27,8 @@ 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; } diff --git a/lldb/test/API/commands/expression/import-std-module/forward_decl_from_module/TestForwardDeclFromStdModule.py b/lldb/test/API/commands/expression/import-std-module/forward_decl_from_module/TestForwardDeclFromStdModule.py --- a/lldb/test/API/commands/expression/import-std-module/forward_decl_from_module/TestForwardDeclFromStdModule.py +++ b/lldb/test/API/commands/expression/import-std-module/forward_decl_from_module/TestForwardDeclFromStdModule.py @@ -39,4 +39,4 @@ # Both `std::vector` and the type of the member have forward # declarations before their definitions. self.expect("expr --raw -- v", - substrs=['(std::__1::vector) $0 = {', 'f = 0x', '}']) + substrs=['(std::__1::vector) $0 = {', 'f = nullptr', '}']) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py @@ -80,6 +80,7 @@ '(%s::u32string) u32_empty = ""'%ns, '(%s::basic_string, ' '%s::allocator >) uchar = "aaaaa"'%(ns,ns,ns), + '(%s::string *) null_str = nullptr'%ns, ]) self.runCmd("n") @@ -117,6 +118,7 @@ '(%s::u32string) u32_empty = ""'%ns, '(%s::basic_string, ' '%s::allocator >) uchar = "aaaaa"'%(ns,ns,ns), + '(%s::string *) null_str = nullptr'%ns, ]) # The test assumes that std::string is in its cap-size-data layout. diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp @@ -74,6 +74,7 @@ std::u32string u32_string(U"🍄🍅🍆🍌"); std::u32string u32_empty(U""); std::basic_string uchar(5, 'a'); + std::string *null_str = nullptr; #if _LIBCPP_ABI_VERSION == 1 std::string garbage1, garbage2, garbage3, garbage4, garbage5; diff --git a/lldb/test/API/lang/c/anonymous/TestAnonymous.py b/lldb/test/API/lang/c/anonymous/TestAnonymous.py --- a/lldb/test/API/lang/c/anonymous/TestAnonymous.py +++ b/lldb/test/API/lang/c/anonymous/TestAnonymous.py @@ -62,7 +62,7 @@ # 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"]) diff --git a/lldb/test/API/lang/objc/objc-builtin-types/Makefile b/lldb/test/API/lang/objcxx/objc-builtin-types/Makefile rename from lldb/test/API/lang/objc/objc-builtin-types/Makefile rename to lldb/test/API/lang/objcxx/objc-builtin-types/Makefile diff --git a/lldb/test/API/lang/objc/objc-builtin-types/TestObjCBuiltinTypes.py b/lldb/test/API/lang/objcxx/objc-builtin-types/TestObjCBuiltinTypes.py rename from lldb/test/API/lang/objc/objc-builtin-types/TestObjCBuiltinTypes.py rename to lldb/test/API/lang/objcxx/objc-builtin-types/TestObjCBuiltinTypes.py --- a/lldb/test/API/lang/objc/objc-builtin-types/TestObjCBuiltinTypes.py +++ b/lldb/test/API/lang/objcxx/objc-builtin-types/TestObjCBuiltinTypes.py @@ -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 * @@ -21,7 +19,6 @@ self.main_source, '// Set breakpoint here.') @add_test_categories(['pyapi']) - # [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() @@ -57,4 +54,7 @@ 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"]) diff --git a/lldb/test/API/lang/objc/objc-builtin-types/main.cpp b/lldb/test/API/lang/objcxx/objc-builtin-types/main.cpp rename from lldb/test/API/lang/objc/objc-builtin-types/main.cpp rename to lldb/test/API/lang/objcxx/objc-builtin-types/main.cpp