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 
26 namespace lldb_private {
27 class SyntheticChildrenFrontEnd {
28 protected:
29   ValueObject &m_backend;
30 
31   void SetValid(bool valid) { m_valid = valid; }
32 
33   bool IsValid() { return m_valid; }
34 
35 public:
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 
81 protected:
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 
97 private:
98   bool m_valid;
99   SyntheticChildrenFrontEnd(const SyntheticChildrenFrontEnd &) = delete;
100   const SyntheticChildrenFrontEnd &
101   operator=(const SyntheticChildrenFrontEnd &) = delete;
102 };
103 
104 class SyntheticValueProviderFrontEnd : public SyntheticChildrenFrontEnd {
105 public:
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 
125 private:
126   SyntheticValueProviderFrontEnd(const SyntheticValueProviderFrontEnd &) =
127       delete;
128   const SyntheticValueProviderFrontEnd &
129   operator=(const SyntheticValueProviderFrontEnd &) = delete;
130 };
131 
132 class SyntheticChildren {
133 public:
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 
268 protected:
269   uint32_t m_my_revision;
270   Flags m_flags;
271 
272 private:
273   SyntheticChildren(const SyntheticChildren &) = delete;
274   const SyntheticChildren &operator=(const SyntheticChildren &) = delete;
275 };
276 
277 class TypeFilterImpl : public SyntheticChildren {
278   std::vector<std::string> m_expression_paths;
279 
280 public:
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 
353 private:
354   TypeFilterImpl(const TypeFilterImpl &) = delete;
355   const TypeFilterImpl &operator=(const TypeFilterImpl &) = delete;
356 };
357 
358 class CXXSyntheticChildren : public SyntheticChildren {
359 public:
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 
378 protected:
379   CreateFrontEndCallback m_create_callback;
380   std::string m_description;
381 
382 private:
383   CXXSyntheticChildren(const CXXSyntheticChildren &) = delete;
384   const CXXSyntheticChildren &operator=(const CXXSyntheticChildren &) = delete;
385 };
386 
387 class ScriptedSyntheticChildren : public SyntheticChildren {
388   std::string m_python_class;
389   std::string m_python_code;
390 
391 public:
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 
460 private:
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