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_TypeSynthetic_h_
10 #define lldb_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 
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   DISALLOW_COPY_AND_ASSIGN(SyntheticChildrenFrontEnd);
100 };
101 
102 class SyntheticValueProviderFrontEnd : public SyntheticChildrenFrontEnd {
103 public:
104   SyntheticValueProviderFrontEnd(ValueObject &backend)
105       : SyntheticChildrenFrontEnd(backend) {}
106 
107   ~SyntheticValueProviderFrontEnd() override = default;
108 
109   size_t CalculateNumChildren() override { return 0; }
110 
111   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { return nullptr; }
112 
113   size_t GetIndexOfChildWithName(ConstString name) override {
114     return UINT32_MAX;
115   }
116 
117   bool Update() override { return false; }
118 
119   bool MightHaveChildren() override { return false; }
120 
121   lldb::ValueObjectSP GetSyntheticValue() override = 0;
122 
123 private:
124   DISALLOW_COPY_AND_ASSIGN(SyntheticValueProviderFrontEnd);
125 };
126 
127 class SyntheticChildren {
128 public:
129   class Flags {
130   public:
131     Flags() : m_flags(lldb::eTypeOptionCascade) {}
132 
133     Flags(const Flags &other) : m_flags(other.m_flags) {}
134 
135     Flags(uint32_t value) : m_flags(value) {}
136 
137     Flags &operator=(const Flags &rhs) {
138       if (&rhs != this)
139         m_flags = rhs.m_flags;
140 
141       return *this;
142     }
143 
144     Flags &operator=(const uint32_t &rhs) {
145       m_flags = rhs;
146       return *this;
147     }
148 
149     Flags &Clear() {
150       m_flags = 0;
151       return *this;
152     }
153 
154     bool GetCascades() const {
155       return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade;
156     }
157 
158     Flags &SetCascades(bool value = true) {
159       if (value)
160         m_flags |= lldb::eTypeOptionCascade;
161       else
162         m_flags &= ~lldb::eTypeOptionCascade;
163       return *this;
164     }
165 
166     bool GetSkipPointers() const {
167       return (m_flags & lldb::eTypeOptionSkipPointers) ==
168              lldb::eTypeOptionSkipPointers;
169     }
170 
171     Flags &SetSkipPointers(bool value = true) {
172       if (value)
173         m_flags |= lldb::eTypeOptionSkipPointers;
174       else
175         m_flags &= ~lldb::eTypeOptionSkipPointers;
176       return *this;
177     }
178 
179     bool GetSkipReferences() const {
180       return (m_flags & lldb::eTypeOptionSkipReferences) ==
181              lldb::eTypeOptionSkipReferences;
182     }
183 
184     Flags &SetSkipReferences(bool value = true) {
185       if (value)
186         m_flags |= lldb::eTypeOptionSkipReferences;
187       else
188         m_flags &= ~lldb::eTypeOptionSkipReferences;
189       return *this;
190     }
191 
192     bool GetNonCacheable() const {
193       return (m_flags & lldb::eTypeOptionNonCacheable) ==
194              lldb::eTypeOptionNonCacheable;
195     }
196 
197     Flags &SetNonCacheable(bool value = true) {
198       if (value)
199         m_flags |= lldb::eTypeOptionNonCacheable;
200       else
201         m_flags &= ~lldb::eTypeOptionNonCacheable;
202       return *this;
203     }
204 
205     bool GetFrontEndWantsDereference() const {
206       return (m_flags & lldb::eTypeOptionFrontEndWantsDereference) ==
207              lldb::eTypeOptionFrontEndWantsDereference;
208     }
209 
210     Flags &SetFrontEndWantsDereference(bool value = true) {
211       if (value)
212         m_flags |= lldb::eTypeOptionFrontEndWantsDereference;
213       else
214         m_flags &= ~lldb::eTypeOptionFrontEndWantsDereference;
215       return *this;
216     }
217 
218     uint32_t GetValue() { return m_flags; }
219 
220     void SetValue(uint32_t value) { m_flags = value; }
221 
222   private:
223     uint32_t m_flags;
224   };
225 
226   SyntheticChildren(const Flags &flags) : m_flags(flags) {}
227 
228   virtual ~SyntheticChildren() = default;
229 
230   bool Cascades() const { return m_flags.GetCascades(); }
231 
232   bool SkipsPointers() const { return m_flags.GetSkipPointers(); }
233 
234   bool SkipsReferences() const { return m_flags.GetSkipReferences(); }
235 
236   bool NonCacheable() const { return m_flags.GetNonCacheable(); }
237 
238   bool WantsDereference() const { return m_flags.GetFrontEndWantsDereference();}
239 
240   void SetCascades(bool value) { m_flags.SetCascades(value); }
241 
242   void SetSkipsPointers(bool value) { m_flags.SetSkipPointers(value); }
243 
244   void SetSkipsReferences(bool value) { m_flags.SetSkipReferences(value); }
245 
246   void SetNonCacheable(bool value) { m_flags.SetNonCacheable(value); }
247 
248   uint32_t GetOptions() { return m_flags.GetValue(); }
249 
250   void SetOptions(uint32_t value) { m_flags.SetValue(value); }
251 
252   virtual bool IsScripted() = 0;
253 
254   virtual std::string GetDescription() = 0;
255 
256   virtual SyntheticChildrenFrontEnd::AutoPointer
257   GetFrontEnd(ValueObject &backend) = 0;
258 
259   typedef std::shared_ptr<SyntheticChildren> SharedPointer;
260 
261   uint32_t &GetRevision() { return m_my_revision; }
262 
263 protected:
264   uint32_t m_my_revision;
265   Flags m_flags;
266 
267 private:
268   DISALLOW_COPY_AND_ASSIGN(SyntheticChildren);
269 };
270 
271 class TypeFilterImpl : public SyntheticChildren {
272   std::vector<std::string> m_expression_paths;
273 
274 public:
275   TypeFilterImpl(const SyntheticChildren::Flags &flags)
276       : SyntheticChildren(flags), m_expression_paths() {}
277 
278   TypeFilterImpl(const SyntheticChildren::Flags &flags,
279                  const std::initializer_list<const char *> items)
280       : SyntheticChildren(flags), m_expression_paths() {
281     for (auto path : items)
282       AddExpressionPath(path);
283   }
284 
285   void AddExpressionPath(const char *path) {
286     AddExpressionPath(std::string(path));
287   }
288 
289   void Clear() { m_expression_paths.clear(); }
290 
291   size_t GetCount() const { return m_expression_paths.size(); }
292 
293   const char *GetExpressionPathAtIndex(size_t i) const {
294     return m_expression_paths[i].c_str();
295   }
296 
297   bool SetExpressionPathAtIndex(size_t i, const char *path) {
298     return SetExpressionPathAtIndex(i, std::string(path));
299   }
300 
301   void AddExpressionPath(const std::string &path);
302 
303   bool SetExpressionPathAtIndex(size_t i, const std::string &path);
304 
305   bool IsScripted() override { return false; }
306 
307   std::string GetDescription() override;
308 
309   class FrontEnd : public SyntheticChildrenFrontEnd {
310   public:
311     FrontEnd(TypeFilterImpl *flt, ValueObject &backend)
312         : SyntheticChildrenFrontEnd(backend), filter(flt) {}
313 
314     ~FrontEnd() override = default;
315 
316     size_t CalculateNumChildren() override { return filter->GetCount(); }
317 
318     lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
319       if (idx >= filter->GetCount())
320         return lldb::ValueObjectSP();
321       return m_backend.GetSyntheticExpressionPathChild(
322           filter->GetExpressionPathAtIndex(idx), true);
323     }
324 
325     bool Update() override { return false; }
326 
327     bool MightHaveChildren() override { return filter->GetCount() > 0; }
328 
329     size_t GetIndexOfChildWithName(ConstString name) override;
330 
331     typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
332 
333   private:
334     TypeFilterImpl *filter;
335 
336     DISALLOW_COPY_AND_ASSIGN(FrontEnd);
337   };
338 
339   SyntheticChildrenFrontEnd::AutoPointer
340   GetFrontEnd(ValueObject &backend) override {
341     return SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(this, backend));
342   }
343 
344   typedef std::shared_ptr<TypeFilterImpl> SharedPointer;
345 
346 private:
347   DISALLOW_COPY_AND_ASSIGN(TypeFilterImpl);
348 };
349 
350 class CXXSyntheticChildren : public SyntheticChildren {
351 public:
352   typedef std::function<SyntheticChildrenFrontEnd *(CXXSyntheticChildren *,
353                                                     lldb::ValueObjectSP)>
354       CreateFrontEndCallback;
355   CXXSyntheticChildren(const SyntheticChildren::Flags &flags,
356                        const char *description, CreateFrontEndCallback callback)
357       : SyntheticChildren(flags), m_create_callback(callback),
358         m_description(description ? description : "") {}
359 
360   bool IsScripted() override { return false; }
361 
362   std::string GetDescription() override;
363 
364   SyntheticChildrenFrontEnd::AutoPointer
365   GetFrontEnd(ValueObject &backend) override {
366     return SyntheticChildrenFrontEnd::AutoPointer(
367         m_create_callback(this, backend.GetSP()));
368   }
369 
370 protected:
371   CreateFrontEndCallback m_create_callback;
372   std::string m_description;
373 
374 private:
375   DISALLOW_COPY_AND_ASSIGN(CXXSyntheticChildren);
376 };
377 
378 class ScriptedSyntheticChildren : public SyntheticChildren {
379   std::string m_python_class;
380   std::string m_python_code;
381 
382 public:
383   ScriptedSyntheticChildren(const SyntheticChildren::Flags &flags,
384                             const char *pclass, const char *pcode = nullptr)
385       : SyntheticChildren(flags), m_python_class(), m_python_code() {
386     if (pclass)
387       m_python_class = pclass;
388     if (pcode)
389       m_python_code = pcode;
390   }
391 
392   const char *GetPythonClassName() { return m_python_class.c_str(); }
393 
394   const char *GetPythonCode() { return m_python_code.c_str(); }
395 
396   void SetPythonClassName(const char *fname) {
397     m_python_class.assign(fname);
398     m_python_code.clear();
399   }
400 
401   void SetPythonCode(const char *script) { m_python_code.assign(script); }
402 
403   std::string GetDescription() override;
404 
405   bool IsScripted() override { return true; }
406 
407   class FrontEnd : public SyntheticChildrenFrontEnd {
408   public:
409     FrontEnd(std::string pclass, ValueObject &backend);
410 
411     ~FrontEnd() override;
412 
413     bool IsValid();
414 
415     size_t CalculateNumChildren() override;
416 
417     size_t CalculateNumChildren(uint32_t max) override;
418 
419     lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
420 
421     bool Update() override;
422 
423     bool MightHaveChildren() override;
424 
425     size_t GetIndexOfChildWithName(ConstString name) override;
426 
427     lldb::ValueObjectSP GetSyntheticValue() override;
428 
429     ConstString GetSyntheticTypeName() override;
430 
431     typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
432 
433   private:
434     std::string m_python_class;
435     StructuredData::ObjectSP m_wrapper_sp;
436     ScriptInterpreter *m_interpreter;
437 
438     DISALLOW_COPY_AND_ASSIGN(FrontEnd);
439   };
440 
441   SyntheticChildrenFrontEnd::AutoPointer
442   GetFrontEnd(ValueObject &backend) override {
443     auto synth_ptr = SyntheticChildrenFrontEnd::AutoPointer(
444         new FrontEnd(m_python_class, backend));
445     if (synth_ptr && ((FrontEnd *)synth_ptr.get())->IsValid())
446       return synth_ptr;
447     return nullptr;
448   }
449 
450 private:
451   DISALLOW_COPY_AND_ASSIGN(ScriptedSyntheticChildren);
452 };
453 } // namespace lldb_private
454 
455 #endif // lldb_TypeSynthetic_h_
456