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