xref: /llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp (revision a5f03b4adcd147aeecc0e0d029660c12fb4d2951)
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