Coverage Report

Created: 2022-01-18 06:27

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