1*cfb07508SAlisamar Husain //===-- GenericOptional.cpp ----------------------------------------------===//
2*cfb07508SAlisamar Husain //
3*cfb07508SAlisamar Husain // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*cfb07508SAlisamar Husain // See https://llvm.org/LICENSE.txt for license information.
5*cfb07508SAlisamar Husain // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*cfb07508SAlisamar Husain //
7*cfb07508SAlisamar Husain //===---------------------------------------------------------------------===//
8*cfb07508SAlisamar Husain 
9*cfb07508SAlisamar Husain #include "Generic.h"
10*cfb07508SAlisamar Husain #include "LibCxx.h"
11*cfb07508SAlisamar Husain #include "LibStdcpp.h"
12*cfb07508SAlisamar Husain #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
13*cfb07508SAlisamar Husain #include "lldb/DataFormatters/FormattersHelpers.h"
14*cfb07508SAlisamar Husain #include "lldb/Target/Target.h"
15*cfb07508SAlisamar Husain 
16*cfb07508SAlisamar Husain using namespace lldb;
17*cfb07508SAlisamar Husain using namespace lldb_private;
18*cfb07508SAlisamar Husain 
GenericOptionalSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)19*cfb07508SAlisamar Husain bool lldb_private::formatters::GenericOptionalSummaryProvider(
20*cfb07508SAlisamar Husain     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
21*cfb07508SAlisamar Husain   stream.Printf(" Has Value=%s ",
22*cfb07508SAlisamar Husain                 valobj.GetNumChildren() == 0 ? "false" : "true");
23*cfb07508SAlisamar Husain 
24*cfb07508SAlisamar Husain   return true;
25*cfb07508SAlisamar Husain }
26*cfb07508SAlisamar Husain 
27*cfb07508SAlisamar Husain // Synthetic Children Provider
28*cfb07508SAlisamar Husain namespace {
29*cfb07508SAlisamar Husain 
30*cfb07508SAlisamar Husain class GenericOptionalFrontend : public SyntheticChildrenFrontEnd {
31*cfb07508SAlisamar Husain public:
32*cfb07508SAlisamar Husain   enum class StdLib {
33*cfb07508SAlisamar Husain     LibCxx,
34*cfb07508SAlisamar Husain     LibStdcpp,
35*cfb07508SAlisamar Husain   };
36*cfb07508SAlisamar Husain 
37*cfb07508SAlisamar Husain   GenericOptionalFrontend(ValueObject &valobj, StdLib stdlib);
38*cfb07508SAlisamar Husain 
GetIndexOfChildWithName(ConstString name)39*cfb07508SAlisamar Husain   size_t GetIndexOfChildWithName(ConstString name) override {
40*cfb07508SAlisamar Husain     return formatters::ExtractIndexFromString(name.GetCString());
41*cfb07508SAlisamar Husain   }
42*cfb07508SAlisamar Husain 
MightHaveChildren()43*cfb07508SAlisamar Husain   bool MightHaveChildren() override { return true; }
CalculateNumChildren()44*cfb07508SAlisamar Husain   size_t CalculateNumChildren() override { return m_has_value ? 1U : 0U; }
45*cfb07508SAlisamar Husain 
46*cfb07508SAlisamar Husain   ValueObjectSP GetChildAtIndex(size_t idx) override;
47*cfb07508SAlisamar Husain   bool Update() override;
48*cfb07508SAlisamar Husain 
49*cfb07508SAlisamar Husain private:
50*cfb07508SAlisamar Husain   bool m_has_value = false;
51*cfb07508SAlisamar Husain   StdLib m_stdlib;
52*cfb07508SAlisamar Husain };
53*cfb07508SAlisamar Husain 
54*cfb07508SAlisamar Husain } // namespace
55*cfb07508SAlisamar Husain 
GenericOptionalFrontend(ValueObject & valobj,StdLib stdlib)56*cfb07508SAlisamar Husain GenericOptionalFrontend::GenericOptionalFrontend(ValueObject &valobj,
57*cfb07508SAlisamar Husain                                                  StdLib stdlib)
58*cfb07508SAlisamar Husain     : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) {
59*cfb07508SAlisamar Husain   if (auto target_sp = m_backend.GetTargetSP()) {
60*cfb07508SAlisamar Husain     Update();
61*cfb07508SAlisamar Husain   }
62*cfb07508SAlisamar Husain }
63*cfb07508SAlisamar Husain 
Update()64*cfb07508SAlisamar Husain bool GenericOptionalFrontend::Update() {
65*cfb07508SAlisamar Husain   ValueObjectSP engaged_sp;
66*cfb07508SAlisamar Husain 
67*cfb07508SAlisamar Husain   if (m_stdlib == StdLib::LibCxx)
68*cfb07508SAlisamar Husain     engaged_sp =
69*cfb07508SAlisamar Husain         m_backend.GetChildMemberWithName(ConstString("__engaged_"), true);
70*cfb07508SAlisamar Husain   else if (m_stdlib == StdLib::LibStdcpp)
71*cfb07508SAlisamar Husain     engaged_sp =
72*cfb07508SAlisamar Husain         m_backend.GetChildMemberWithName(ConstString("_M_payload"), true)
73*cfb07508SAlisamar Husain             ->GetChildMemberWithName(ConstString("_M_engaged"), true);
74*cfb07508SAlisamar Husain 
75*cfb07508SAlisamar Husain   if (!engaged_sp)
76*cfb07508SAlisamar Husain     return false;
77*cfb07508SAlisamar Husain 
78*cfb07508SAlisamar Husain   // _M_engaged/__engaged is a bool flag and is true if the optional contains a
79*cfb07508SAlisamar Husain   // value. Converting it to unsigned gives us a size of 1 if it contains a
80*cfb07508SAlisamar Husain   // value and 0 if not.
81*cfb07508SAlisamar Husain   m_has_value = engaged_sp->GetValueAsUnsigned(0) != 0;
82*cfb07508SAlisamar Husain 
83*cfb07508SAlisamar Husain   return false;
84*cfb07508SAlisamar Husain }
85*cfb07508SAlisamar Husain 
GetChildAtIndex(size_t _idx)86*cfb07508SAlisamar Husain ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(size_t _idx) {
87*cfb07508SAlisamar Husain   if (!m_has_value)
88*cfb07508SAlisamar Husain     return ValueObjectSP();
89*cfb07508SAlisamar Husain 
90*cfb07508SAlisamar Husain   ValueObjectSP val_sp;
91*cfb07508SAlisamar Husain 
92*cfb07508SAlisamar Husain   if (m_stdlib == StdLib::LibCxx)
93*cfb07508SAlisamar Husain     // __val_ contains the underlying value of an optional if it has one.
94*cfb07508SAlisamar Husain     // Currently because it is part of an anonymous union
95*cfb07508SAlisamar Husain     // GetChildMemberWithName() does not peer through and find it unless we are
96*cfb07508SAlisamar Husain     // at the parent itself. We can obtain the parent through __engaged_.
97*cfb07508SAlisamar Husain     val_sp = m_backend.GetChildMemberWithName(ConstString("__engaged_"), true)
98*cfb07508SAlisamar Husain                  ->GetParent()
99*cfb07508SAlisamar Husain                  ->GetChildAtIndex(0, true)
100*cfb07508SAlisamar Husain                  ->GetChildMemberWithName(ConstString("__val_"), true);
101*cfb07508SAlisamar Husain   else if (m_stdlib == StdLib::LibStdcpp) {
102*cfb07508SAlisamar Husain     val_sp = m_backend.GetChildMemberWithName(ConstString("_M_payload"), true)
103*cfb07508SAlisamar Husain                  ->GetChildMemberWithName(ConstString("_M_payload"), true);
104*cfb07508SAlisamar Husain 
105*cfb07508SAlisamar Husain     // In some implementations, _M_value contains the underlying value of an
106*cfb07508SAlisamar Husain     // optional, and in other versions, it's in the payload member.
107*cfb07508SAlisamar Husain     ValueObjectSP candidate =
108*cfb07508SAlisamar Husain         val_sp->GetChildMemberWithName(ConstString("_M_value"), true);
109*cfb07508SAlisamar Husain     if (candidate)
110*cfb07508SAlisamar Husain       val_sp = candidate;
111*cfb07508SAlisamar Husain   }
112*cfb07508SAlisamar Husain 
113*cfb07508SAlisamar Husain   if (!val_sp)
114*cfb07508SAlisamar Husain     return ValueObjectSP();
115*cfb07508SAlisamar Husain 
116*cfb07508SAlisamar Husain   CompilerType holder_type = val_sp->GetCompilerType();
117*cfb07508SAlisamar Husain 
118*cfb07508SAlisamar Husain   if (!holder_type)
119*cfb07508SAlisamar Husain     return ValueObjectSP();
120*cfb07508SAlisamar Husain 
121*cfb07508SAlisamar Husain   return val_sp->Clone(ConstString("Value"));
122*cfb07508SAlisamar Husain }
123*cfb07508SAlisamar Husain 
124*cfb07508SAlisamar Husain SyntheticChildrenFrontEnd *
LibStdcppOptionalSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)125*cfb07508SAlisamar Husain formatters::LibStdcppOptionalSyntheticFrontEndCreator(
126*cfb07508SAlisamar Husain     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
127*cfb07508SAlisamar Husain   if (valobj_sp)
128*cfb07508SAlisamar Husain     return new GenericOptionalFrontend(
129*cfb07508SAlisamar Husain         *valobj_sp, GenericOptionalFrontend::StdLib::LibStdcpp);
130*cfb07508SAlisamar Husain   return nullptr;
131*cfb07508SAlisamar Husain }
132*cfb07508SAlisamar Husain 
LibcxxOptionalSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)133*cfb07508SAlisamar Husain SyntheticChildrenFrontEnd *formatters::LibcxxOptionalSyntheticFrontEndCreator(
134*cfb07508SAlisamar Husain     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
135*cfb07508SAlisamar Husain   if (valobj_sp)
136*cfb07508SAlisamar Husain     return new GenericOptionalFrontend(*valobj_sp,
137*cfb07508SAlisamar Husain                                        GenericOptionalFrontend::StdLib::LibCxx);
138*cfb07508SAlisamar Husain   return nullptr;
139*cfb07508SAlisamar Husain }
140