/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/DataFormatters/TypeSynthetic.h
Line | Count | Source (jump to first uncovered line) |
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 | 0 | void SetValid(bool valid) { m_valid = valid; } |
32 | | |
33 | 0 | bool IsValid() { return m_valid; } |
34 | | |
35 | | public: |
36 | | SyntheticChildrenFrontEnd(ValueObject &backend) |
37 | 1.86k | : m_backend(backend), m_valid(true) {} |
38 | | |
39 | 1.55k | virtual ~SyntheticChildrenFrontEnd() = default; |
40 | | |
41 | | virtual size_t CalculateNumChildren() = 0; |
42 | | |
43 | 767 | virtual size_t CalculateNumChildren(uint32_t max) { |
44 | 767 | auto count = CalculateNumChildren(); |
45 | 767 | return count <= max ? count : max0 ; |
46 | 767 | } |
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 | 1.50k | 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 | 1.54k | 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 | 0 | : SyntheticChildrenFrontEnd(backend) {} |
108 | | |
109 | | ~SyntheticValueProviderFrontEnd() override = default; |
110 | | |
111 | 0 | size_t CalculateNumChildren() override { return 0; } |
112 | | |
113 | 0 | lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { return nullptr; } |
114 | | |
115 | 0 | size_t GetIndexOfChildWithName(ConstString name) override { |
116 | 0 | return UINT32_MAX; |
117 | 0 | } |
118 | | |
119 | 0 | bool Update() override { return false; } |
120 | | |
121 | 0 | 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 | 27.3k | Flags() = default; |
137 | | |
138 | 79.9k | Flags(const Flags &other) : m_flags(other.m_flags) {} |
139 | | |
140 | 11 | Flags(uint32_t value) : m_flags(value) {} |
141 | | |
142 | 0 | Flags &operator=(const Flags &rhs) { |
143 | 0 | if (&rhs != this) |
144 | 0 | m_flags = rhs.m_flags; |
145 | 0 |
|
146 | 0 | return *this; |
147 | 0 | } |
148 | | |
149 | 0 | Flags &operator=(const uint32_t &rhs) { |
150 | 0 | m_flags = rhs; |
151 | 0 | return *this; |
152 | 0 | } |
153 | | |
154 | 0 | Flags &Clear() { |
155 | 0 | m_flags = 0; |
156 | 0 | return *this; |
157 | 0 | } |
158 | | |
159 | 864 | bool GetCascades() const { |
160 | 864 | return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade; |
161 | 864 | } |
162 | | |
163 | 3.49k | Flags &SetCascades(bool value = true) { |
164 | 3.49k | if (value) |
165 | 3.49k | m_flags |= lldb::eTypeOptionCascade; |
166 | 0 | else |
167 | 0 | m_flags &= ~lldb::eTypeOptionCascade; |
168 | 3.49k | return *this; |
169 | 3.49k | } |
170 | | |
171 | 864 | bool GetSkipPointers() const { |
172 | 864 | return (m_flags & lldb::eTypeOptionSkipPointers) == |
173 | 864 | lldb::eTypeOptionSkipPointers; |
174 | 864 | } |
175 | | |
176 | 3.49k | Flags &SetSkipPointers(bool value = true) { |
177 | 3.49k | if (value) |
178 | 1.36k | m_flags |= lldb::eTypeOptionSkipPointers; |
179 | 2.13k | else |
180 | 2.13k | m_flags &= ~lldb::eTypeOptionSkipPointers; |
181 | 3.49k | return *this; |
182 | 3.49k | } |
183 | | |
184 | 862 | bool GetSkipReferences() const { |
185 | 862 | return (m_flags & lldb::eTypeOptionSkipReferences) == |
186 | 862 | lldb::eTypeOptionSkipReferences; |
187 | 862 | } |
188 | | |
189 | 3.49k | Flags &SetSkipReferences(bool value = true) { |
190 | 3.49k | if (value) |
191 | 1.36k | m_flags |= lldb::eTypeOptionSkipReferences; |
192 | 2.13k | else |
193 | 2.13k | m_flags &= ~lldb::eTypeOptionSkipReferences; |
194 | 3.49k | return *this; |
195 | 3.49k | } |
196 | | |
197 | 538 | bool GetNonCacheable() const { |
198 | 538 | return (m_flags & lldb::eTypeOptionNonCacheable) == |
199 | 538 | lldb::eTypeOptionNonCacheable; |
200 | 538 | } |
201 | | |
202 | 1.36k | Flags &SetNonCacheable(bool value = true) { |
203 | 1.36k | if (value) |
204 | 1.36k | m_flags |= lldb::eTypeOptionNonCacheable; |
205 | 0 | else |
206 | 0 | m_flags &= ~lldb::eTypeOptionNonCacheable; |
207 | 1.36k | return *this; |
208 | 1.36k | } |
209 | | |
210 | 1.84k | bool GetFrontEndWantsDereference() const { |
211 | 1.84k | return (m_flags & lldb::eTypeOptionFrontEndWantsDereference) == |
212 | 1.84k | lldb::eTypeOptionFrontEndWantsDereference; |
213 | 1.84k | } |
214 | | |
215 | 1.36k | Flags &SetFrontEndWantsDereference(bool value = true) { |
216 | 1.36k | if (value) |
217 | 1.36k | m_flags |= lldb::eTypeOptionFrontEndWantsDereference; |
218 | 0 | else |
219 | 0 | m_flags &= ~lldb::eTypeOptionFrontEndWantsDereference; |
220 | 1.36k | return *this; |
221 | 1.36k | } |
222 | | |
223 | 2 | uint32_t GetValue() { return m_flags; } |
224 | | |
225 | 0 | 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); |
232 | | |
233 | | virtual ~SyntheticChildren(); |
234 | | |
235 | 864 | bool Cascades() const { return m_flags.GetCascades(); } |
236 | | |
237 | 864 | bool SkipsPointers() const { return m_flags.GetSkipPointers(); } |
238 | | |
239 | 862 | bool SkipsReferences() const { return m_flags.GetSkipReferences(); } |
240 | | |
241 | 538 | bool NonCacheable() const { return m_flags.GetNonCacheable(); } |
242 | | |
243 | 1.84k | bool WantsDereference() const { return m_flags.GetFrontEndWantsDereference();} |
244 | | |
245 | 0 | void SetCascades(bool value) { m_flags.SetCascades(value); } |
246 | | |
247 | 0 | void SetSkipsPointers(bool value) { m_flags.SetSkipPointers(value); } |
248 | | |
249 | 0 | void SetSkipsReferences(bool value) { m_flags.SetSkipReferences(value); } |
250 | | |
251 | 0 | void SetNonCacheable(bool value) { m_flags.SetNonCacheable(value); } |
252 | | |
253 | 2 | uint32_t GetOptions() { return m_flags.GetValue(); } |
254 | | |
255 | 0 | 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 | 54.0k | uint32_t &GetRevision() { return m_my_revision; } |
267 | | |
268 | | protected: |
269 | | uint32_t m_my_revision = 0; |
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 | 35 | : SyntheticChildren(flags) {} |
283 | | |
284 | | TypeFilterImpl(const SyntheticChildren::Flags &flags, |
285 | | const std::initializer_list<const char *> items) |
286 | 0 | : SyntheticChildren(flags) { |
287 | 0 | for (auto path : items) |
288 | 0 | AddExpressionPath(path); |
289 | 0 | } |
290 | | |
291 | 8 | void AddExpressionPath(const char *path) { |
292 | 8 | AddExpressionPath(std::string(path)); |
293 | 8 | } |
294 | | |
295 | 0 | void Clear() { m_expression_paths.clear(); } |
296 | | |
297 | 159 | size_t GetCount() const { return m_expression_paths.size(); } |
298 | | |
299 | 104 | const char *GetExpressionPathAtIndex(size_t i) const { |
300 | 104 | return m_expression_paths[i].c_str(); |
301 | 104 | } |
302 | | |
303 | 2 | bool SetExpressionPathAtIndex(size_t i, const char *path) { |
304 | 2 | return SetExpressionPathAtIndex(i, std::string(path)); |
305 | 2 | } |
306 | | |
307 | | void AddExpressionPath(const std::string &path); |
308 | | |
309 | | bool SetExpressionPathAtIndex(size_t i, const std::string &path); |
310 | | |
311 | 0 | 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 | 38 | : SyntheticChildrenFrontEnd(backend), filter(flt) {} |
319 | | |
320 | 28 | ~FrontEnd() override = default; |
321 | | |
322 | 38 | size_t CalculateNumChildren() override { return filter->GetCount(); } |
323 | | |
324 | 74 | lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { |
325 | 74 | if (idx >= filter->GetCount()) |
326 | 0 | return lldb::ValueObjectSP(); |
327 | 74 | return m_backend.GetSyntheticExpressionPathChild( |
328 | 74 | filter->GetExpressionPathAtIndex(idx), true); |
329 | 74 | } |
330 | | |
331 | 38 | bool Update() override { return false; } |
332 | | |
333 | 6 | 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 | 38 | GetFrontEnd(ValueObject &backend) override { |
348 | 38 | return SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(this, backend)); |
349 | 38 | } |
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 | | |
366 | | virtual ~CXXSyntheticChildren(); |
367 | | |
368 | 0 | bool IsScripted() override { return false; } |
369 | | |
370 | | std::string GetDescription() override; |
371 | | |
372 | | SyntheticChildrenFrontEnd::AutoPointer |
373 | 1.70k | GetFrontEnd(ValueObject &backend) override { |
374 | 1.70k | return SyntheticChildrenFrontEnd::AutoPointer( |
375 | 1.70k | m_create_callback(this, backend.GetSP())); |
376 | 1.70k | } |
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 | 6.87k | : SyntheticChildren(flags) { |
395 | 6.87k | if (pclass) |
396 | 6.87k | m_python_class = pclass; |
397 | 6.87k | if (pcode) |
398 | 6 | m_python_code = pcode; |
399 | 6.87k | } |
400 | | |
401 | 35 | const char *GetPythonClassName() { return m_python_class.c_str(); } |
402 | | |
403 | 6 | const char *GetPythonCode() { return m_python_code.c_str(); } |
404 | | |
405 | 0 | void SetPythonClassName(const char *fname) { |
406 | 0 | m_python_class.assign(fname); |
407 | 0 | m_python_code.clear(); |
408 | 0 | } |
409 | | |
410 | 0 | void SetPythonCode(const char *script) { m_python_code.assign(script); } |
411 | | |
412 | | std::string GetDescription() override; |
413 | | |
414 | 0 | 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 | 105 | GetFrontEnd(ValueObject &backend) override { |
453 | 105 | auto synth_ptr = SyntheticChildrenFrontEnd::AutoPointer( |
454 | 105 | new FrontEnd(m_python_class, backend)); |
455 | 105 | if (synth_ptr && ((FrontEnd *)synth_ptr.get())->IsValid()) |
456 | 102 | return synth_ptr; |
457 | 3 | return nullptr; |
458 | 105 | } |
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 |