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(format: " 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(item_name: 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(name: "__engaged_" ); |
71 | else if (m_stdlib == StdLib::LibStdcpp) |
72 | engaged_sp = m_backend.GetChildMemberWithName(name: "_M_payload" ) |
73 | ->GetChildMemberWithName(name: "_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(fail_value: 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(name: "__engaged_" ) |
98 | ->GetParent() |
99 | ->GetChildAtIndex(idx: 0) |
100 | ->GetChildMemberWithName(name: "__val_" ); |
101 | else if (m_stdlib == StdLib::LibStdcpp) { |
102 | val_sp = m_backend.GetChildMemberWithName(name: "_M_payload" ) |
103 | ->GetChildMemberWithName(name: "_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(name: "_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(new_name: 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 | |