168 lines · cpp
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-exception6//7//===---------------------------------------------------------------------===//8 9#include "Generic.h"10#include "LibCxx.h"11#include "LibStdcpp.h"12#include "MsvcStl.h"13#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"14#include "lldb/DataFormatters/FormattersHelpers.h"15#include "lldb/Target/Target.h"16 17using namespace lldb;18using namespace lldb_private;19 20bool lldb_private::formatters::GenericOptionalSummaryProvider(21 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {22 stream.Printf(" Has Value=%s ",23 valobj.GetNumChildrenIgnoringErrors() == 0 ? "false" : "true");24 25 return true;26}27 28// Synthetic Children Provider29namespace {30 31class GenericOptionalFrontend : public SyntheticChildrenFrontEnd {32public:33 enum class StdLib {34 LibCxx,35 LibStdcpp,36 MsvcStl,37 };38 39 GenericOptionalFrontend(ValueObject &valobj, StdLib stdlib);40 41 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {42 if (name == "$$dereference$$")43 return 0;44 auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());45 if (!optional_idx) {46 return llvm::createStringError("Type has no child named '%s'",47 name.AsCString());48 }49 return *optional_idx;50 }51 52 llvm::Expected<uint32_t> CalculateNumChildren() override {53 return m_has_value ? 1U : 0U;54 }55 56 ValueObjectSP GetChildAtIndex(uint32_t idx) override;57 lldb::ChildCacheState Update() override;58 59private:60 bool m_has_value = false;61 StdLib m_stdlib;62};63 64} // namespace65 66GenericOptionalFrontend::GenericOptionalFrontend(ValueObject &valobj,67 StdLib stdlib)68 : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) {69 if (auto target_sp = m_backend.GetTargetSP()) {70 Update();71 }72}73 74lldb::ChildCacheState GenericOptionalFrontend::Update() {75 ValueObjectSP engaged_sp;76 77 if (m_stdlib == StdLib::LibCxx)78 engaged_sp = m_backend.GetChildMemberWithName("__engaged_");79 else if (m_stdlib == StdLib::LibStdcpp) {80 if (ValueObjectSP payload = m_backend.GetChildMemberWithName("_M_payload"))81 engaged_sp = payload->GetChildMemberWithName("_M_engaged");82 } else if (m_stdlib == StdLib::MsvcStl)83 engaged_sp = m_backend.GetChildMemberWithName("_Has_value");84 85 if (!engaged_sp)86 return lldb::ChildCacheState::eRefetch;87 88 // _M_engaged/__engaged is a bool flag and is true if the optional contains a89 // value. Converting it to unsigned gives us a size of 1 if it contains a90 // value and 0 if not.91 m_has_value = engaged_sp->GetValueAsUnsigned(0) != 0;92 93 return lldb::ChildCacheState::eRefetch;94}95 96ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(uint32_t _idx) {97 if (!m_has_value)98 return ValueObjectSP();99 100 ValueObjectSP val_sp;101 102 if (m_stdlib == StdLib::LibCxx)103 // __val_ contains the underlying value of an optional if it has one.104 // Currently because it is part of an anonymous union105 // GetChildMemberWithName() does not peer through and find it unless we are106 // at the parent itself. We can obtain the parent through __engaged_.107 val_sp = m_backend.GetChildMemberWithName("__engaged_")108 ->GetParent()109 ->GetChildAtIndex(0)110 ->GetChildMemberWithName("__val_");111 else if (m_stdlib == StdLib::LibStdcpp) {112 val_sp = m_backend.GetChildMemberWithName("_M_payload")113 ->GetChildMemberWithName("_M_payload");114 115 // In some implementations, _M_value contains the underlying value of an116 // optional, and in other versions, it's in the payload member.117 ValueObjectSP candidate = val_sp->GetChildMemberWithName("_M_value");118 if (candidate)119 val_sp = candidate;120 } else if (m_stdlib == StdLib::MsvcStl)121 // Same issue as with LibCxx122 val_sp = m_backend.GetChildMemberWithName("_Has_value")123 ->GetParent()124 ->GetChildAtIndex(0)125 ->GetChildMemberWithName("_Value");126 127 if (!val_sp)128 return ValueObjectSP();129 130 CompilerType holder_type = val_sp->GetCompilerType();131 132 if (!holder_type)133 return ValueObjectSP();134 135 return val_sp->Clone(ConstString("Value"));136}137 138SyntheticChildrenFrontEnd *139formatters::LibStdcppOptionalSyntheticFrontEndCreator(140 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {141 if (valobj_sp)142 return new GenericOptionalFrontend(143 *valobj_sp, GenericOptionalFrontend::StdLib::LibStdcpp);144 return nullptr;145}146 147SyntheticChildrenFrontEnd *formatters::LibcxxOptionalSyntheticFrontEndCreator(148 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {149 if (valobj_sp)150 return new GenericOptionalFrontend(*valobj_sp,151 GenericOptionalFrontend::StdLib::LibCxx);152 return nullptr;153}154 155bool formatters::IsMsvcStlOptional(ValueObject &valobj) {156 if (auto valobj_sp = valobj.GetNonSyntheticValue())157 return valobj_sp->GetChildMemberWithName("_Has_value") != nullptr;158 return false;159}160 161SyntheticChildrenFrontEnd *formatters::MsvcStlOptionalSyntheticFrontEndCreator(162 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {163 if (valobj_sp)164 return new GenericOptionalFrontend(165 *valobj_sp, GenericOptionalFrontend::StdLib::MsvcStl);166 return nullptr;167}168