| //===----------------------------------------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "MsvcStl.h" | |
| #include "lldb/DataFormatters/FormattersHelpers.h" | |
| #include "llvm/Support/ErrorExtras.h" | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| using namespace lldb_private::formatters; | |
| namespace { | |
| class MsvcStlExpectedFrontend : public SyntheticChildrenFrontEnd { | |
| public: | |
| MsvcStlExpectedFrontend(ValueObject &valobj) | |
| : SyntheticChildrenFrontEnd(valobj) { | |
| if (valobj.GetTargetSP()) | |
| Update(); | |
| } | |
| llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override { | |
| if (!m_active) | |
| return llvm::createStringErrorV("type has no child named '{0}'", name); | |
| if (m_has_value) { | |
| if (name == "Value" || name == "$$dereference$$") | |
| return 0; | |
| } else if (name == "Unexpected") { | |
| return 0; | |
| } | |
| return llvm::createStringErrorV("type has no child named '{0}'", name); | |
| } | |
| llvm::Expected<uint32_t> CalculateNumChildren() override { | |
| return m_active ? 1U : 0U; | |
| } | |
| ValueObjectSP GetChildAtIndex(uint32_t idx) override { | |
| if (!m_active || idx != 0) | |
| return {}; | |
| return m_active->Clone(m_has_value ? "Value" : "Unexpected"); | |
| } | |
| lldb::ChildCacheState Update() override { | |
| m_active = nullptr; | |
| m_has_value = false; | |
| ValueObjectSP ns = m_backend.GetNonSyntheticValue(); | |
| if (!ns) | |
| return lldb::ChildCacheState::eRefetch; | |
| ValueObjectSP has_sp = ns->GetChildMemberWithName("_Has_value"); | |
| if (!has_sp) | |
| return lldb::ChildCacheState::eRefetch; | |
| m_has_value = has_sp->GetValueAsUnsigned(0) != 0; | |
| // expected<void, E> has no value child when engaged. | |
| m_active = | |
| ns->GetChildMemberWithName(m_has_value ? "_Value" : "_Unexpected") | |
| .get(); | |
| return lldb::ChildCacheState::eRefetch; | |
| } | |
| private: | |
| ValueObject *m_active = nullptr; | |
| bool m_has_value = false; | |
| }; | |
| } // namespace | |
| bool formatters::IsMsvcStlExpected(ValueObject &valobj) { | |
| if (auto valobj_sp = valobj.GetNonSyntheticValue()) | |
| return valobj_sp->GetChildMemberWithName("_Has_value") != nullptr; | |
| return false; | |
| } | |
| bool formatters::MsvcStlExpectedSummaryProvider(ValueObject &valobj, | |
| Stream &stream, | |
| const TypeSummaryOptions &) { | |
| ValueObjectSP ns = valobj.GetNonSyntheticValue(); | |
| if (!ns) | |
| return false; | |
| ValueObjectSP has_sp = ns->GetChildMemberWithName("_Has_value"); | |
| if (!has_sp) | |
| return false; | |
| // Keep the summary consistent with std::optional. | |
| stream.Printf(" Has Value=%s ", | |
| has_sp->GetValueAsUnsigned(0) ? "true" : "false"); | |
| return true; | |
| } | |
| SyntheticChildrenFrontEnd *formatters::MsvcStlExpectedSyntheticFrontEndCreator( | |
| CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { | |
| if (valobj_sp) | |
| return new MsvcStlExpectedFrontend(*valobj_sp); | |
| return nullptr; | |
| } |