1 //===-- GenericOptional.cpp ----------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===---------------------------------------------------------------------===// 8 9 #include "Generic.h" 10 #include "LibCxx.h" 11 #include "LibStdcpp.h" 12 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 13 #include "lldb/DataFormatters/FormattersHelpers.h" 14 #include "lldb/Target/Target.h" 15 16 using namespace lldb; 17 using namespace lldb_private; 18 19 bool lldb_private::formatters::GenericOptionalSummaryProvider( 20 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 21 stream.Printf(" Has Value=%s ", 22 valobj.GetNumChildrenIgnoringErrors() == 0 ? "false" : "true"); 23 24 return true; 25 } 26 27 // Synthetic Children Provider 28 namespace { 29 30 class GenericOptionalFrontend : public SyntheticChildrenFrontEnd { 31 public: 32 enum class StdLib { 33 LibCxx, 34 LibStdcpp, 35 }; 36 37 GenericOptionalFrontend(ValueObject &valobj, StdLib stdlib); 38 39 size_t GetIndexOfChildWithName(ConstString name) override { 40 if (name == "$$dereference$$") 41 return 0; 42 return formatters::ExtractIndexFromString(name.GetCString()); 43 } 44 45 bool MightHaveChildren() override { return true; } 46 llvm::Expected<uint32_t> CalculateNumChildren() override { 47 return m_has_value ? 1U : 0U; 48 } 49 50 ValueObjectSP GetChildAtIndex(uint32_t idx) override; 51 lldb::ChildCacheState Update() override; 52 53 private: 54 bool m_has_value = false; 55 StdLib m_stdlib; 56 }; 57 58 } // namespace 59 60 GenericOptionalFrontend::GenericOptionalFrontend(ValueObject &valobj, 61 StdLib stdlib) 62 : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) { 63 if (auto target_sp = m_backend.GetTargetSP()) { 64 Update(); 65 } 66 } 67 68 lldb::ChildCacheState GenericOptionalFrontend::Update() { 69 ValueObjectSP engaged_sp; 70 71 if (m_stdlib == StdLib::LibCxx) 72 engaged_sp = m_backend.GetChildMemberWithName("__engaged_"); 73 else if (m_stdlib == StdLib::LibStdcpp) 74 engaged_sp = m_backend.GetChildMemberWithName("_M_payload") 75 ->GetChildMemberWithName("_M_engaged"); 76 77 if (!engaged_sp) 78 return lldb::ChildCacheState::eRefetch; 79 80 // _M_engaged/__engaged is a bool flag and is true if the optional contains a 81 // value. Converting it to unsigned gives us a size of 1 if it contains a 82 // value and 0 if not. 83 m_has_value = engaged_sp->GetValueAsUnsigned(0) != 0; 84 85 return lldb::ChildCacheState::eRefetch; 86 } 87 88 ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(uint32_t _idx) { 89 if (!m_has_value) 90 return ValueObjectSP(); 91 92 ValueObjectSP val_sp; 93 94 if (m_stdlib == StdLib::LibCxx) 95 // __val_ contains the underlying value of an optional if it has one. 96 // Currently because it is part of an anonymous union 97 // GetChildMemberWithName() does not peer through and find it unless we are 98 // at the parent itself. We can obtain the parent through __engaged_. 99 val_sp = m_backend.GetChildMemberWithName("__engaged_") 100 ->GetParent() 101 ->GetChildAtIndex(0) 102 ->GetChildMemberWithName("__val_"); 103 else if (m_stdlib == StdLib::LibStdcpp) { 104 val_sp = m_backend.GetChildMemberWithName("_M_payload") 105 ->GetChildMemberWithName("_M_payload"); 106 107 // In some implementations, _M_value contains the underlying value of an 108 // optional, and in other versions, it's in the payload member. 109 ValueObjectSP candidate = val_sp->GetChildMemberWithName("_M_value"); 110 if (candidate) 111 val_sp = candidate; 112 } 113 114 if (!val_sp) 115 return ValueObjectSP(); 116 117 CompilerType holder_type = val_sp->GetCompilerType(); 118 119 if (!holder_type) 120 return ValueObjectSP(); 121 122 return val_sp->Clone(ConstString("Value")); 123 } 124 125 SyntheticChildrenFrontEnd * 126 formatters::LibStdcppOptionalSyntheticFrontEndCreator( 127 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 128 if (valobj_sp) 129 return new GenericOptionalFrontend( 130 *valobj_sp, GenericOptionalFrontend::StdLib::LibStdcpp); 131 return nullptr; 132 } 133 134 SyntheticChildrenFrontEnd *formatters::LibcxxOptionalSyntheticFrontEndCreator( 135 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 136 if (valobj_sp) 137 return new GenericOptionalFrontend(*valobj_sp, 138 GenericOptionalFrontend::StdLib::LibCxx); 139 return nullptr; 140 } 141