Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- LibCxxVariant.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-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "LibCxxVariant.h"
10
#include "lldb/DataFormatters/FormattersHelpers.h"
11
12
#include "llvm/ADT/Optional.h"
13
#include "llvm/ADT/ScopeExit.h"
14
15
using namespace lldb;
16
using namespace lldb_private;
17
18
// libc++ variant implementation contains two members that we care about both
19
// are contained in the __impl member.
20
// - __index which tells us which of the variadic template types is the active
21
//   type for the variant
22
// - __data is a variadic union which recursively contains itself as member
23
//   which refers to the tailing variadic types.
24
//   - __head which refers to the leading non pack type
25
//     - __value refers to the actual value contained
26
//   - __tail which refers to the remaining pack types
27
//
28
// e.g. given std::variant<int,double,char> v1
29
//
30
// (lldb) frame var -R v1.__impl.__data
31
//(... __union<... 0, int, double, char>) v1.__impl.__data = {
32
// ...
33
//  __head = {
34
//    __value = ...
35
//  }
36
//  __tail = {
37
//  ...
38
//    __head = {
39
//      __value = ...
40
//    }
41
//    __tail = {
42
//    ...
43
//      __head = {
44
//        __value = ...
45
//  ...
46
//
47
// So given
48
// - __index equal to 0 the active value is contained in
49
//
50
//     __data.__head.__value
51
//
52
// - __index equal to 1 the active value is contained in
53
//
54
//     __data.__tail.__head.__value
55
//
56
// - __index equal to 2 the active value is contained in
57
//
58
//      __data.__tail.__tail.__head.__value
59
//
60
61
namespace {
62
// libc++ std::variant index could have one of three states
63
// 1) Valid, we can obtain it and its not variant_npos
64
// 2) Invalid, we can't obtain it or it is not a type we expect
65
// 3) NPos, its value is variant_npos which means the variant has no value
66
enum class LibcxxVariantIndexValidity { Valid, Invalid, NPos };
67
68
LibcxxVariantIndexValidity
69
72
LibcxxVariantGetIndexValidity(ValueObjectSP &impl_sp) {
70
72
  ValueObjectSP index_sp(
71
72
      impl_sp->GetChildMemberWithName(ConstString("__index"), true));
72
73
72
  if (!index_sp)
74
0
    return LibcxxVariantIndexValidity::Invalid;
75
76
72
  int64_t index_value = index_sp->GetValueAsSigned(0);
77
78
72
  if (index_value == -1)
79
9
    return LibcxxVariantIndexValidity::NPos;
80
81
63
  return LibcxxVariantIndexValidity::Valid;
82
72
}
83
84
42
llvm::Optional<uint64_t> LibcxxVariantIndexValue(ValueObjectSP &impl_sp) {
85
42
  ValueObjectSP index_sp(
86
42
      impl_sp->GetChildMemberWithName(ConstString("__index"), true));
87
88
42
  if (!index_sp)
89
0
    return {};
90
91
42
  return {index_sp->GetValueAsUnsigned(0)};
92
42
}
93
94
42
ValueObjectSP LibcxxVariantGetNthHead(ValueObjectSP &impl_sp, uint64_t index) {
95
42
  ValueObjectSP data_sp(
96
42
      impl_sp->GetChildMemberWithName(ConstString("__data"), true));
97
98
42
  if (!data_sp)
99
0
    return ValueObjectSP{};
100
101
42
  ValueObjectSP current_level = data_sp;
102
66
  for (uint64_t n = index; n != 0; 
--n24
) {
103
24
    ValueObjectSP tail_sp(
104
24
        current_level->GetChildMemberWithName(ConstString("__tail"), true));
105
106
24
    if (!tail_sp)
107
0
      return ValueObjectSP{};
108
109
24
    current_level = tail_sp;
110
24
  }
111
112
42
  return current_level->GetChildMemberWithName(ConstString("__head"), true);
113
42
}
114
} // namespace
115
116
namespace lldb_private {
117
namespace formatters {
118
bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream,
119
24
                                  const TypeSummaryOptions &options) {
120
24
  ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
121
24
  if (!valobj_sp)
122
0
    return false;
123
124
24
  ValueObjectSP impl_sp(
125
24
      valobj_sp->GetChildMemberWithName(ConstString("__impl"), true));
126
127
24
  if (!impl_sp)
128
0
    return false;
129
130
24
  LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
131
132
24
  if (validity == LibcxxVariantIndexValidity::Invalid)
133
0
    return false;
134
135
24
  if (validity == LibcxxVariantIndexValidity::NPos) {
136
3
    stream.Printf(" No Value");
137
3
    return true;
138
3
  }
139
140
21
  auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
141
142
21
  if (!optional_index_value)
143
0
    return false;
144
145
21
  uint64_t index_value = *optional_index_value;
146
147
21
  ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
148
149
21
  if (!nth_head)
150
0
    return false;
151
152
21
  CompilerType head_type = nth_head->GetCompilerType();
153
154
21
  if (!head_type)
155
0
    return false;
156
157
21
  CompilerType template_type = head_type.GetTypeTemplateArgument(1);
158
159
21
  if (!template_type)
160
0
    return false;
161
162
21
  stream << " Active Type = " << template_type.GetDisplayTypeName() << " ";
163
164
21
  return true;
165
21
}
166
} // namespace formatters
167
} // namespace lldb_private
168
169
namespace {
170
class VariantFrontEnd : public SyntheticChildrenFrontEnd {
171
public:
172
24
  VariantFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
173
24
    Update();
174
24
  }
175
176
0
  size_t GetIndexOfChildWithName(ConstString name) override {
177
0
    return formatters::ExtractIndexFromString(name.GetCString());
178
0
  }
179
180
3
  bool MightHaveChildren() override { return true; }
181
  bool Update() override;
182
24
  size_t CalculateNumChildren() override { return m_size; }
183
  ValueObjectSP GetChildAtIndex(size_t idx) override;
184
185
private:
186
  size_t m_size = 0;
187
};
188
} // namespace
189
190
48
bool VariantFrontEnd::Update() {
191
48
  m_size = 0;
192
48
  ValueObjectSP impl_sp(
193
48
      m_backend.GetChildMemberWithName(ConstString("__impl"), true));
194
48
  if (!impl_sp)
195
0
    return false;
196
197
48
  LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
198
199
48
  if (validity == LibcxxVariantIndexValidity::Invalid)
200
0
    return false;
201
202
48
  if (validity == LibcxxVariantIndexValidity::NPos)
203
6
    return true;
204
205
42
  m_size = 1;
206
207
42
  return false;
208
48
}
209
210
21
ValueObjectSP VariantFrontEnd::GetChildAtIndex(size_t idx) {
211
21
  if (idx >= m_size)
212
0
    return ValueObjectSP();
213
214
21
  ValueObjectSP impl_sp(
215
21
      m_backend.GetChildMemberWithName(ConstString("__impl"), true));
216
217
21
  auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
218
219
21
  if (!optional_index_value)
220
0
    return ValueObjectSP();
221
222
21
  uint64_t index_value = *optional_index_value;
223
224
21
  ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
225
226
21
  if (!nth_head)
227
0
    return ValueObjectSP();
228
229
21
  CompilerType head_type = nth_head->GetCompilerType();
230
231
21
  if (!head_type)
232
0
    return ValueObjectSP();
233
234
21
  CompilerType template_type = head_type.GetTypeTemplateArgument(1);
235
236
21
  if (!template_type)
237
0
    return ValueObjectSP();
238
239
21
  ValueObjectSP head_value(
240
21
      nth_head->GetChildMemberWithName(ConstString("__value"), true));
241
242
21
  if (!head_value)
243
0
    return ValueObjectSP();
244
245
21
  return head_value->Clone(ConstString("Value"));
246
21
}
247
248
SyntheticChildrenFrontEnd *
249
formatters::LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,
250
24
                                         lldb::ValueObjectSP valobj_sp) {
251
24
  if (valobj_sp)
252
24
    return new VariantFrontEnd(*valobj_sp);
253
0
  return nullptr;
254
24
}