10eae32dcSDimitry Andric //===-- GenericOptional.cpp ----------------------------------------------===// 20eae32dcSDimitry Andric // 30eae32dcSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40eae32dcSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50eae32dcSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60eae32dcSDimitry Andric // 70eae32dcSDimitry Andric //===---------------------------------------------------------------------===// 80eae32dcSDimitry Andric 90eae32dcSDimitry Andric #include "Generic.h" 100eae32dcSDimitry Andric #include "LibCxx.h" 110eae32dcSDimitry Andric #include "LibStdcpp.h" 120eae32dcSDimitry Andric #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 130eae32dcSDimitry Andric #include "lldb/DataFormatters/FormattersHelpers.h" 140eae32dcSDimitry Andric #include "lldb/Target/Target.h" 150eae32dcSDimitry Andric 160eae32dcSDimitry Andric using namespace lldb; 170eae32dcSDimitry Andric using namespace lldb_private; 180eae32dcSDimitry Andric 190eae32dcSDimitry Andric bool lldb_private::formatters::GenericOptionalSummaryProvider( 200eae32dcSDimitry Andric ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 210eae32dcSDimitry Andric stream.Printf(" Has Value=%s ", 22*0fca6ea1SDimitry Andric valobj.GetNumChildrenIgnoringErrors() == 0 ? "false" : "true"); 230eae32dcSDimitry Andric 240eae32dcSDimitry Andric return true; 250eae32dcSDimitry Andric } 260eae32dcSDimitry Andric 270eae32dcSDimitry Andric // Synthetic Children Provider 280eae32dcSDimitry Andric namespace { 290eae32dcSDimitry Andric 300eae32dcSDimitry Andric class GenericOptionalFrontend : public SyntheticChildrenFrontEnd { 310eae32dcSDimitry Andric public: 320eae32dcSDimitry Andric enum class StdLib { 330eae32dcSDimitry Andric LibCxx, 340eae32dcSDimitry Andric LibStdcpp, 350eae32dcSDimitry Andric }; 360eae32dcSDimitry Andric 370eae32dcSDimitry Andric GenericOptionalFrontend(ValueObject &valobj, StdLib stdlib); 380eae32dcSDimitry Andric 390eae32dcSDimitry Andric size_t GetIndexOfChildWithName(ConstString name) override { 400eae32dcSDimitry Andric return formatters::ExtractIndexFromString(name.GetCString()); 410eae32dcSDimitry Andric } 420eae32dcSDimitry Andric 430eae32dcSDimitry Andric bool MightHaveChildren() override { return true; } 44*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> CalculateNumChildren() override { 45*0fca6ea1SDimitry Andric return m_has_value ? 1U : 0U; 46*0fca6ea1SDimitry Andric } 470eae32dcSDimitry Andric 48*0fca6ea1SDimitry Andric ValueObjectSP GetChildAtIndex(uint32_t idx) override; 49*0fca6ea1SDimitry Andric lldb::ChildCacheState Update() override; 500eae32dcSDimitry Andric 510eae32dcSDimitry Andric private: 520eae32dcSDimitry Andric bool m_has_value = false; 530eae32dcSDimitry Andric StdLib m_stdlib; 540eae32dcSDimitry Andric }; 550eae32dcSDimitry Andric 560eae32dcSDimitry Andric } // namespace 570eae32dcSDimitry Andric 580eae32dcSDimitry Andric GenericOptionalFrontend::GenericOptionalFrontend(ValueObject &valobj, 590eae32dcSDimitry Andric StdLib stdlib) 600eae32dcSDimitry Andric : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) { 610eae32dcSDimitry Andric if (auto target_sp = m_backend.GetTargetSP()) { 620eae32dcSDimitry Andric Update(); 630eae32dcSDimitry Andric } 640eae32dcSDimitry Andric } 650eae32dcSDimitry Andric 66*0fca6ea1SDimitry Andric lldb::ChildCacheState GenericOptionalFrontend::Update() { 670eae32dcSDimitry Andric ValueObjectSP engaged_sp; 680eae32dcSDimitry Andric 690eae32dcSDimitry Andric if (m_stdlib == StdLib::LibCxx) 7006c3fb27SDimitry Andric engaged_sp = m_backend.GetChildMemberWithName("__engaged_"); 710eae32dcSDimitry Andric else if (m_stdlib == StdLib::LibStdcpp) 7206c3fb27SDimitry Andric engaged_sp = m_backend.GetChildMemberWithName("_M_payload") 7306c3fb27SDimitry Andric ->GetChildMemberWithName("_M_engaged"); 740eae32dcSDimitry Andric 750eae32dcSDimitry Andric if (!engaged_sp) 76*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 770eae32dcSDimitry Andric 780eae32dcSDimitry Andric // _M_engaged/__engaged is a bool flag and is true if the optional contains a 790eae32dcSDimitry Andric // value. Converting it to unsigned gives us a size of 1 if it contains a 800eae32dcSDimitry Andric // value and 0 if not. 810eae32dcSDimitry Andric m_has_value = engaged_sp->GetValueAsUnsigned(0) != 0; 820eae32dcSDimitry Andric 83*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 840eae32dcSDimitry Andric } 850eae32dcSDimitry Andric 86*0fca6ea1SDimitry Andric ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(uint32_t _idx) { 870eae32dcSDimitry Andric if (!m_has_value) 880eae32dcSDimitry Andric return ValueObjectSP(); 890eae32dcSDimitry Andric 900eae32dcSDimitry Andric ValueObjectSP val_sp; 910eae32dcSDimitry Andric 920eae32dcSDimitry Andric if (m_stdlib == StdLib::LibCxx) 930eae32dcSDimitry Andric // __val_ contains the underlying value of an optional if it has one. 940eae32dcSDimitry Andric // Currently because it is part of an anonymous union 950eae32dcSDimitry Andric // GetChildMemberWithName() does not peer through and find it unless we are 960eae32dcSDimitry Andric // at the parent itself. We can obtain the parent through __engaged_. 9706c3fb27SDimitry Andric val_sp = m_backend.GetChildMemberWithName("__engaged_") 980eae32dcSDimitry Andric ->GetParent() 9906c3fb27SDimitry Andric ->GetChildAtIndex(0) 10006c3fb27SDimitry Andric ->GetChildMemberWithName("__val_"); 1010eae32dcSDimitry Andric else if (m_stdlib == StdLib::LibStdcpp) { 10206c3fb27SDimitry Andric val_sp = m_backend.GetChildMemberWithName("_M_payload") 10306c3fb27SDimitry Andric ->GetChildMemberWithName("_M_payload"); 1040eae32dcSDimitry Andric 1050eae32dcSDimitry Andric // In some implementations, _M_value contains the underlying value of an 1060eae32dcSDimitry Andric // optional, and in other versions, it's in the payload member. 10706c3fb27SDimitry Andric ValueObjectSP candidate = val_sp->GetChildMemberWithName("_M_value"); 1080eae32dcSDimitry Andric if (candidate) 1090eae32dcSDimitry Andric val_sp = candidate; 1100eae32dcSDimitry Andric } 1110eae32dcSDimitry Andric 1120eae32dcSDimitry Andric if (!val_sp) 1130eae32dcSDimitry Andric return ValueObjectSP(); 1140eae32dcSDimitry Andric 1150eae32dcSDimitry Andric CompilerType holder_type = val_sp->GetCompilerType(); 1160eae32dcSDimitry Andric 1170eae32dcSDimitry Andric if (!holder_type) 1180eae32dcSDimitry Andric return ValueObjectSP(); 1190eae32dcSDimitry Andric 1200eae32dcSDimitry Andric return val_sp->Clone(ConstString("Value")); 1210eae32dcSDimitry Andric } 1220eae32dcSDimitry Andric 1230eae32dcSDimitry Andric SyntheticChildrenFrontEnd * 1240eae32dcSDimitry Andric formatters::LibStdcppOptionalSyntheticFrontEndCreator( 1250eae32dcSDimitry Andric CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 1260eae32dcSDimitry Andric if (valobj_sp) 1270eae32dcSDimitry Andric return new GenericOptionalFrontend( 1280eae32dcSDimitry Andric *valobj_sp, GenericOptionalFrontend::StdLib::LibStdcpp); 1290eae32dcSDimitry Andric return nullptr; 1300eae32dcSDimitry Andric } 1310eae32dcSDimitry Andric 1320eae32dcSDimitry Andric SyntheticChildrenFrontEnd *formatters::LibcxxOptionalSyntheticFrontEndCreator( 1330eae32dcSDimitry Andric CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 1340eae32dcSDimitry Andric if (valobj_sp) 1350eae32dcSDimitry Andric return new GenericOptionalFrontend(*valobj_sp, 1360eae32dcSDimitry Andric GenericOptionalFrontend::StdLib::LibCxx); 1370eae32dcSDimitry Andric return nullptr; 1380eae32dcSDimitry Andric } 139