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 = m_backend.GetChildMemberWithName("__engaged_"); 69 else if (m_stdlib == StdLib::LibStdcpp) 70 engaged_sp = m_backend.GetChildMemberWithName("_M_payload") 71 ->GetChildMemberWithName("_M_engaged"); 72 73 if (!engaged_sp) 74 return false; 75 76 // _M_engaged/__engaged is a bool flag and is true if the optional contains a 77 // value. Converting it to unsigned gives us a size of 1 if it contains a 78 // value and 0 if not. 79 m_has_value = engaged_sp->GetValueAsUnsigned(0) != 0; 80 81 return false; 82 } 83 84 ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(size_t _idx) { 85 if (!m_has_value) 86 return ValueObjectSP(); 87 88 ValueObjectSP val_sp; 89 90 if (m_stdlib == StdLib::LibCxx) 91 // __val_ contains the underlying value of an optional if it has one. 92 // Currently because it is part of an anonymous union 93 // GetChildMemberWithName() does not peer through and find it unless we are 94 // at the parent itself. We can obtain the parent through __engaged_. 95 val_sp = m_backend.GetChildMemberWithName("__engaged_") 96 ->GetParent() 97 ->GetChildAtIndex(0) 98 ->GetChildMemberWithName("__val_"); 99 else if (m_stdlib == StdLib::LibStdcpp) { 100 val_sp = m_backend.GetChildMemberWithName("_M_payload") 101 ->GetChildMemberWithName("_M_payload"); 102 103 // In some implementations, _M_value contains the underlying value of an 104 // optional, and in other versions, it's in the payload member. 105 ValueObjectSP candidate = val_sp->GetChildMemberWithName("_M_value"); 106 if (candidate) 107 val_sp = candidate; 108 } 109 110 if (!val_sp) 111 return ValueObjectSP(); 112 113 CompilerType holder_type = val_sp->GetCompilerType(); 114 115 if (!holder_type) 116 return ValueObjectSP(); 117 118 return val_sp->Clone(ConstString("Value")); 119 } 120 121 SyntheticChildrenFrontEnd * 122 formatters::LibStdcppOptionalSyntheticFrontEndCreator( 123 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 124 if (valobj_sp) 125 return new GenericOptionalFrontend( 126 *valobj_sp, GenericOptionalFrontend::StdLib::LibStdcpp); 127 return nullptr; 128 } 129 130 SyntheticChildrenFrontEnd *formatters::LibcxxOptionalSyntheticFrontEndCreator( 131 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 132 if (valobj_sp) 133 return new GenericOptionalFrontend(*valobj_sp, 134 GenericOptionalFrontend::StdLib::LibCxx); 135 return nullptr; 136 } 137