Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -388,6 +388,7 @@ 945261C11B9A11FC00BF138D /* LibCxxInitializerList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945261B71B9A11E800BF138D /* LibCxxInitializerList.cpp */; }; 945261C21B9A11FC00BF138D /* LibCxxList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945261B81B9A11E800BF138D /* LibCxxList.cpp */; }; 945261C31B9A11FC00BF138D /* LibCxxMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945261B91B9A11E800BF138D /* LibCxxMap.cpp */; }; + E4A63A9120F55D28000D9548 /* LibCxxOptional.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A63A9020F55D27000D9548 /* LibCxxOptional.cpp */; }; AF9FF1F71FAA79FE00474976 /* LibCxxQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF9FF1F61FAA79FE00474976 /* LibCxxQueue.cpp */; }; AF9FF1F51FAA79A400474976 /* LibCxxTuple.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF9FF1F41FAA79A400474976 /* LibCxxTuple.cpp */; }; 945261C41B9A11FC00BF138D /* LibCxxUnorderedMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945261BA1B9A11E800BF138D /* LibCxxUnorderedMap.cpp */; }; @@ -1999,6 +2000,7 @@ 945261B71B9A11E800BF138D /* LibCxxInitializerList.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxInitializerList.cpp; path = Language/CPlusPlus/LibCxxInitializerList.cpp; sourceTree = ""; }; 945261B81B9A11E800BF138D /* LibCxxList.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxList.cpp; path = Language/CPlusPlus/LibCxxList.cpp; sourceTree = ""; }; 945261B91B9A11E800BF138D /* LibCxxMap.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxMap.cpp; path = Language/CPlusPlus/LibCxxMap.cpp; sourceTree = ""; }; + E4A63A9020F55D27000D9548 /* LibCxxOptional.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxOptional.cpp; path = Language/CPlusPlus/LibCxxOptional.cpp; sourceTree = ""; }; AF9FF1F61FAA79FE00474976 /* LibCxxQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxQueue.cpp; path = Language/CPlusPlus/LibCxxQueue.cpp; sourceTree = ""; }; AF9FF1F41FAA79A400474976 /* LibCxxTuple.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxTuple.cpp; path = Language/CPlusPlus/LibCxxTuple.cpp; sourceTree = ""; }; 945261BA1B9A11E800BF138D /* LibCxxUnorderedMap.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxUnorderedMap.cpp; path = Language/CPlusPlus/LibCxxUnorderedMap.cpp; sourceTree = ""; }; @@ -6346,6 +6348,7 @@ 945261B71B9A11E800BF138D /* LibCxxInitializerList.cpp */, 945261B81B9A11E800BF138D /* LibCxxList.cpp */, 945261B91B9A11E800BF138D /* LibCxxMap.cpp */, + E4A63A9020F55D27000D9548 /* LibCxxOptional.cpp */, AF9FF1F61FAA79FE00474976 /* LibCxxQueue.cpp */, AF9FF1F41FAA79A400474976 /* LibCxxTuple.cpp */, 945261BA1B9A11E800BF138D /* LibCxxUnorderedMap.cpp */, @@ -8038,6 +8041,7 @@ AF26703B1852D01E00B6CC36 /* QueueList.cpp in Sources */, 267C012B136880DF006E963E /* OptionGroupValueObjectDisplay.cpp in Sources */, 49CA96FE1E6AACC900C03FEE /* DataEncoder.cpp in Sources */, + E4A63A9120F55D28000D9548 /* LibCxxOptional.cpp in Sources */, 26BCFC521368AE38006DC050 /* OptionGroupFormat.cpp in Sources */, 2654A6901E552ED500DA1013 /* VASprintf.cpp in Sources */, AF81DEFA1828A23F0042CF19 /* SystemRuntime.cpp in Sources */, Index: packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/optional/Makefile =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/optional/Makefile @@ -0,0 +1,9 @@ +LEVEL = ../../../../../make + +CXX_SOURCES := main.cpp + +USE_LIBCPP := 1 +include $(LEVEL)/Makefile.rules +CXXFLAGS += -O0 +CXXFLAGS += -std=c++17 +#CFLAGS += -std=c++17 Index: packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/optional/TestDataFormatterLibcxxOptional.py =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/optional/TestDataFormatterLibcxxOptional.py @@ -0,0 +1,97 @@ +""" +Test lldb data formatter subsystem. +""" + +from __future__ import print_function + + +import os +import time +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class LibcxxOptionalDataFormatterTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(["libc++"]) +## @skipIf(debug_info="gmodules", +## bugnumber="https://bugs.llvm.org/show_bug.cgi?id=36048") + def test_with_run_command(self): + """Test that that file and class static variables display correctly.""" + self.build() + self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) + + bkpt = self.target().FindBreakpointByID( + lldbutil.run_break_set_by_source_regexp( + self, "break here")) + + self.runCmd("run", RUN_SUCCEEDED) + + # The stop reason of the thread should be breakpoint. + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs=['stopped', + 'stop reason = breakpoint']) + + # 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) + self.runCmd('type filter clear', check=False) + self.runCmd('type synth clear', check=False) + self.runCmd( + "settings set target.max-children-count 256", + check=False) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + # empty vectors (and storage pointers SHOULD BOTH BE NULL..) + self.expect("frame variable number", + substrs=['engaged=false']) + + lldbutil.continue_to_breakpoint(self.process(), bkpt) + + # first value added + self.expect("frame variable number", + substrs=['engaged=true', + '[0] = 42', + '}']) + + # add some more data + lldbutil.continue_to_breakpoint(self.process(), bkpt) + + self.expect("frame variable numbers", + substrs=['numbers = engaged=false']) + + self.expect("p numbers", + substrs=['$0 = engaged=false']) + + lldbutil.continue_to_breakpoint(self.process(), bkpt) + + self.expect("p numbers", + substrs=['$1 = engaged=true {', + '[0] = size=4 {', + '[0] = 1', + '[1] = 2', + '[2] = 3', + '[3] = 4', + '}', + '}']) + + # add some more data + lldbutil.continue_to_breakpoint(self.process(), bkpt) + + self.expect("frame variable ostring", + substrs=['ostring = engaged=false']) + + lldbutil.continue_to_breakpoint(self.process(), bkpt) + + self.expect("p ostring", + substrs=['$2 = engaged=true {', + '[0] = "hello"', + '}']) Index: packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/optional/main.cpp =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/optional/main.cpp @@ -0,0 +1,39 @@ +#include +#include +#include +#include + +using int_vect = std::vector ; +using string_vec = std::vector ; +using optional_int = std::optional ; +using optional_int_vect = std::optional ; +using optional_string = std::optional ; + +int main() +{ + optional_int number ; + + printf( "%d\n", number.has_value() ) ; // break here + + number = 42 ; + + printf( "%d\n", *number ) ; // break here + + optional_int_vect numbers ; + + printf( "%d\n", numbers.has_value() ) ; // break here + + numbers = {1,2,3,4} ; + + printf( "%d %d\n", numbers.value()[0], numbers.value()[1] ) ; // break here + + optional_string ostring ; + + printf( "%s\n", ostring.has_value() ) ; // break here + + ostring = "hello" ; + + printf( "%s\n", ostring->c_str() ) ; // break here + + return 0; // break here +} Index: source/Plugins/Language/CPlusPlus/CMakeLists.txt =================================================================== --- source/Plugins/Language/CPlusPlus/CMakeLists.txt +++ source/Plugins/Language/CPlusPlus/CMakeLists.txt @@ -11,6 +11,7 @@ LibCxxMap.cpp LibCxxQueue.cpp LibCxxTuple.cpp + LibCxxOptional.cpp LibCxxUnorderedMap.cpp LibCxxVector.cpp LibStdcpp.cpp Index: source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp =================================================================== --- source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -251,14 +251,14 @@ bool CPlusPlusLanguage::IsCPPMangledName(const char *name) { // FIXME!! we should really run through all the known C++ Language plugins // and ask each one if this is a C++ mangled name - + if (name == nullptr) return false; - - // MSVC style mangling + + // MSVC style mangling if (name[0] == '?') return true; - + return (name[0] != '\0' && name[0] == '_' && name[1] == 'Z'); } @@ -491,6 +491,10 @@ "libc++ std::tuple synthetic children", ConstString("^std::__(ndk)?1::tuple<.*>(( )?&)?$"), stl_synth_flags, true); + AddCXXSynthetic(cpp_category_sp, LibcxxOptionalFrontEndCreator, + "libc++ std::optional synthetic children", + ConstString("^std::__(ndk)?1::optional<.+>(( )?&)?$"), stl_synth_flags, + true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator, @@ -585,6 +589,12 @@ stl_summary_flags.SetSkipPointers(true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxOptionalSummaryProvider, + "libc++ std::optional summary provider", + ConstString("^std::__(ndk)?1::optional<.+>(( )?&)?$"), + stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxSmartPointerSummaryProvider, "libc++ std::shared_ptr summary provider", Index: source/Plugins/Language/CPlusPlus/LibCxx.h =================================================================== --- source/Plugins/Language/CPlusPlus/LibCxx.h +++ source/Plugins/Language/CPlusPlus/LibCxx.h @@ -27,6 +27,12 @@ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // libc++ std::wstring +bool LibcxxOptionalSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions + &options); // libc++ std::optional<> + + bool LibcxxSmartPointerSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions @@ -133,6 +139,9 @@ SyntheticChildrenFrontEnd *LibcxxTupleFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); +SyntheticChildrenFrontEnd *LibcxxOptionalFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp) ; + } // namespace formatters } // namespace lldb_private Index: source/Plugins/Language/CPlusPlus/LibCxx.cpp =================================================================== --- source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -33,6 +33,25 @@ using namespace lldb_private; using namespace lldb_private::formatters; +bool lldb_private::formatters::LibcxxOptionalSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + if (!valobj_sp) + return false; + ValueObjectSP engaged_sp( + valobj_sp->GetChildMemberWithName(ConstString("__engaged_"), true)); + + if (!engaged_sp) { + return false; + } + + const char *engaged_as_cstring = engaged_sp->GetValueAsUnsigned(0) == 1 ? "true" : "false" ; + + stream.Printf(" engaged=%s", engaged_as_cstring ); + + return true; +} + bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); @@ -120,9 +139,9 @@ if (!valobj_sp) return false; - + static ConstString g___i_("__i_"); - + // this must be a ValueObject* because it is a child of the ValueObject we // are producing children for it if were a ValueObjectSP, we would end up // with a loop (iterator -> synthetic -> child -> parent == iterator) and @@ -163,7 +182,7 @@ m_pair_ptr = nullptr; return false; } - + auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); m_pair_ptr = nullptr; if (addr && addr!=LLDB_INVALID_ADDRESS) { Index: source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp =================================================================== --- /dev/null +++ source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp @@ -0,0 +1,91 @@ +//===-- LibCxxOptional.cpp -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LibCxx.h" +#include "lldb/DataFormatters/FormattersHelpers.h" + +using namespace lldb; +using namespace lldb_private; + +namespace { + +class OptionalFrontEnd: public SyntheticChildrenFrontEnd { +public: + OptionalFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) { + Update(); + } + + size_t GetIndexOfChildWithName(const ConstString &name) override { + return formatters::ExtractIndexFromString(name.GetCString()); + } + + bool MightHaveChildren() override { return true; } + bool Update() override; + size_t CalculateNumChildren() override { return m_elements.size(); } + ValueObjectSP GetChildAtIndex(size_t idx) override; + +private: + std::vector m_elements; + ValueObjectSP m_base_sp; +}; +} + +bool OptionalFrontEnd::Update() { + m_elements.clear(); + + ValueObjectSP engaged_sp( m_backend.GetChildMemberWithName(ConstString("__engaged_"), true)); + + if (!engaged_sp) { + return false; + } + + uint64_t num_elements = engaged_sp->GetValueAsSigned(0) ; + + m_elements.assign(num_elements, ValueObjectSP()); + return false; +} + +ValueObjectSP OptionalFrontEnd::GetChildAtIndex(size_t idx) { + if (idx >= m_elements.size()) { + return ValueObjectSP(); + } + + //ValueObjectSP val_sp( m_backend.GetChildMemberWithName(ConstString("__val_"), true)); + ValueObjectSP val_sp( m_backend.GetChildMemberWithName(ConstString("__engaged_") , true)->GetParent()->GetChildAtIndex(0,true)->GetChildMemberWithName(ConstString("__val_"), true) ); + + if (!val_sp) { + fprintf( stderr, "no __val_!\n" ) ; + return ValueObjectSP(); + } + + if (m_elements[idx]) { + return m_elements[idx]; + } + + CompilerType holder_type = + val_sp->GetCompilerType() ; + + if (!holder_type) { + fprintf( stderr, "no holder_type!\n" ) ; + return ValueObjectSP(); + } + + m_elements[idx] = + val_sp->Clone(ConstString(llvm::formatv("[{0}]", idx).str())); + + return m_elements[idx]; +} + +SyntheticChildrenFrontEnd * +formatters::LibcxxOptionalFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp) { + if (valobj_sp) + return new OptionalFrontEnd(*valobj_sp); + return nullptr; +}