180814287SRaphael Isemann //===-- LibCxxVariant.cpp -------------------------------------------------===//
28306f76eSShafik Yaghmour //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68306f76eSShafik Yaghmour //
78306f76eSShafik Yaghmour //===----------------------------------------------------------------------===//
88306f76eSShafik Yaghmour 
98306f76eSShafik Yaghmour #include "LibCxxVariant.h"
108306f76eSShafik Yaghmour #include "lldb/DataFormatters/FormattersHelpers.h"
118306f76eSShafik Yaghmour 
128306f76eSShafik Yaghmour #include "llvm/ADT/Optional.h"
138306f76eSShafik Yaghmour #include "llvm/ADT/ScopeExit.h"
148306f76eSShafik Yaghmour 
158306f76eSShafik Yaghmour using namespace lldb;
168306f76eSShafik Yaghmour using namespace lldb_private;
178306f76eSShafik Yaghmour 
188306f76eSShafik Yaghmour // libc++ variant implementation contains two members that we care about both
198306f76eSShafik Yaghmour // are contained in the __impl member.
208306f76eSShafik Yaghmour // - __index which tells us which of the variadic template types is the active
218306f76eSShafik Yaghmour //   type for the variant
228306f76eSShafik Yaghmour // - __data is a variadic union which recursively contains itself as member
238306f76eSShafik Yaghmour //   which refers to the tailing variadic types.
248306f76eSShafik Yaghmour //   - __head which refers to the leading non pack type
258306f76eSShafik Yaghmour //     - __value refers to the actual value contained
268306f76eSShafik Yaghmour //   - __tail which refers to the remaining pack types
278306f76eSShafik Yaghmour //
288306f76eSShafik Yaghmour // e.g. given std::variant<int,double,char> v1
298306f76eSShafik Yaghmour //
308306f76eSShafik Yaghmour // (lldb) frame var -R v1.__impl.__data
318306f76eSShafik Yaghmour //(... __union<... 0, int, double, char>) v1.__impl.__data = {
328306f76eSShafik Yaghmour // ...
338306f76eSShafik Yaghmour //  __head = {
348306f76eSShafik Yaghmour //    __value = ...
358306f76eSShafik Yaghmour //  }
368306f76eSShafik Yaghmour //  __tail = {
378306f76eSShafik Yaghmour //  ...
388306f76eSShafik Yaghmour //    __head = {
398306f76eSShafik Yaghmour //      __value = ...
408306f76eSShafik Yaghmour //    }
418306f76eSShafik Yaghmour //    __tail = {
428306f76eSShafik Yaghmour //    ...
438306f76eSShafik Yaghmour //      __head = {
448306f76eSShafik Yaghmour //        __value = ...
458306f76eSShafik Yaghmour //  ...
468306f76eSShafik Yaghmour //
478306f76eSShafik Yaghmour // So given
488306f76eSShafik Yaghmour // - __index equal to 0 the active value is contained in
498306f76eSShafik Yaghmour //
508306f76eSShafik Yaghmour //     __data.__head.__value
518306f76eSShafik Yaghmour //
528306f76eSShafik Yaghmour // - __index equal to 1 the active value is contained in
538306f76eSShafik Yaghmour //
548306f76eSShafik Yaghmour //     __data.__tail.__head.__value
558306f76eSShafik Yaghmour //
568306f76eSShafik Yaghmour // - __index equal to 2 the active value is contained in
578306f76eSShafik Yaghmour //
588306f76eSShafik Yaghmour //      __data.__tail.__tail.__head.__value
598306f76eSShafik Yaghmour //
608306f76eSShafik Yaghmour 
618306f76eSShafik Yaghmour namespace {
628306f76eSShafik Yaghmour // libc++ std::variant index could have one of three states
6397212121SRaphael Isemann // 1) Valid, we can obtain it and its not variant_npos
6497212121SRaphael Isemann // 2) Invalid, we can't obtain it or it is not a type we expect
6597212121SRaphael Isemann // 3) NPos, its value is variant_npos which means the variant has no value
6697212121SRaphael Isemann enum class LibcxxVariantIndexValidity { Valid, Invalid, NPos };
678306f76eSShafik Yaghmour 
688306f76eSShafik Yaghmour LibcxxVariantIndexValidity
LibcxxVariantGetIndexValidity(ValueObjectSP & impl_sp)698306f76eSShafik Yaghmour LibcxxVariantGetIndexValidity(ValueObjectSP &impl_sp) {
708306f76eSShafik Yaghmour   ValueObjectSP index_sp(
718306f76eSShafik Yaghmour       impl_sp->GetChildMemberWithName(ConstString("__index"), true));
728306f76eSShafik Yaghmour 
738306f76eSShafik Yaghmour   if (!index_sp)
7497212121SRaphael Isemann     return LibcxxVariantIndexValidity::Invalid;
758306f76eSShafik Yaghmour 
768306f76eSShafik Yaghmour   int64_t index_value = index_sp->GetValueAsSigned(0);
778306f76eSShafik Yaghmour 
788306f76eSShafik Yaghmour   if (index_value == -1)
7997212121SRaphael Isemann     return LibcxxVariantIndexValidity::NPos;
808306f76eSShafik Yaghmour 
8197212121SRaphael Isemann   return LibcxxVariantIndexValidity::Valid;
828306f76eSShafik Yaghmour }
838306f76eSShafik Yaghmour 
LibcxxVariantIndexValue(ValueObjectSP & impl_sp)848306f76eSShafik Yaghmour llvm::Optional<uint64_t> LibcxxVariantIndexValue(ValueObjectSP &impl_sp) {
858306f76eSShafik Yaghmour   ValueObjectSP index_sp(
868306f76eSShafik Yaghmour       impl_sp->GetChildMemberWithName(ConstString("__index"), true));
878306f76eSShafik Yaghmour 
888306f76eSShafik Yaghmour   if (!index_sp)
898306f76eSShafik Yaghmour     return {};
908306f76eSShafik Yaghmour 
918306f76eSShafik Yaghmour   return {index_sp->GetValueAsUnsigned(0)};
928306f76eSShafik Yaghmour }
938306f76eSShafik Yaghmour 
LibcxxVariantGetNthHead(ValueObjectSP & impl_sp,uint64_t index)948306f76eSShafik Yaghmour ValueObjectSP LibcxxVariantGetNthHead(ValueObjectSP &impl_sp, uint64_t index) {
958306f76eSShafik Yaghmour   ValueObjectSP data_sp(
968306f76eSShafik Yaghmour       impl_sp->GetChildMemberWithName(ConstString("__data"), true));
978306f76eSShafik Yaghmour 
988306f76eSShafik Yaghmour   if (!data_sp)
998306f76eSShafik Yaghmour     return ValueObjectSP{};
1008306f76eSShafik Yaghmour 
1018306f76eSShafik Yaghmour   ValueObjectSP current_level = data_sp;
1028306f76eSShafik Yaghmour   for (uint64_t n = index; n != 0; --n) {
1038306f76eSShafik Yaghmour     ValueObjectSP tail_sp(
1048306f76eSShafik Yaghmour         current_level->GetChildMemberWithName(ConstString("__tail"), true));
1058306f76eSShafik Yaghmour 
1068306f76eSShafik Yaghmour     if (!tail_sp)
1078306f76eSShafik Yaghmour       return ValueObjectSP{};
1088306f76eSShafik Yaghmour 
1098306f76eSShafik Yaghmour     current_level = tail_sp;
1108306f76eSShafik Yaghmour   }
1118306f76eSShafik Yaghmour 
1128306f76eSShafik Yaghmour   return current_level->GetChildMemberWithName(ConstString("__head"), true);
113831be096SHenry Wong }
1148306f76eSShafik Yaghmour } // namespace
1158306f76eSShafik Yaghmour 
1168306f76eSShafik Yaghmour namespace lldb_private {
1178306f76eSShafik Yaghmour namespace formatters {
LibcxxVariantSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)1188306f76eSShafik Yaghmour bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream,
1198306f76eSShafik Yaghmour                                   const TypeSummaryOptions &options) {
1208306f76eSShafik Yaghmour   ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
1218306f76eSShafik Yaghmour   if (!valobj_sp)
1228306f76eSShafik Yaghmour     return false;
1238306f76eSShafik Yaghmour 
1248306f76eSShafik Yaghmour   ValueObjectSP impl_sp(
1258306f76eSShafik Yaghmour       valobj_sp->GetChildMemberWithName(ConstString("__impl"), true));
1268306f76eSShafik Yaghmour 
1278306f76eSShafik Yaghmour   if (!impl_sp)
1288306f76eSShafik Yaghmour     return false;
1298306f76eSShafik Yaghmour 
1308306f76eSShafik Yaghmour   LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
1318306f76eSShafik Yaghmour 
13297212121SRaphael Isemann   if (validity == LibcxxVariantIndexValidity::Invalid)
1338306f76eSShafik Yaghmour     return false;
1348306f76eSShafik Yaghmour 
13597212121SRaphael Isemann   if (validity == LibcxxVariantIndexValidity::NPos) {
1368306f76eSShafik Yaghmour     stream.Printf(" No Value");
1378306f76eSShafik Yaghmour     return true;
1388306f76eSShafik Yaghmour   }
1398306f76eSShafik Yaghmour 
1408306f76eSShafik Yaghmour   auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
1418306f76eSShafik Yaghmour 
1428306f76eSShafik Yaghmour   if (!optional_index_value)
1438306f76eSShafik Yaghmour     return false;
1448306f76eSShafik Yaghmour 
1458306f76eSShafik Yaghmour   uint64_t index_value = *optional_index_value;
1468306f76eSShafik Yaghmour 
1478306f76eSShafik Yaghmour   ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
1488306f76eSShafik Yaghmour 
1498306f76eSShafik Yaghmour   if (!nth_head)
1508306f76eSShafik Yaghmour     return false;
1518306f76eSShafik Yaghmour 
1528306f76eSShafik Yaghmour   CompilerType head_type = nth_head->GetCompilerType();
1538306f76eSShafik Yaghmour 
1548306f76eSShafik Yaghmour   if (!head_type)
1558306f76eSShafik Yaghmour     return false;
1568306f76eSShafik Yaghmour 
1578306f76eSShafik Yaghmour   CompilerType template_type = head_type.GetTypeTemplateArgument(1);
1588306f76eSShafik Yaghmour 
1598306f76eSShafik Yaghmour   if (!template_type)
1608306f76eSShafik Yaghmour     return false;
1618306f76eSShafik Yaghmour 
162*785df616SRaphael Isemann   stream << " Active Type = " << template_type.GetDisplayTypeName() << " ";
1638306f76eSShafik Yaghmour 
1648306f76eSShafik Yaghmour   return true;
1658306f76eSShafik Yaghmour }
1668306f76eSShafik Yaghmour } // namespace formatters
1678306f76eSShafik Yaghmour } // namespace lldb_private
1688306f76eSShafik Yaghmour 
1698306f76eSShafik Yaghmour namespace {
1708306f76eSShafik Yaghmour class VariantFrontEnd : public SyntheticChildrenFrontEnd {
1718306f76eSShafik Yaghmour public:
VariantFrontEnd(ValueObject & valobj)1728306f76eSShafik Yaghmour   VariantFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
1738306f76eSShafik Yaghmour     Update();
1748306f76eSShafik Yaghmour   }
1758306f76eSShafik Yaghmour 
GetIndexOfChildWithName(ConstString name)1760e4c4821SAdrian Prantl   size_t GetIndexOfChildWithName(ConstString name) override {
1778306f76eSShafik Yaghmour     return formatters::ExtractIndexFromString(name.GetCString());
1788306f76eSShafik Yaghmour   }
1798306f76eSShafik Yaghmour 
MightHaveChildren()1808306f76eSShafik Yaghmour   bool MightHaveChildren() override { return true; }
1818306f76eSShafik Yaghmour   bool Update() override;
CalculateNumChildren()1828306f76eSShafik Yaghmour   size_t CalculateNumChildren() override { return m_size; }
1838306f76eSShafik Yaghmour   ValueObjectSP GetChildAtIndex(size_t idx) override;
1848306f76eSShafik Yaghmour 
1858306f76eSShafik Yaghmour private:
1868306f76eSShafik Yaghmour   size_t m_size = 0;
1878306f76eSShafik Yaghmour };
1888306f76eSShafik Yaghmour } // namespace
1898306f76eSShafik Yaghmour 
Update()1908306f76eSShafik Yaghmour bool VariantFrontEnd::Update() {
1918306f76eSShafik Yaghmour   m_size = 0;
1928306f76eSShafik Yaghmour   ValueObjectSP impl_sp(
1938306f76eSShafik Yaghmour       m_backend.GetChildMemberWithName(ConstString("__impl"), true));
1948306f76eSShafik Yaghmour   if (!impl_sp)
1958306f76eSShafik Yaghmour     return false;
1968306f76eSShafik Yaghmour 
1978306f76eSShafik Yaghmour   LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
1988306f76eSShafik Yaghmour 
19997212121SRaphael Isemann   if (validity == LibcxxVariantIndexValidity::Invalid)
2008306f76eSShafik Yaghmour     return false;
2018306f76eSShafik Yaghmour 
20297212121SRaphael Isemann   if (validity == LibcxxVariantIndexValidity::NPos)
2038306f76eSShafik Yaghmour     return true;
2048306f76eSShafik Yaghmour 
2058306f76eSShafik Yaghmour   m_size = 1;
2068306f76eSShafik Yaghmour 
2078306f76eSShafik Yaghmour   return false;
2088306f76eSShafik Yaghmour }
2098306f76eSShafik Yaghmour 
GetChildAtIndex(size_t idx)2108306f76eSShafik Yaghmour ValueObjectSP VariantFrontEnd::GetChildAtIndex(size_t idx) {
2118306f76eSShafik Yaghmour   if (idx >= m_size)
2128306f76eSShafik Yaghmour     return ValueObjectSP();
2138306f76eSShafik Yaghmour 
2148306f76eSShafik Yaghmour   ValueObjectSP impl_sp(
2158306f76eSShafik Yaghmour       m_backend.GetChildMemberWithName(ConstString("__impl"), true));
2168306f76eSShafik Yaghmour 
2178306f76eSShafik Yaghmour   auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
2188306f76eSShafik Yaghmour 
2198306f76eSShafik Yaghmour   if (!optional_index_value)
2208306f76eSShafik Yaghmour     return ValueObjectSP();
2218306f76eSShafik Yaghmour 
2228306f76eSShafik Yaghmour   uint64_t index_value = *optional_index_value;
2238306f76eSShafik Yaghmour 
2248306f76eSShafik Yaghmour   ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
2258306f76eSShafik Yaghmour 
2268306f76eSShafik Yaghmour   if (!nth_head)
2278306f76eSShafik Yaghmour     return ValueObjectSP();
2288306f76eSShafik Yaghmour 
2298306f76eSShafik Yaghmour   CompilerType head_type = nth_head->GetCompilerType();
2308306f76eSShafik Yaghmour 
2318306f76eSShafik Yaghmour   if (!head_type)
2328306f76eSShafik Yaghmour     return ValueObjectSP();
2338306f76eSShafik Yaghmour 
2348306f76eSShafik Yaghmour   CompilerType template_type = head_type.GetTypeTemplateArgument(1);
2358306f76eSShafik Yaghmour 
2368306f76eSShafik Yaghmour   if (!template_type)
2378306f76eSShafik Yaghmour     return ValueObjectSP();
2388306f76eSShafik Yaghmour 
2398306f76eSShafik Yaghmour   ValueObjectSP head_value(
2408306f76eSShafik Yaghmour       nth_head->GetChildMemberWithName(ConstString("__value"), true));
2418306f76eSShafik Yaghmour 
2428306f76eSShafik Yaghmour   if (!head_value)
2438306f76eSShafik Yaghmour     return ValueObjectSP();
2448306f76eSShafik Yaghmour 
2450ed233c8SRaphael Isemann   return head_value->Clone(ConstString("Value"));
2468306f76eSShafik Yaghmour }
2478306f76eSShafik Yaghmour 
2488306f76eSShafik Yaghmour SyntheticChildrenFrontEnd *
LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)2498306f76eSShafik Yaghmour formatters::LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,
2508306f76eSShafik Yaghmour                                          lldb::ValueObjectSP valobj_sp) {
2518306f76eSShafik Yaghmour   if (valobj_sp)
2528306f76eSShafik Yaghmour     return new VariantFrontEnd(*valobj_sp);
2538306f76eSShafik Yaghmour   return nullptr;
2548306f76eSShafik Yaghmour }
255