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 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 | |
82 | protected: |
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 (llvm::StringRef name, |
94 | const DataExtractor &data, |
95 | const ExecutionContext &exe_ctx, |
96 | CompilerType type); |
97 | |
98 | private: |
99 | bool m_valid; |
100 | SyntheticChildrenFrontEnd(const SyntheticChildrenFrontEnd &) = delete; |
101 | const SyntheticChildrenFrontEnd & |
102 | operator=(const SyntheticChildrenFrontEnd &) = delete; |
103 | }; |
104 | |
105 | class SyntheticValueProviderFrontEnd : public SyntheticChildrenFrontEnd { |
106 | public: |
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 | |
128 | private: |
129 | SyntheticValueProviderFrontEnd(const SyntheticValueProviderFrontEnd &) = |
130 | delete; |
131 | const SyntheticValueProviderFrontEnd & |
132 | operator=(const SyntheticValueProviderFrontEnd &) = delete; |
133 | }; |
134 | |
135 | class SyntheticChildren { |
136 | public: |
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 | |
271 | protected: |
272 | uint32_t m_my_revision = 0; |
273 | Flags m_flags; |
274 | |
275 | private: |
276 | SyntheticChildren(const SyntheticChildren &) = delete; |
277 | const SyntheticChildren &operator=(const SyntheticChildren &) = delete; |
278 | }; |
279 | |
280 | class TypeFilterImpl : public SyntheticChildren { |
281 | std::vector<std::string> m_expression_paths; |
282 | |
283 | public: |
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 | |
358 | private: |
359 | TypeFilterImpl(const TypeFilterImpl &) = delete; |
360 | const TypeFilterImpl &operator=(const TypeFilterImpl &) = delete; |
361 | }; |
362 | |
363 | class CXXSyntheticChildren : public SyntheticChildren { |
364 | public: |
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 | |
383 | protected: |
384 | CreateFrontEndCallback m_create_callback; |
385 | std::string m_description; |
386 | |
387 | private: |
388 | CXXSyntheticChildren(const CXXSyntheticChildren &) = delete; |
389 | const CXXSyntheticChildren &operator=(const CXXSyntheticChildren &) = delete; |
390 | }; |
391 | |
392 | class ScriptedSyntheticChildren : public SyntheticChildren { |
393 | std::string m_python_class; |
394 | std::string m_python_code; |
395 | |
396 | public: |
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 | |
465 | private: |
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 | |