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