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.GetNumChildren() == 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 return formatters::ExtractIndexFromString(name.GetCString()); 41 } 42 43 bool MightHaveChildren() override { return true; } 44 size_t CalculateNumChildren() override { return m_has_value ? 1U : 0U; } 45 46 ValueObjectSP GetChildAtIndex(size_t idx) override; 47 bool Update() override; 48 49 private: 50 bool m_has_value = false; 51 StdLib m_stdlib; 52 }; 53 54 } // namespace 55 56 GenericOptionalFrontend::GenericOptionalFrontend(ValueObject &valobj, 57 StdLib stdlib) 58 : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) { 59 if (auto target_sp = m_backend.GetTargetSP()) { 60 Update(); 61 } 62 } 63 64 bool GenericOptionalFrontend::Update() { 65 ValueObjectSP engaged_sp; 66 67 if (m_stdlib == StdLib::LibCxx) 68 engaged_sp = 69 m_backend.GetChildMemberWithName(ConstString("__engaged_"), true); 70 else if (m_stdlib == StdLib::LibStdcpp) 71 engaged_sp = 72 m_backend.GetChildMemberWithName(ConstString("_M_payload"), true) 73 ->GetChildMemberWithName(ConstString("_M_engaged"), true); 74 75 if (!engaged_sp) 76 return false; 77 78 // _M_engaged/__engaged is a bool flag and is true if the optional contains a 79 // value. Converting it to unsigned gives us a size of 1 if it contains a 80 // value and 0 if not. 81 m_has_value = engaged_sp->GetValueAsUnsigned(0) != 0; 82 83 return false; 84 } 85 86 ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(size_t _idx) { 87 if (!m_has_value) 88 return ValueObjectSP(); 89 90 ValueObjectSP val_sp; 91 92 if (m_stdlib == StdLib::LibCxx) 93 // __val_ contains the underlying value of an optional if it has one. 94 // Currently because it is part of an anonymous union 95 // GetChildMemberWithName() does not peer through and find it unless we are 96 // at the parent itself. We can obtain the parent through __engaged_. 97 val_sp = m_backend.GetChildMemberWithName(ConstString("__engaged_"), true) 98 ->GetParent() 99 ->GetChildAtIndex(0, true) 100 ->GetChildMemberWithName(ConstString("__val_"), true); 101 else if (m_stdlib == StdLib::LibStdcpp) { 102 val_sp = m_backend.GetChildMemberWithName(ConstString("_M_payload"), true) 103 ->GetChildMemberWithName(ConstString("_M_payload"), true); 104 105 // In some implementations, _M_value contains the underlying value of an 106 // optional, and in other versions, it's in the payload member. 107 ValueObjectSP candidate = 108 val_sp->GetChildMemberWithName(ConstString("_M_value"), true); 109 if (candidate) 110 val_sp = candidate; 111 } 112 113 if (!val_sp) 114 return ValueObjectSP(); 115 116 CompilerType holder_type = val_sp->GetCompilerType(); 117 118 if (!holder_type) 119 return ValueObjectSP(); 120 121 return val_sp->Clone(ConstString("Value")); 122 } 123 124 SyntheticChildrenFrontEnd * 125 formatters::LibStdcppOptionalSyntheticFrontEndCreator( 126 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 127 if (valobj_sp) 128 return new GenericOptionalFrontend( 129 *valobj_sp, GenericOptionalFrontend::StdLib::LibStdcpp); 130 return nullptr; 131 } 132 133 SyntheticChildrenFrontEnd *formatters::LibcxxOptionalSyntheticFrontEndCreator( 134 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 135 if (valobj_sp) 136 return new GenericOptionalFrontend(*valobj_sp, 137 GenericOptionalFrontend::StdLib::LibCxx); 138 return nullptr; 139 } 140