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 return formatters::ExtractIndexFromString(name.GetCString()); 41 } 42 43 bool MightHaveChildren() override { return true; } 44 llvm::Expected<uint32_t> CalculateNumChildren() override { 45 return m_has_value ? 1U : 0U; 46 } 47 48 ValueObjectSP GetChildAtIndex(uint32_t idx) override; 49 lldb::ChildCacheState Update() override; 50 51 private: 52 bool m_has_value = false; 53 StdLib m_stdlib; 54 }; 55 56 } // namespace 57 58 GenericOptionalFrontend::GenericOptionalFrontend(ValueObject &valobj, 59 StdLib stdlib) 60 : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) { 61 if (auto target_sp = m_backend.GetTargetSP()) { 62 Update(); 63 } 64 } 65 66 lldb::ChildCacheState GenericOptionalFrontend::Update() { 67 ValueObjectSP engaged_sp; 68 69 if (m_stdlib == StdLib::LibCxx) 70 engaged_sp = m_backend.GetChildMemberWithName("__engaged_"); 71 else if (m_stdlib == StdLib::LibStdcpp) 72 engaged_sp = m_backend.GetChildMemberWithName("_M_payload") 73 ->GetChildMemberWithName("_M_engaged"); 74 75 if (!engaged_sp) 76 return lldb::ChildCacheState::eRefetch; 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 lldb::ChildCacheState::eRefetch; 84 } 85 86 ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(uint32_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("__engaged_") 98 ->GetParent() 99 ->GetChildAtIndex(0) 100 ->GetChildMemberWithName("__val_"); 101 else if (m_stdlib == StdLib::LibStdcpp) { 102 val_sp = m_backend.GetChildMemberWithName("_M_payload") 103 ->GetChildMemberWithName("_M_payload"); 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 = val_sp->GetChildMemberWithName("_M_value"); 108 if (candidate) 109 val_sp = candidate; 110 } 111 112 if (!val_sp) 113 return ValueObjectSP(); 114 115 CompilerType holder_type = val_sp->GetCompilerType(); 116 117 if (!holder_type) 118 return ValueObjectSP(); 119 120 return val_sp->Clone(ConstString("Value")); 121 } 122 123 SyntheticChildrenFrontEnd * 124 formatters::LibStdcppOptionalSyntheticFrontEndCreator( 125 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 126 if (valobj_sp) 127 return new GenericOptionalFrontend( 128 *valobj_sp, GenericOptionalFrontend::StdLib::LibStdcpp); 129 return nullptr; 130 } 131 132 SyntheticChildrenFrontEnd *formatters::LibcxxOptionalSyntheticFrontEndCreator( 133 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 134 if (valobj_sp) 135 return new GenericOptionalFrontend(*valobj_sp, 136 GenericOptionalFrontend::StdLib::LibCxx); 137 return nullptr; 138 } 139