1//===-- TypeSynthetic.h -----------------------------------------*- C++ -*-===//
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#ifndef LLDB_DATAFORMATTERS_TYPESYNTHETIC_H
10#define LLDB_DATAFORMATTERS_TYPESYNTHETIC_H
11
12#include <cstdint>
13
14#include <functional>
15#include <initializer_list>
16#include <memory>
17#include <string>
18#include <vector>
19
20#include "lldb/lldb-enumerations.h"
21#include "lldb/lldb-public.h"
22
23#include "lldb/Core/ValueObject.h"
24#include "lldb/Utility/StructuredData.h"
25
26namespace lldb_private {
27class SyntheticChildrenFrontEnd {
28protected:
29 ValueObject &m_backend;
30
31 void SetValid(bool valid) { m_valid = valid; }
32
33 bool IsValid() { return m_valid; }
34
35public:
36 SyntheticChildrenFrontEnd(ValueObject &backend)
37 : m_backend(backend), m_valid(true) {}
38
39 virtual ~SyntheticChildrenFrontEnd() = default;
40
41 virtual size_t CalculateNumChildren() = 0;
42
43 virtual size_t CalculateNumChildren(uint32_t max) {
44 auto count = CalculateNumChildren();
45 return count <= max ? count : max;
46 }
47
48 virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx) = 0;
49
50 virtual size_t GetIndexOfChildWithName(ConstString name) = 0;
51
52 /// This function is assumed to always succeed and if it fails, the front-end
53 /// should know to deal with it in the correct way (most probably, by refusing
54 /// to return any children). The return value of \ref Update should actually
55 /// be interpreted as "ValueObjectSyntheticFilter cache is good/bad". If this
56 /// function returns \ref lldb::ChildCacheState::eReuse, \ref
57 /// ValueObjectSyntheticFilter is allowed to use the children it fetched
58 /// previously and cached. Otherwise, \ref ValueObjectSyntheticFilter must
59 /// throw away its cache, and query again for children.
60 virtual lldb::ChildCacheState Update() = 0;
61
62 // if this function returns false, then CalculateNumChildren() MUST return 0
63 // since UI frontends might validly decide not to inquire for children given
64 // a false return value from this call if it returns true, then
65 // CalculateNumChildren() can return any number >= 0 (0 being valid) it
66 // should if at all possible be more efficient than CalculateNumChildren()
67 virtual bool MightHaveChildren() = 0;
68
69 // if this function returns a non-null ValueObject, then the returned
70 // ValueObject will stand for this ValueObject whenever a "value" request is
71 // made to this ValueObject
72 virtual lldb::ValueObjectSP GetSyntheticValue() { return nullptr; }
73
74 // if this function returns a non-empty ConstString, then clients are
75 // expected to use the return as the name of the type of this ValueObject for
76 // display purposes
77 virtual ConstString GetSyntheticTypeName() { return ConstString(); }
78
79 typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
80 typedef std::unique_ptr<SyntheticChildrenFrontEnd> AutoPointer;
81
82protected:
83 lldb::ValueObjectSP
84 CreateValueObjectFromExpression(llvm::StringRef name,
85 llvm::StringRef expression,
86 const ExecutionContext &exe_ctx);
87
88 lldb::ValueObjectSP
89 CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address,
90 const ExecutionContext &exe_ctx,
91 CompilerType type);
92
93 lldb::ValueObjectSP CreateValueObjectFromData(llvm::StringRef name,
94 const DataExtractor &data,
95 const ExecutionContext &exe_ctx,
96 CompilerType type);
97
98private:
99 bool m_valid;
100 SyntheticChildrenFrontEnd(const SyntheticChildrenFrontEnd &) = delete;
101 const SyntheticChildrenFrontEnd &
102 operator=(const SyntheticChildrenFrontEnd &) = delete;
103};
104
105class SyntheticValueProviderFrontEnd : public SyntheticChildrenFrontEnd {
106public:
107 SyntheticValueProviderFrontEnd(ValueObject &backend)
108 : SyntheticChildrenFrontEnd(backend) {}
109
110 ~SyntheticValueProviderFrontEnd() override = default;
111
112 size_t CalculateNumChildren() override { return 0; }
113
114 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { return nullptr; }
115
116 size_t GetIndexOfChildWithName(ConstString name) override {
117 return UINT32_MAX;
118 }
119
120 lldb::ChildCacheState Update() override {
121 return lldb::ChildCacheState::eRefetch;
122 }
123
124 bool MightHaveChildren() override { return false; }
125
126 lldb::ValueObjectSP GetSyntheticValue() override = 0;
127
128private:
129 SyntheticValueProviderFrontEnd(const SyntheticValueProviderFrontEnd &) =
130 delete;
131 const SyntheticValueProviderFrontEnd &
132 operator=(const SyntheticValueProviderFrontEnd &) = delete;
133};
134
135class SyntheticChildren {
136public:
137 class Flags {
138 public:
139 Flags() = default;
140
141 Flags(const Flags &other) : m_flags(other.m_flags) {}
142
143 Flags(uint32_t value) : m_flags(value) {}
144
145 Flags &operator=(const Flags &rhs) {
146 if (&rhs != this)
147 m_flags = rhs.m_flags;
148
149 return *this;
150 }
151
152 Flags &operator=(const uint32_t &rhs) {
153 m_flags = rhs;
154 return *this;
155 }
156
157 Flags &Clear() {
158 m_flags = 0;
159 return *this;
160 }
161
162 bool GetCascades() const {
163 return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade;
164 }
165
166 Flags &SetCascades(bool value = true) {
167 if (value)
168 m_flags |= lldb::eTypeOptionCascade;
169 else
170 m_flags &= ~lldb::eTypeOptionCascade;
171 return *this;
172 }
173
174 bool GetSkipPointers() const {
175 return (m_flags & lldb::eTypeOptionSkipPointers) ==
176 lldb::eTypeOptionSkipPointers;
177 }
178
179 Flags &SetSkipPointers(bool value = true) {
180 if (value)
181 m_flags |= lldb::eTypeOptionSkipPointers;
182 else
183 m_flags &= ~lldb::eTypeOptionSkipPointers;
184 return *this;
185 }
186
187 bool GetSkipReferences() const {
188 return (m_flags & lldb::eTypeOptionSkipReferences) ==
189 lldb::eTypeOptionSkipReferences;
190 }
191
192 Flags &SetSkipReferences(bool value = true) {
193 if (value)
194 m_flags |= lldb::eTypeOptionSkipReferences;
195 else
196 m_flags &= ~lldb::eTypeOptionSkipReferences;
197 return *this;
198 }
199
200 bool GetNonCacheable() const {
201 return (m_flags & lldb::eTypeOptionNonCacheable) ==
202 lldb::eTypeOptionNonCacheable;
203 }
204
205 Flags &SetNonCacheable(bool value = true) {
206 if (value)
207 m_flags |= lldb::eTypeOptionNonCacheable;
208 else
209 m_flags &= ~lldb::eTypeOptionNonCacheable;
210 return *this;
211 }
212
213 bool GetFrontEndWantsDereference() const {
214 return (m_flags & lldb::eTypeOptionFrontEndWantsDereference) ==
215 lldb::eTypeOptionFrontEndWantsDereference;
216 }
217
218 Flags &SetFrontEndWantsDereference(bool value = true) {
219 if (value)
220 m_flags |= lldb::eTypeOptionFrontEndWantsDereference;
221 else
222 m_flags &= ~lldb::eTypeOptionFrontEndWantsDereference;
223 return *this;
224 }
225
226 uint32_t GetValue() { return m_flags; }
227
228 void SetValue(uint32_t value) { m_flags = value; }
229
230 private:
231 uint32_t m_flags = lldb::eTypeOptionCascade;
232 };
233
234 SyntheticChildren(const Flags &flags);
235
236 virtual ~SyntheticChildren();
237
238 bool Cascades() const { return m_flags.GetCascades(); }
239
240 bool SkipsPointers() const { return m_flags.GetSkipPointers(); }
241
242 bool SkipsReferences() const { return m_flags.GetSkipReferences(); }
243
244 bool NonCacheable() const { return m_flags.GetNonCacheable(); }
245
246 bool WantsDereference() const { return m_flags.GetFrontEndWantsDereference();}
247
248 void SetCascades(bool value) { m_flags.SetCascades(value); }
249
250 void SetSkipsPointers(bool value) { m_flags.SetSkipPointers(value); }
251
252 void SetSkipsReferences(bool value) { m_flags.SetSkipReferences(value); }
253
254 void SetNonCacheable(bool value) { m_flags.SetNonCacheable(value); }
255
256 uint32_t GetOptions() { return m_flags.GetValue(); }
257
258 void SetOptions(uint32_t value) { m_flags.SetValue(value); }
259
260 virtual bool IsScripted() = 0;
261
262 virtual std::string GetDescription() = 0;
263
264 virtual SyntheticChildrenFrontEnd::AutoPointer
265 GetFrontEnd(ValueObject &backend) = 0;
266
267 typedef std::shared_ptr<SyntheticChildren> SharedPointer;
268
269 uint32_t &GetRevision() { return m_my_revision; }
270
271protected:
272 uint32_t m_my_revision = 0;
273 Flags m_flags;
274
275private:
276 SyntheticChildren(const SyntheticChildren &) = delete;
277 const SyntheticChildren &operator=(const SyntheticChildren &) = delete;
278};
279
280class TypeFilterImpl : public SyntheticChildren {
281 std::vector<std::string> m_expression_paths;
282
283public:
284 TypeFilterImpl(const SyntheticChildren::Flags &flags)
285 : SyntheticChildren(flags) {}
286
287 TypeFilterImpl(const SyntheticChildren::Flags &flags,
288 const std::initializer_list<const char *> items)
289 : SyntheticChildren(flags) {
290 for (auto path : items)
291 AddExpressionPath(path);
292 }
293
294 void AddExpressionPath(const char *path) {
295 AddExpressionPath(path: std::string(path));
296 }
297
298 void Clear() { m_expression_paths.clear(); }
299
300 size_t GetCount() const { return m_expression_paths.size(); }
301
302 const char *GetExpressionPathAtIndex(size_t i) const {
303 return m_expression_paths[i].c_str();
304 }
305
306 bool SetExpressionPathAtIndex(size_t i, const char *path) {
307 return SetExpressionPathAtIndex(i, path: std::string(path));
308 }
309
310 void AddExpressionPath(const std::string &path);
311
312 bool SetExpressionPathAtIndex(size_t i, const std::string &path);
313
314 bool IsScripted() override { return false; }
315
316 std::string GetDescription() override;
317
318 class FrontEnd : public SyntheticChildrenFrontEnd {
319 public:
320 FrontEnd(TypeFilterImpl *flt, ValueObject &backend)
321 : SyntheticChildrenFrontEnd(backend), filter(flt) {}
322
323 ~FrontEnd() override = default;
324
325 size_t CalculateNumChildren() override { return filter->GetCount(); }
326
327 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
328 if (idx >= filter->GetCount())
329 return lldb::ValueObjectSP();
330 return m_backend.GetSyntheticExpressionPathChild(
331 expression: filter->GetExpressionPathAtIndex(i: idx), can_create: true);
332 }
333
334 lldb::ChildCacheState Update() override {
335 return lldb::ChildCacheState::eRefetch;
336 }
337
338 bool MightHaveChildren() override { return filter->GetCount() > 0; }
339
340 size_t GetIndexOfChildWithName(ConstString name) override;
341
342 typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
343
344 private:
345 TypeFilterImpl *filter;
346
347 FrontEnd(const FrontEnd &) = delete;
348 const FrontEnd &operator=(const FrontEnd &) = delete;
349 };
350
351 SyntheticChildrenFrontEnd::AutoPointer
352 GetFrontEnd(ValueObject &backend) override {
353 return SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(this, backend));
354 }
355
356 typedef std::shared_ptr<TypeFilterImpl> SharedPointer;
357
358private:
359 TypeFilterImpl(const TypeFilterImpl &) = delete;
360 const TypeFilterImpl &operator=(const TypeFilterImpl &) = delete;
361};
362
363class CXXSyntheticChildren : public SyntheticChildren {
364public:
365 typedef std::function<SyntheticChildrenFrontEnd *(CXXSyntheticChildren *,
366 lldb::ValueObjectSP)>
367 CreateFrontEndCallback;
368 CXXSyntheticChildren(const SyntheticChildren::Flags &flags,
369 const char *description, CreateFrontEndCallback callback);
370
371 virtual ~CXXSyntheticChildren();
372
373 bool IsScripted() override { return false; }
374
375 std::string GetDescription() override;
376
377 SyntheticChildrenFrontEnd::AutoPointer
378 GetFrontEnd(ValueObject &backend) override {
379 return SyntheticChildrenFrontEnd::AutoPointer(
380 m_create_callback(this, backend.GetSP()));
381 }
382
383protected:
384 CreateFrontEndCallback m_create_callback;
385 std::string m_description;
386
387private:
388 CXXSyntheticChildren(const CXXSyntheticChildren &) = delete;
389 const CXXSyntheticChildren &operator=(const CXXSyntheticChildren &) = delete;
390};
391
392class ScriptedSyntheticChildren : public SyntheticChildren {
393 std::string m_python_class;
394 std::string m_python_code;
395
396public:
397 ScriptedSyntheticChildren(const SyntheticChildren::Flags &flags,
398 const char *pclass, const char *pcode = nullptr)
399 : SyntheticChildren(flags) {
400 if (pclass)
401 m_python_class = pclass;
402 if (pcode)
403 m_python_code = pcode;
404 }
405
406 const char *GetPythonClassName() { return m_python_class.c_str(); }
407
408 const char *GetPythonCode() { return m_python_code.c_str(); }
409
410 void SetPythonClassName(const char *fname) {
411 m_python_class.assign(s: fname);
412 m_python_code.clear();
413 }
414
415 void SetPythonCode(const char *script) { m_python_code.assign(s: script); }
416
417 std::string GetDescription() override;
418
419 bool IsScripted() override { return true; }
420
421 class FrontEnd : public SyntheticChildrenFrontEnd {
422 public:
423 FrontEnd(std::string pclass, ValueObject &backend);
424
425 ~FrontEnd() override;
426
427 bool IsValid();
428
429 size_t CalculateNumChildren() override;
430
431 size_t CalculateNumChildren(uint32_t max) override;
432
433 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
434
435 lldb::ChildCacheState Update() override;
436
437 bool MightHaveChildren() override;
438
439 size_t GetIndexOfChildWithName(ConstString name) override;
440
441 lldb::ValueObjectSP GetSyntheticValue() override;
442
443 ConstString GetSyntheticTypeName() override;
444
445 typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
446
447 private:
448 std::string m_python_class;
449 StructuredData::ObjectSP m_wrapper_sp;
450 ScriptInterpreter *m_interpreter;
451
452 FrontEnd(const FrontEnd &) = delete;
453 const FrontEnd &operator=(const FrontEnd &) = delete;
454 };
455
456 SyntheticChildrenFrontEnd::AutoPointer
457 GetFrontEnd(ValueObject &backend) override {
458 auto synth_ptr = SyntheticChildrenFrontEnd::AutoPointer(
459 new FrontEnd(m_python_class, backend));
460 if (synth_ptr && ((FrontEnd *)synth_ptr.get())->IsValid())
461 return synth_ptr;
462 return nullptr;
463 }
464
465private:
466 ScriptedSyntheticChildren(const ScriptedSyntheticChildren &) = delete;
467 const ScriptedSyntheticChildren &
468 operator=(const ScriptedSyntheticChildren &) = delete;
469};
470} // namespace lldb_private
471
472#endif // LLDB_DATAFORMATTERS_TYPESYNTHETIC_H
473

source code of lldb/include/lldb/DataFormatters/TypeSynthetic.h