Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Core/ValueObjectSyntheticFilter.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- ValueObjectSyntheticFilter.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 "lldb/Core/ValueObjectSyntheticFilter.h"
10
11
#include "lldb/Core/Value.h"
12
#include "lldb/Core/ValueObject.h"
13
#include "lldb/DataFormatters/TypeSynthetic.h"
14
#include "lldb/Target/ExecutionContext.h"
15
#include "lldb/Utility/ConstString.h"
16
#include "lldb/Utility/LLDBLog.h"
17
#include "lldb/Utility/Log.h"
18
#include "lldb/Utility/Status.h"
19
20
#include "llvm/ADT/STLExtras.h"
21
#include <optional>
22
23
namespace lldb_private {
24
class Declaration;
25
}
26
27
using namespace lldb_private;
28
29
class DummySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
30
public:
31
  DummySyntheticFrontEnd(ValueObject &backend)
32
44
      : SyntheticChildrenFrontEnd(backend) {}
33
34
9
  size_t CalculateNumChildren() override { return m_backend.GetNumChildren(); }
35
36
36
  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
37
36
    return m_backend.GetChildAtIndex(idx);
38
36
  }
39
40
0
  size_t GetIndexOfChildWithName(ConstString name) override {
41
0
    return m_backend.GetIndexOfChildWithName(name);
42
0
  }
43
44
2
  bool MightHaveChildren() override { return true; }
45
46
42
  bool Update() override { return false; }
47
};
48
49
ValueObjectSynthetic::ValueObjectSynthetic(ValueObject &parent,
50
                                           lldb::SyntheticChildrenSP filter)
51
1.84k
    : ValueObject(parent), m_synth_sp(std::move(filter)), m_children_byindex(),
52
1.84k
      m_name_toindex(), m_synthetic_children_cache(),
53
      m_synthetic_children_count(UINT32_MAX),
54
1.84k
      m_parent_type_name(parent.GetTypeName()),
55
1.84k
      m_might_have_children(eLazyBoolCalculate),
56
1.84k
      m_provides_value(eLazyBoolCalculate) {
57
1.84k
  SetName(parent.GetName());
58
  // Copying the data of an incomplete type won't work as it has no byte size.
59
1.84k
  if (m_parent->GetCompilerType().IsCompleteType())
60
1.84k
    CopyValueData(m_parent);
61
1.84k
  CreateSynthFilter();
62
1.84k
}
63
64
1.55k
ValueObjectSynthetic::~ValueObjectSynthetic() = default;
65
66
33.8k
CompilerType ValueObjectSynthetic::GetCompilerTypeImpl() {
67
33.8k
  return m_parent->GetCompilerType();
68
33.8k
}
69
70
0
ConstString ValueObjectSynthetic::GetTypeName() {
71
0
  return m_parent->GetTypeName();
72
0
}
73
74
4.88k
ConstString ValueObjectSynthetic::GetQualifiedTypeName() {
75
4.88k
  return m_parent->GetQualifiedTypeName();
76
4.88k
}
77
78
1.67k
ConstString ValueObjectSynthetic::GetDisplayTypeName() {
79
1.67k
  if (ConstString synth_name = m_synth_filter_up->GetSyntheticTypeName())
80
6
    return synth_name;
81
82
1.67k
  return m_parent->GetDisplayTypeName();
83
1.67k
}
84
85
863
size_t ValueObjectSynthetic::CalculateNumChildren(uint32_t max) {
86
863
  Log *log = GetLog(LLDBLog::DataFormatters);
87
88
863
  UpdateValueIfNeeded();
89
863
  if (m_synthetic_children_count < UINT32_MAX)
90
0
    return m_synthetic_children_count <= max ? m_synthetic_children_count : max;
91
92
863
  if (max < UINT32_MAX) {
93
6
    size_t num_children = m_synth_filter_up->CalculateNumChildren(max);
94
6
    LLDB_LOGF(log,
95
6
              "[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
96
6
              "%s and type %s, the filter returned %zu child values",
97
6
              GetName().AsCString(), GetTypeName().AsCString(), num_children);
98
6
    return num_children;
99
857
  } else {
100
857
    size_t num_children = (m_synthetic_children_count =
101
857
                               m_synth_filter_up->CalculateNumChildren(max));
102
857
    LLDB_LOGF(log,
103
857
              "[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
104
857
              "%s and type %s, the filter returned %zu child values",
105
857
              GetName().AsCString(), GetTypeName().AsCString(), num_children);
106
857
    return num_children;
107
857
  }
108
863
}
109
110
lldb::ValueObjectSP
111
243
ValueObjectSynthetic::GetDynamicValue(lldb::DynamicValueType valueType) {
112
243
  if (!m_parent)
113
0
    return lldb::ValueObjectSP();
114
243
  if (IsDynamic() && 
GetDynamicValueType() == valueType0
)
115
0
    return GetSP();
116
243
  return m_parent->GetDynamicValue(valueType);
117
243
}
118
119
447
bool ValueObjectSynthetic::MightHaveChildren() {
120
447
  if (m_might_have_children == eLazyBoolCalculate)
121
328
    m_might_have_children =
122
328
        (m_synth_filter_up->MightHaveChildren() ? 
eLazyBoolYes199
:
eLazyBoolNo129
);
123
447
  return (m_might_have_children != eLazyBoolNo);
124
447
}
125
126
2
std::optional<uint64_t> ValueObjectSynthetic::GetByteSize() {
127
2
  return m_parent->GetByteSize();
128
2
}
129
130
2
lldb::ValueType ValueObjectSynthetic::GetValueType() const {
131
2
  return m_parent->GetValueType();
132
2
}
133
134
1.84k
void ValueObjectSynthetic::CreateSynthFilter() {
135
1.84k
  ValueObject *valobj_for_frontend = m_parent;
136
1.84k
  if (m_synth_sp->WantsDereference())
137
274
  {
138
274
    CompilerType type = m_parent->GetCompilerType();
139
274
    if (type.IsValid() && type.IsPointerOrReferenceType())
140
48
    {
141
48
      Status error;
142
48
      lldb::ValueObjectSP deref_sp = m_parent->Dereference(error);
143
48
      if (error.Success())
144
46
        valobj_for_frontend = deref_sp.get();
145
48
    }
146
274
  }
147
1.84k
  m_synth_filter_up = (m_synth_sp->GetFrontEnd(*valobj_for_frontend));
148
1.84k
  if (!m_synth_filter_up)
149
44
    m_synth_filter_up = std::make_unique<DummySyntheticFrontEnd>(*m_parent);
150
1.84k
}
151
152
1.66k
bool ValueObjectSynthetic::UpdateValue() {
153
1.66k
  Log *log = GetLog(LLDBLog::DataFormatters);
154
155
1.66k
  SetValueIsValid(false);
156
1.66k
  m_error.Clear();
157
158
1.66k
  if (!m_parent->UpdateValueIfNeeded(false)) {
159
    // our parent could not update.. as we are meaningless without a parent,
160
    // just stop
161
17
    if (m_parent->GetError().Fail())
162
17
      m_error = m_parent->GetError();
163
17
    return false;
164
17
  }
165
166
  // Regenerate the synthetic filter if our typename changes. When the (dynamic)
167
  // type of an object changes, so does their synthetic filter of choice.
168
1.64k
  ConstString new_parent_type_name = m_parent->GetTypeName();
169
1.64k
  if (new_parent_type_name != m_parent_type_name) {
170
0
    LLDB_LOGF(log,
171
0
              "[ValueObjectSynthetic::UpdateValue] name=%s, type changed "
172
0
              "from %s to %s, recomputing synthetic filter",
173
0
              GetName().AsCString(), m_parent_type_name.AsCString(),
174
0
              new_parent_type_name.AsCString());
175
0
    m_parent_type_name = new_parent_type_name;
176
0
    CreateSynthFilter();
177
0
  }
178
179
  // let our backend do its update
180
1.64k
  if (!m_synth_filter_up->Update()) {
181
1.24k
    LLDB_LOGF(log,
182
1.24k
              "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
183
1.24k
              "filter said caches are stale - clearing",
184
1.24k
              GetName().AsCString());
185
    // filter said that cached values are stale
186
1.24k
    {
187
1.24k
      std::lock_guard<std::mutex> guard(m_child_mutex);
188
1.24k
      m_children_byindex.clear();
189
1.24k
      m_name_toindex.clear();
190
1.24k
    }
191
    // usually, an object's value can change but this does not alter its
192
    // children count for a synthetic VO that might indeed happen, so we need
193
    // to tell the upper echelons that they need to come back to us asking for
194
    // children
195
1.24k
    m_flags.m_children_count_valid = false;
196
1.24k
    {
197
1.24k
      std::lock_guard<std::mutex> guard(m_child_mutex);
198
1.24k
      m_synthetic_children_cache.clear();
199
1.24k
    }
200
1.24k
    m_synthetic_children_count = UINT32_MAX;
201
1.24k
    m_might_have_children = eLazyBoolCalculate;
202
1.24k
  } else {
203
403
    LLDB_LOGF(log,
204
403
              "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
205
403
              "filter said caches are still valid",
206
403
              GetName().AsCString());
207
403
  }
208
209
1.64k
  m_provides_value = eLazyBoolCalculate;
210
211
1.64k
  lldb::ValueObjectSP synth_val(m_synth_filter_up->GetSyntheticValue());
212
213
1.64k
  if (synth_val && 
synth_val->CanProvideValue()12
) {
214
12
    LLDB_LOGF(log,
215
12
              "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
216
12
              "filter said it can provide a value",
217
12
              GetName().AsCString());
218
219
12
    m_provides_value = eLazyBoolYes;
220
12
    CopyValueData(synth_val.get());
221
1.63k
  } else {
222
1.63k
    LLDB_LOGF(log,
223
1.63k
              "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
224
1.63k
              "filter said it will not provide a value",
225
1.63k
              GetName().AsCString());
226
227
1.63k
    m_provides_value = eLazyBoolNo;
228
    // Copying the data of an incomplete type won't work as it has no byte size.
229
1.63k
    if (m_parent->GetCompilerType().IsCompleteType())
230
1.62k
      CopyValueData(m_parent);
231
1.63k
  }
232
233
1.64k
  SetValueIsValid(true);
234
1.64k
  return true;
235
1.66k
}
236
237
lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(size_t idx,
238
24.1k
                                                          bool can_create) {
239
24.1k
  Log *log = GetLog(LLDBLog::DataFormatters);
240
241
24.1k
  LLDB_LOGF(log,
242
24.1k
            "[ValueObjectSynthetic::GetChildAtIndex] name=%s, retrieving "
243
24.1k
            "child at index %zu",
244
24.1k
            GetName().AsCString(), idx);
245
246
24.1k
  UpdateValueIfNeeded();
247
248
24.1k
  ValueObject *valobj;
249
24.1k
  bool child_is_cached;
250
24.1k
  {
251
24.1k
    std::lock_guard<std::mutex> guard(m_child_mutex);
252
24.1k
    auto cached_child_it = m_children_byindex.find(idx);
253
24.1k
    child_is_cached = cached_child_it != m_children_byindex.end();
254
24.1k
    if (child_is_cached)
255
12.9k
      valobj = cached_child_it->second;
256
24.1k
  }
257
258
24.1k
  if (!child_is_cached) {
259
11.1k
    if (can_create && m_synth_filter_up != nullptr) {
260
11.1k
      LLDB_LOGF(log,
261
11.1k
                "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
262
11.1k
                "index %zu not cached and will be created",
263
11.1k
                GetName().AsCString(), idx);
264
265
11.1k
      lldb::ValueObjectSP synth_guy = m_synth_filter_up->GetChildAtIndex(idx);
266
267
11.1k
      LLDB_LOGF(
268
11.1k
          log,
269
11.1k
          "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at index "
270
11.1k
          "%zu created as %p (is "
271
11.1k
          "synthetic: %s)",
272
11.1k
          GetName().AsCString(), idx, static_cast<void *>(synth_guy.get()),
273
11.1k
          synth_guy.get()
274
11.1k
              ? (synth_guy->IsSyntheticChildrenGenerated() ? "yes" : "no")
275
11.1k
              : "no");
276
277
11.1k
      if (!synth_guy)
278
45
        return synth_guy;
279
280
11.1k
      {
281
11.1k
        std::lock_guard<std::mutex> guard(m_child_mutex);
282
11.1k
        if (synth_guy->IsSyntheticChildrenGenerated())
283
9.23k
          m_synthetic_children_cache.push_back(synth_guy);
284
11.1k
        m_children_byindex[idx] = synth_guy.get();
285
11.1k
      }
286
11.1k
      synth_guy->SetPreferredDisplayLanguageIfNeeded(
287
11.1k
          GetPreferredDisplayLanguage());
288
11.1k
      return synth_guy;
289
11.1k
    } else {
290
0
      LLDB_LOGF(log,
291
0
                "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
292
0
                "index %zu not cached and cannot "
293
0
                "be created (can_create = %s, synth_filter = %p)",
294
0
                GetName().AsCString(), idx, can_create ? "yes" : "no",
295
0
                static_cast<void *>(m_synth_filter_up.get()));
296
297
0
      return lldb::ValueObjectSP();
298
0
    }
299
12.9k
  } else {
300
12.9k
    LLDB_LOGF(log,
301
12.9k
              "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
302
12.9k
              "index %zu cached as %p",
303
12.9k
              GetName().AsCString(), idx, static_cast<void *>(valobj));
304
305
12.9k
    return valobj->GetSP();
306
12.9k
  }
307
24.1k
}
308
309
lldb::ValueObjectSP
310
ValueObjectSynthetic::GetChildMemberWithName(llvm::StringRef name,
311
57
                                             bool can_create) {
312
57
  UpdateValueIfNeeded();
313
314
57
  uint32_t index = GetIndexOfChildWithName(name);
315
316
57
  if (index == UINT32_MAX)
317
6
    return lldb::ValueObjectSP();
318
319
51
  return GetChildAtIndex(index, can_create);
320
57
}
321
322
57
size_t ValueObjectSynthetic::GetIndexOfChildWithName(llvm::StringRef name_ref) {
323
57
  UpdateValueIfNeeded();
324
325
57
  ConstString name(name_ref);
326
327
57
  uint32_t found_index = UINT32_MAX;
328
57
  bool did_find;
329
57
  {
330
57
    std::lock_guard<std::mutex> guard(m_child_mutex);
331
57
    auto name_to_index = m_name_toindex.find(name.GetCString());
332
57
    did_find = name_to_index != m_name_toindex.end();
333
57
    if (did_find)
334
10
      found_index = name_to_index->second;
335
57
  }
336
337
57
  if (!did_find && 
m_synth_filter_up != nullptr47
) {
338
47
    uint32_t index = m_synth_filter_up->GetIndexOfChildWithName(name);
339
47
    if (index == UINT32_MAX)
340
6
      return index;
341
41
    std::lock_guard<std::mutex> guard(m_child_mutex);
342
41
    m_name_toindex[name.GetCString()] = index;
343
41
    return index;
344
47
  } else 
if (10
!did_find10
&&
m_synth_filter_up == nullptr0
)
345
0
    return UINT32_MAX;
346
10
  else /*if (iter != m_name_toindex.end())*/
347
10
    return found_index;
348
57
}
349
350
3.19k
bool ValueObjectSynthetic::IsInScope() { return m_parent->IsInScope(); }
351
352
270
lldb::ValueObjectSP ValueObjectSynthetic::GetNonSyntheticValue() {
353
270
  return m_parent->GetSP();
354
270
}
355
356
3.48k
void ValueObjectSynthetic::CopyValueData(ValueObject *source) {
357
3.48k
  m_value = (source->UpdateValueIfNeeded(), source->GetValue());
358
3.48k
  ExecutionContext exe_ctx(GetExecutionContextRef());
359
3.48k
  m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
360
3.48k
}
361
362
3.32k
bool ValueObjectSynthetic::CanProvideValue() {
363
3.32k
  if (!UpdateValueIfNeeded())
364
0
    return false;
365
3.32k
  if (m_provides_value == eLazyBoolYes)
366
28
    return true;
367
3.29k
  return m_parent->CanProvideValue();
368
3.32k
}
369
370
bool ValueObjectSynthetic::SetValueFromCString(const char *value_str,
371
2
                                               Status &error) {
372
2
  return m_parent->SetValueFromCString(value_str, error);
373
2
}
374
375
6
void ValueObjectSynthetic::SetFormat(lldb::Format format) {
376
6
  if (m_parent) {
377
6
    m_parent->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
378
6
    m_parent->SetFormat(format);
379
6
  }
380
6
  this->ValueObject::SetFormat(format);
381
6
  this->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
382
6
}
383
384
void ValueObjectSynthetic::SetPreferredDisplayLanguage(
385
0
    lldb::LanguageType lang) {
386
0
  this->ValueObject::SetPreferredDisplayLanguage(lang);
387
0
  if (m_parent)
388
0
    m_parent->SetPreferredDisplayLanguage(lang);
389
0
}
390
391
11.9k
lldb::LanguageType ValueObjectSynthetic::GetPreferredDisplayLanguage() {
392
11.9k
  if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {
393
11.9k
    if (m_parent)
394
11.9k
      return m_parent->GetPreferredDisplayLanguage();
395
0
    return lldb::eLanguageTypeUnknown;
396
11.9k
  } else
397
6
    return m_preferred_display_language;
398
11.9k
}
399
400
2
bool ValueObjectSynthetic::IsSyntheticChildrenGenerated() {
401
2
  if (m_parent)
402
2
    return m_parent->IsSyntheticChildrenGenerated();
403
0
  return false;
404
2
}
405
406
0
void ValueObjectSynthetic::SetSyntheticChildrenGenerated(bool b) {
407
0
  if (m_parent)
408
0
    m_parent->SetSyntheticChildrenGenerated(b);
409
0
  this->ValueObject::SetSyntheticChildrenGenerated(b);
410
0
}
411
412
1
bool ValueObjectSynthetic::GetDeclaration(Declaration &decl) {
413
1
  if (m_parent)
414
1
    return m_parent->GetDeclaration(decl);
415
416
0
  return ValueObject::GetDeclaration(decl);
417
1
}
418
419
0
uint64_t ValueObjectSynthetic::GetLanguageFlags() {
420
0
  if (m_parent)
421
0
    return m_parent->GetLanguageFlags();
422
0
  return this->ValueObject::GetLanguageFlags();
423
0
}
424
425
0
void ValueObjectSynthetic::SetLanguageFlags(uint64_t flags) {
426
0
  if (m_parent)
427
0
    m_parent->SetLanguageFlags(flags);
428
0
  else
429
0
    this->ValueObject::SetLanguageFlags(flags);
430
0
}