1 //===-- TypeSummary.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_TYPESUMMARY_H
10 #define LLDB_DATAFORMATTERS_TYPESUMMARY_H
11 
12 #include <cstdint>
13 
14 #include <functional>
15 #include <memory>
16 #include <string>
17 
18 #include "lldb/lldb-enumerations.h"
19 #include "lldb/lldb-public.h"
20 
21 #include "lldb/Core/FormatEntity.h"
22 #include "lldb/Utility/Status.h"
23 #include "lldb/Utility/StructuredData.h"
24 
25 namespace lldb_private {
26 class TypeSummaryOptions {
27 public:
28   TypeSummaryOptions();
29 
30   ~TypeSummaryOptions() = default;
31 
32   lldb::LanguageType GetLanguage() const;
33 
34   lldb::TypeSummaryCapping GetCapping() const;
35 
36   TypeSummaryOptions &SetLanguage(lldb::LanguageType);
37 
38   TypeSummaryOptions &SetCapping(lldb::TypeSummaryCapping);
39 
40 private:
41   lldb::LanguageType m_lang = lldb::eLanguageTypeUnknown;
42   lldb::TypeSummaryCapping m_capping = lldb::eTypeSummaryCapped;
43 };
44 
45 class TypeSummaryImpl {
46 public:
47   enum class Kind { eSummaryString, eScript, eCallback, eInternal };
48 
49   virtual ~TypeSummaryImpl() = default;
50 
51   Kind GetKind() const { return m_kind; }
52 
53   class Flags {
54   public:
55     Flags() = default;
56 
57     Flags(const Flags &other) : m_flags(other.m_flags) {}
58 
59     Flags(uint32_t value) : m_flags(value) {}
60 
61     Flags &operator=(const Flags &rhs) {
62       if (&rhs != this)
63         m_flags = rhs.m_flags;
64 
65       return *this;
66     }
67 
68     Flags &operator=(const uint32_t &rhs) {
69       m_flags = rhs;
70       return *this;
71     }
72 
73     Flags &Clear() {
74       m_flags = 0;
75       return *this;
76     }
77 
78     bool GetCascades() const {
79       return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade;
80     }
81 
82     Flags &SetCascades(bool value = true) {
83       if (value)
84         m_flags |= lldb::eTypeOptionCascade;
85       else
86         m_flags &= ~lldb::eTypeOptionCascade;
87       return *this;
88     }
89 
90     bool GetSkipPointers() const {
91       return (m_flags & lldb::eTypeOptionSkipPointers) ==
92              lldb::eTypeOptionSkipPointers;
93     }
94 
95     Flags &SetSkipPointers(bool value = true) {
96       if (value)
97         m_flags |= lldb::eTypeOptionSkipPointers;
98       else
99         m_flags &= ~lldb::eTypeOptionSkipPointers;
100       return *this;
101     }
102 
103     bool GetSkipReferences() const {
104       return (m_flags & lldb::eTypeOptionSkipReferences) ==
105              lldb::eTypeOptionSkipReferences;
106     }
107 
108     Flags &SetSkipReferences(bool value = true) {
109       if (value)
110         m_flags |= lldb::eTypeOptionSkipReferences;
111       else
112         m_flags &= ~lldb::eTypeOptionSkipReferences;
113       return *this;
114     }
115 
116     bool GetDontShowChildren() const {
117       return (m_flags & lldb::eTypeOptionHideChildren) ==
118              lldb::eTypeOptionHideChildren;
119     }
120 
121     Flags &SetDontShowChildren(bool value = true) {
122       if (value)
123         m_flags |= lldb::eTypeOptionHideChildren;
124       else
125         m_flags &= ~lldb::eTypeOptionHideChildren;
126       return *this;
127     }
128 
129     bool GetHideEmptyAggregates() const {
130       return (m_flags & lldb::eTypeOptionHideEmptyAggregates) ==
131              lldb::eTypeOptionHideEmptyAggregates;
132     }
133 
134     Flags &SetHideEmptyAggregates(bool value = true) {
135       if (value)
136         m_flags |= lldb::eTypeOptionHideEmptyAggregates;
137       else
138         m_flags &= ~lldb::eTypeOptionHideEmptyAggregates;
139       return *this;
140     }
141 
142     bool GetDontShowValue() const {
143       return (m_flags & lldb::eTypeOptionHideValue) ==
144              lldb::eTypeOptionHideValue;
145     }
146 
147     Flags &SetDontShowValue(bool value = true) {
148       if (value)
149         m_flags |= lldb::eTypeOptionHideValue;
150       else
151         m_flags &= ~lldb::eTypeOptionHideValue;
152       return *this;
153     }
154 
155     bool GetShowMembersOneLiner() const {
156       return (m_flags & lldb::eTypeOptionShowOneLiner) ==
157              lldb::eTypeOptionShowOneLiner;
158     }
159 
160     Flags &SetShowMembersOneLiner(bool value = true) {
161       if (value)
162         m_flags |= lldb::eTypeOptionShowOneLiner;
163       else
164         m_flags &= ~lldb::eTypeOptionShowOneLiner;
165       return *this;
166     }
167 
168     bool GetHideItemNames() const {
169       return (m_flags & lldb::eTypeOptionHideNames) ==
170              lldb::eTypeOptionHideNames;
171     }
172 
173     Flags &SetHideItemNames(bool value = true) {
174       if (value)
175         m_flags |= lldb::eTypeOptionHideNames;
176       else
177         m_flags &= ~lldb::eTypeOptionHideNames;
178       return *this;
179     }
180 
181     bool GetNonCacheable() const {
182       return (m_flags & lldb::eTypeOptionNonCacheable) ==
183              lldb::eTypeOptionNonCacheable;
184     }
185 
186     Flags &SetNonCacheable(bool value = true) {
187       if (value)
188         m_flags |= lldb::eTypeOptionNonCacheable;
189       else
190         m_flags &= ~lldb::eTypeOptionNonCacheable;
191       return *this;
192     }
193 
194     uint32_t GetValue() { return m_flags; }
195 
196     void SetValue(uint32_t value) { m_flags = value; }
197 
198   private:
199     uint32_t m_flags = lldb::eTypeOptionCascade;
200   };
201 
202   bool Cascades() const { return m_flags.GetCascades(); }
203 
204   bool SkipsPointers() const { return m_flags.GetSkipPointers(); }
205 
206   bool SkipsReferences() const { return m_flags.GetSkipReferences(); }
207 
208   bool NonCacheable() const { return m_flags.GetNonCacheable(); }
209 
210   virtual bool DoesPrintChildren(ValueObject *valobj) const {
211     return !m_flags.GetDontShowChildren();
212   }
213 
214   virtual bool DoesPrintEmptyAggregates() const {
215     return !m_flags.GetHideEmptyAggregates();
216   }
217 
218   virtual bool DoesPrintValue(ValueObject *valobj) const {
219     return !m_flags.GetDontShowValue();
220   }
221 
222   bool IsOneLiner() const { return m_flags.GetShowMembersOneLiner(); }
223 
224   virtual bool HideNames(ValueObject *valobj) const {
225     return m_flags.GetHideItemNames();
226   }
227 
228   void SetCascades(bool value) { m_flags.SetCascades(value); }
229 
230   void SetSkipsPointers(bool value) { m_flags.SetSkipPointers(value); }
231 
232   void SetSkipsReferences(bool value) { m_flags.SetSkipReferences(value); }
233 
234   virtual void SetDoesPrintChildren(bool value) {
235     m_flags.SetDontShowChildren(!value);
236   }
237 
238   virtual void SetDoesPrintValue(bool value) {
239     m_flags.SetDontShowValue(!value);
240   }
241 
242   void SetIsOneLiner(bool value) { m_flags.SetShowMembersOneLiner(value); }
243 
244   virtual void SetHideNames(bool value) { m_flags.SetHideItemNames(value); }
245 
246   virtual 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   // we are using a ValueObject* instead of a ValueObjectSP because we do not
253   // need to hold on to this for extended periods of time and we trust the
254   // ValueObject to stay around for as long as it is required for us to
255   // generate its summary
256   virtual bool FormatObject(ValueObject *valobj, std::string &dest,
257                             const TypeSummaryOptions &options) = 0;
258 
259   virtual std::string GetDescription() = 0;
260 
261   uint32_t &GetRevision() { return m_my_revision; }
262 
263   typedef std::shared_ptr<TypeSummaryImpl> SharedPointer;
264 
265 protected:
266   uint32_t m_my_revision = 0;
267   Flags m_flags;
268 
269   TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags);
270 
271 private:
272   Kind m_kind;
273   TypeSummaryImpl(const TypeSummaryImpl &) = delete;
274   const TypeSummaryImpl &operator=(const TypeSummaryImpl &) = delete;
275 };
276 
277 // simple string-based summaries, using ${var to show data
278 struct StringSummaryFormat : public TypeSummaryImpl {
279   std::string m_format_str;
280   FormatEntity::Entry m_format;
281   Status m_error;
282 
283   StringSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *f);
284 
285   ~StringSummaryFormat() override = default;
286 
287   const char *GetSummaryString() const { return m_format_str.c_str(); }
288 
289   void SetSummaryString(const char *f);
290 
291   bool FormatObject(ValueObject *valobj, std::string &dest,
292                     const TypeSummaryOptions &options) override;
293 
294   std::string GetDescription() override;
295 
296   static bool classof(const TypeSummaryImpl *S) {
297     return S->GetKind() == Kind::eSummaryString;
298   }
299 
300 private:
301   StringSummaryFormat(const StringSummaryFormat &) = delete;
302   const StringSummaryFormat &operator=(const StringSummaryFormat &) = delete;
303 };
304 
305 // summaries implemented via a C++ function
306 struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
307   // we should convert these to SBValue and SBStream if we ever cross the
308   // boundary towards the external world
309   typedef std::function<bool(ValueObject &, Stream &,
310                              const TypeSummaryOptions &)>
311       Callback;
312 
313   Callback m_impl;
314   std::string m_description;
315 
316   CXXFunctionSummaryFormat(const TypeSummaryImpl::Flags &flags, Callback impl,
317                            const char *description);
318 
319   ~CXXFunctionSummaryFormat() override = default;
320 
321   Callback GetBackendFunction() const { return m_impl; }
322 
323   const char *GetTextualInfo() const { return m_description.c_str(); }
324 
325   void SetBackendFunction(Callback cb_func) { m_impl = std::move(cb_func); }
326 
327   void SetTextualInfo(const char *descr) {
328     if (descr)
329       m_description.assign(descr);
330     else
331       m_description.clear();
332   }
333 
334   bool FormatObject(ValueObject *valobj, std::string &dest,
335                     const TypeSummaryOptions &options) override;
336 
337   std::string GetDescription() override;
338 
339   static bool classof(const TypeSummaryImpl *S) {
340     return S->GetKind() == Kind::eCallback;
341   }
342 
343   typedef std::shared_ptr<CXXFunctionSummaryFormat> SharedPointer;
344 
345 private:
346   CXXFunctionSummaryFormat(const CXXFunctionSummaryFormat &) = delete;
347   const CXXFunctionSummaryFormat &
348   operator=(const CXXFunctionSummaryFormat &) = delete;
349 };
350 
351 // Python-based summaries, running script code to show data
352 struct ScriptSummaryFormat : public TypeSummaryImpl {
353   std::string m_function_name;
354   std::string m_python_script;
355   StructuredData::ObjectSP m_script_function_sp;
356 
357   ScriptSummaryFormat(const TypeSummaryImpl::Flags &flags,
358                       const char *function_name,
359                       const char *python_script = nullptr);
360 
361   ~ScriptSummaryFormat() override = default;
362 
363   const char *GetFunctionName() const { return m_function_name.c_str(); }
364 
365   const char *GetPythonScript() const { return m_python_script.c_str(); }
366 
367   void SetFunctionName(const char *function_name) {
368     if (function_name)
369       m_function_name.assign(function_name);
370     else
371       m_function_name.clear();
372     m_python_script.clear();
373   }
374 
375   void SetPythonScript(const char *script) {
376     if (script)
377       m_python_script.assign(script);
378     else
379       m_python_script.clear();
380   }
381 
382   bool FormatObject(ValueObject *valobj, std::string &dest,
383                     const TypeSummaryOptions &options) override;
384 
385   std::string GetDescription() override;
386 
387   static bool classof(const TypeSummaryImpl *S) {
388     return S->GetKind() == Kind::eScript;
389   }
390 
391   typedef std::shared_ptr<ScriptSummaryFormat> SharedPointer;
392 
393 private:
394   ScriptSummaryFormat(const ScriptSummaryFormat &) = delete;
395   const ScriptSummaryFormat &operator=(const ScriptSummaryFormat &) = delete;
396 };
397 } // namespace lldb_private
398 
399 #endif // LLDB_DATAFORMATTERS_TYPESUMMARY_H
400