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 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() = default;
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 = lldb::eTypeOptionCascade;
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 = 0;
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) {}
283
284  TypeFilterImpl(const SyntheticChildren::Flags &flags,
285                 const std::initializer_list<const char *> items)
286      : SyntheticChildren(flags) {
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) {
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