1 //===-- SBTypeSummary.cpp -----------------------------------------*- C++
2 //-*-===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/API/SBTypeSummary.h"
11 #include "SBReproducerPrivate.h"
12 #include "Utils.h"
13 #include "lldb/API/SBStream.h"
14 #include "lldb/API/SBValue.h"
15 #include "lldb/DataFormatters/DataVisualization.h"
16 
17 #include "llvm/Support/Casting.h"
18 
19 using namespace lldb;
20 using namespace lldb_private;
21 
22 SBTypeSummaryOptions::SBTypeSummaryOptions() {
23   LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBTypeSummaryOptions);
24 
25   m_opaque_up.reset(new TypeSummaryOptions());
26 }
27 
28 SBTypeSummaryOptions::SBTypeSummaryOptions(
29     const lldb::SBTypeSummaryOptions &rhs) {
30   LLDB_RECORD_CONSTRUCTOR(SBTypeSummaryOptions,
31                           (const lldb::SBTypeSummaryOptions &), rhs);
32 
33   m_opaque_up = clone(rhs.m_opaque_up);
34 }
35 
36 SBTypeSummaryOptions::~SBTypeSummaryOptions() {}
37 
38 bool SBTypeSummaryOptions::IsValid() {
39   LLDB_RECORD_METHOD_NO_ARGS(bool, SBTypeSummaryOptions, IsValid);
40 
41   return m_opaque_up.get();
42 }
43 
44 lldb::LanguageType SBTypeSummaryOptions::GetLanguage() {
45   LLDB_RECORD_METHOD_NO_ARGS(lldb::LanguageType, SBTypeSummaryOptions,
46                              GetLanguage);
47 
48   if (IsValid())
49     return m_opaque_up->GetLanguage();
50   return lldb::eLanguageTypeUnknown;
51 }
52 
53 lldb::TypeSummaryCapping SBTypeSummaryOptions::GetCapping() {
54   LLDB_RECORD_METHOD_NO_ARGS(lldb::TypeSummaryCapping, SBTypeSummaryOptions,
55                              GetCapping);
56 
57   if (IsValid())
58     return m_opaque_up->GetCapping();
59   return eTypeSummaryCapped;
60 }
61 
62 void SBTypeSummaryOptions::SetLanguage(lldb::LanguageType l) {
63   LLDB_RECORD_METHOD(void, SBTypeSummaryOptions, SetLanguage,
64                      (lldb::LanguageType), l);
65 
66   if (IsValid())
67     m_opaque_up->SetLanguage(l);
68 }
69 
70 void SBTypeSummaryOptions::SetCapping(lldb::TypeSummaryCapping c) {
71   LLDB_RECORD_METHOD(void, SBTypeSummaryOptions, SetCapping,
72                      (lldb::TypeSummaryCapping), c);
73 
74   if (IsValid())
75     m_opaque_up->SetCapping(c);
76 }
77 
78 lldb_private::TypeSummaryOptions *SBTypeSummaryOptions::operator->() {
79   return m_opaque_up.get();
80 }
81 
82 const lldb_private::TypeSummaryOptions *SBTypeSummaryOptions::
83 operator->() const {
84   return m_opaque_up.get();
85 }
86 
87 lldb_private::TypeSummaryOptions *SBTypeSummaryOptions::get() {
88   return m_opaque_up.get();
89 }
90 
91 lldb_private::TypeSummaryOptions &SBTypeSummaryOptions::ref() {
92   return *m_opaque_up;
93 }
94 
95 const lldb_private::TypeSummaryOptions &SBTypeSummaryOptions::ref() const {
96   return *m_opaque_up;
97 }
98 
99 SBTypeSummaryOptions::SBTypeSummaryOptions(
100     const lldb_private::TypeSummaryOptions *lldb_object_ptr) {
101   LLDB_RECORD_CONSTRUCTOR(SBTypeSummaryOptions,
102                           (const lldb_private::TypeSummaryOptions *),
103                           lldb_object_ptr);
104 
105   SetOptions(lldb_object_ptr);
106 }
107 
108 void SBTypeSummaryOptions::SetOptions(
109     const lldb_private::TypeSummaryOptions *lldb_object_ptr) {
110   if (lldb_object_ptr)
111     m_opaque_up.reset(new TypeSummaryOptions(*lldb_object_ptr));
112   else
113     m_opaque_up.reset(new TypeSummaryOptions());
114 }
115 
116 SBTypeSummary::SBTypeSummary() : m_opaque_sp() {
117   LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBTypeSummary);
118 }
119 
120 SBTypeSummary SBTypeSummary::CreateWithSummaryString(const char *data,
121                                                      uint32_t options) {
122   LLDB_RECORD_STATIC_METHOD(lldb::SBTypeSummary, SBTypeSummary,
123                             CreateWithSummaryString, (const char *, uint32_t),
124                             data, options);
125 
126   if (!data || data[0] == 0)
127     return LLDB_RECORD_RESULT(SBTypeSummary());
128 
129   return LLDB_RECORD_RESULT(
130       SBTypeSummary(TypeSummaryImplSP(new StringSummaryFormat(options, data))));
131 }
132 
133 SBTypeSummary SBTypeSummary::CreateWithFunctionName(const char *data,
134                                                     uint32_t options) {
135   LLDB_RECORD_STATIC_METHOD(lldb::SBTypeSummary, SBTypeSummary,
136                             CreateWithFunctionName, (const char *, uint32_t),
137                             data, options);
138 
139   if (!data || data[0] == 0)
140     return LLDB_RECORD_RESULT(SBTypeSummary());
141 
142   return LLDB_RECORD_RESULT(
143       SBTypeSummary(TypeSummaryImplSP(new ScriptSummaryFormat(options, data))));
144 }
145 
146 SBTypeSummary SBTypeSummary::CreateWithScriptCode(const char *data,
147                                                   uint32_t options) {
148   LLDB_RECORD_STATIC_METHOD(lldb::SBTypeSummary, SBTypeSummary,
149                             CreateWithScriptCode, (const char *, uint32_t),
150                             data, options);
151 
152   if (!data || data[0] == 0)
153     return LLDB_RECORD_RESULT(SBTypeSummary());
154 
155   return LLDB_RECORD_RESULT(SBTypeSummary(
156       TypeSummaryImplSP(new ScriptSummaryFormat(options, "", data))));
157 }
158 
159 SBTypeSummary SBTypeSummary::CreateWithCallback(FormatCallback cb,
160                                                 uint32_t options,
161                                                 const char *description) {
162   SBTypeSummary retval;
163   if (cb) {
164     retval.SetSP(TypeSummaryImplSP(new CXXFunctionSummaryFormat(
165         options,
166         [cb](ValueObject &valobj, Stream &stm,
167              const TypeSummaryOptions &opt) -> bool {
168           SBStream stream;
169           SBValue sb_value(valobj.GetSP());
170           SBTypeSummaryOptions options(&opt);
171           if (!cb(sb_value, options, stream))
172             return false;
173           stm.Write(stream.GetData(), stream.GetSize());
174           return true;
175         },
176         description ? description : "callback summary formatter")));
177   }
178 
179   return retval;
180 }
181 
182 SBTypeSummary::SBTypeSummary(const lldb::SBTypeSummary &rhs)
183     : m_opaque_sp(rhs.m_opaque_sp) {
184   LLDB_RECORD_CONSTRUCTOR(SBTypeSummary, (const lldb::SBTypeSummary &), rhs);
185 }
186 
187 SBTypeSummary::~SBTypeSummary() {}
188 
189 bool SBTypeSummary::IsValid() const {
190   LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBTypeSummary, IsValid);
191 
192   return m_opaque_sp.get() != NULL;
193 }
194 
195 bool SBTypeSummary::IsFunctionCode() {
196   LLDB_RECORD_METHOD_NO_ARGS(bool, SBTypeSummary, IsFunctionCode);
197 
198   if (!IsValid())
199     return false;
200   if (ScriptSummaryFormat *script_summary_ptr =
201           llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get())) {
202     const char *ftext = script_summary_ptr->GetPythonScript();
203     return (ftext && *ftext != 0);
204   }
205   return false;
206 }
207 
208 bool SBTypeSummary::IsFunctionName() {
209   LLDB_RECORD_METHOD_NO_ARGS(bool, SBTypeSummary, IsFunctionName);
210 
211   if (!IsValid())
212     return false;
213   if (ScriptSummaryFormat *script_summary_ptr =
214           llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get())) {
215     const char *ftext = script_summary_ptr->GetPythonScript();
216     return (!ftext || *ftext == 0);
217   }
218   return false;
219 }
220 
221 bool SBTypeSummary::IsSummaryString() {
222   LLDB_RECORD_METHOD_NO_ARGS(bool, SBTypeSummary, IsSummaryString);
223 
224   if (!IsValid())
225     return false;
226 
227   return m_opaque_sp->GetKind() == TypeSummaryImpl::Kind::eSummaryString;
228 }
229 
230 const char *SBTypeSummary::GetData() {
231   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBTypeSummary, GetData);
232 
233   if (!IsValid())
234     return NULL;
235   if (ScriptSummaryFormat *script_summary_ptr =
236           llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get())) {
237     const char *fname = script_summary_ptr->GetFunctionName();
238     const char *ftext = script_summary_ptr->GetPythonScript();
239     if (ftext && *ftext)
240       return ftext;
241     return fname;
242   } else if (StringSummaryFormat *string_summary_ptr =
243                  llvm::dyn_cast<StringSummaryFormat>(m_opaque_sp.get()))
244     return string_summary_ptr->GetSummaryString();
245   return nullptr;
246 }
247 
248 uint32_t SBTypeSummary::GetOptions() {
249   LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBTypeSummary, GetOptions);
250 
251   if (!IsValid())
252     return lldb::eTypeOptionNone;
253   return m_opaque_sp->GetOptions();
254 }
255 
256 void SBTypeSummary::SetOptions(uint32_t value) {
257   LLDB_RECORD_METHOD(void, SBTypeSummary, SetOptions, (uint32_t), value);
258 
259   if (!CopyOnWrite_Impl())
260     return;
261   m_opaque_sp->SetOptions(value);
262 }
263 
264 void SBTypeSummary::SetSummaryString(const char *data) {
265   LLDB_RECORD_METHOD(void, SBTypeSummary, SetSummaryString, (const char *),
266                      data);
267 
268   if (!IsValid())
269     return;
270   if (!llvm::isa<StringSummaryFormat>(m_opaque_sp.get()))
271     ChangeSummaryType(false);
272   if (StringSummaryFormat *string_summary_ptr =
273           llvm::dyn_cast<StringSummaryFormat>(m_opaque_sp.get()))
274     string_summary_ptr->SetSummaryString(data);
275 }
276 
277 void SBTypeSummary::SetFunctionName(const char *data) {
278   LLDB_RECORD_METHOD(void, SBTypeSummary, SetFunctionName, (const char *),
279                      data);
280 
281   if (!IsValid())
282     return;
283   if (!llvm::isa<ScriptSummaryFormat>(m_opaque_sp.get()))
284     ChangeSummaryType(true);
285   if (ScriptSummaryFormat *script_summary_ptr =
286           llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get()))
287     script_summary_ptr->SetFunctionName(data);
288 }
289 
290 void SBTypeSummary::SetFunctionCode(const char *data) {
291   LLDB_RECORD_METHOD(void, SBTypeSummary, SetFunctionCode, (const char *),
292                      data);
293 
294   if (!IsValid())
295     return;
296   if (!llvm::isa<ScriptSummaryFormat>(m_opaque_sp.get()))
297     ChangeSummaryType(true);
298   if (ScriptSummaryFormat *script_summary_ptr =
299           llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get()))
300     script_summary_ptr->SetPythonScript(data);
301 }
302 
303 bool SBTypeSummary::GetDescription(lldb::SBStream &description,
304                                    lldb::DescriptionLevel description_level) {
305   LLDB_RECORD_METHOD(bool, SBTypeSummary, GetDescription,
306                      (lldb::SBStream &, lldb::DescriptionLevel), description,
307                      description_level);
308 
309   if (!CopyOnWrite_Impl())
310     return false;
311   else {
312     description.Printf("%s\n", m_opaque_sp->GetDescription().c_str());
313     return true;
314   }
315 }
316 
317 bool SBTypeSummary::DoesPrintValue(lldb::SBValue value) {
318   LLDB_RECORD_METHOD(bool, SBTypeSummary, DoesPrintValue, (lldb::SBValue),
319                      value);
320 
321   if (!IsValid())
322     return false;
323   lldb::ValueObjectSP value_sp = value.GetSP();
324   return m_opaque_sp->DoesPrintValue(value_sp.get());
325 }
326 
327 lldb::SBTypeSummary &SBTypeSummary::operator=(const lldb::SBTypeSummary &rhs) {
328   LLDB_RECORD_METHOD(lldb::SBTypeSummary &,
329                      SBTypeSummary, operator=,(const lldb::SBTypeSummary &),
330                      rhs);
331 
332   if (this != &rhs) {
333     m_opaque_sp = rhs.m_opaque_sp;
334   }
335   return *this;
336 }
337 
338 bool SBTypeSummary::operator==(lldb::SBTypeSummary &rhs) {
339   LLDB_RECORD_METHOD(bool, SBTypeSummary, operator==,(lldb::SBTypeSummary &),
340                      rhs);
341 
342   if (!IsValid())
343     return !rhs.IsValid();
344   return m_opaque_sp == rhs.m_opaque_sp;
345 }
346 
347 bool SBTypeSummary::IsEqualTo(lldb::SBTypeSummary &rhs) {
348   LLDB_RECORD_METHOD(bool, SBTypeSummary, IsEqualTo, (lldb::SBTypeSummary &),
349                      rhs);
350 
351   if (IsValid()) {
352     // valid and invalid are different
353     if (!rhs.IsValid())
354       return false;
355   } else {
356     // invalid and valid are different
357     if (rhs.IsValid())
358       return false;
359     else
360       // both invalid are the same
361       return true;
362   }
363 
364   if (m_opaque_sp->GetKind() != rhs.m_opaque_sp->GetKind())
365     return false;
366 
367   switch (m_opaque_sp->GetKind()) {
368   case TypeSummaryImpl::Kind::eCallback:
369     return llvm::dyn_cast<CXXFunctionSummaryFormat>(m_opaque_sp.get()) ==
370            llvm::dyn_cast<CXXFunctionSummaryFormat>(rhs.m_opaque_sp.get());
371   case TypeSummaryImpl::Kind::eScript:
372     if (IsFunctionCode() != rhs.IsFunctionCode())
373       return false;
374     if (IsFunctionName() != rhs.IsFunctionName())
375       return false;
376     return GetOptions() == rhs.GetOptions();
377   case TypeSummaryImpl::Kind::eSummaryString:
378     if (IsSummaryString() != rhs.IsSummaryString())
379       return false;
380     return GetOptions() == rhs.GetOptions();
381   case TypeSummaryImpl::Kind::eInternal:
382     return (m_opaque_sp.get() == rhs.m_opaque_sp.get());
383   }
384 
385   return false;
386 }
387 
388 bool SBTypeSummary::operator!=(lldb::SBTypeSummary &rhs) {
389   LLDB_RECORD_METHOD(bool, SBTypeSummary, operator!=,(lldb::SBTypeSummary &),
390                      rhs);
391 
392   if (!IsValid())
393     return !rhs.IsValid();
394   return m_opaque_sp != rhs.m_opaque_sp;
395 }
396 
397 lldb::TypeSummaryImplSP SBTypeSummary::GetSP() { return m_opaque_sp; }
398 
399 void SBTypeSummary::SetSP(const lldb::TypeSummaryImplSP &typesummary_impl_sp) {
400   m_opaque_sp = typesummary_impl_sp;
401 }
402 
403 SBTypeSummary::SBTypeSummary(const lldb::TypeSummaryImplSP &typesummary_impl_sp)
404     : m_opaque_sp(typesummary_impl_sp) {}
405 
406 bool SBTypeSummary::CopyOnWrite_Impl() {
407   if (!IsValid())
408     return false;
409 
410   if (m_opaque_sp.unique())
411     return true;
412 
413   TypeSummaryImplSP new_sp;
414 
415   if (CXXFunctionSummaryFormat *current_summary_ptr =
416           llvm::dyn_cast<CXXFunctionSummaryFormat>(m_opaque_sp.get())) {
417     new_sp = TypeSummaryImplSP(new CXXFunctionSummaryFormat(
418         GetOptions(), current_summary_ptr->m_impl,
419         current_summary_ptr->m_description.c_str()));
420   } else if (ScriptSummaryFormat *current_summary_ptr =
421                  llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get())) {
422     new_sp = TypeSummaryImplSP(new ScriptSummaryFormat(
423         GetOptions(), current_summary_ptr->GetFunctionName(),
424         current_summary_ptr->GetPythonScript()));
425   } else if (StringSummaryFormat *current_summary_ptr =
426                  llvm::dyn_cast<StringSummaryFormat>(m_opaque_sp.get())) {
427     new_sp = TypeSummaryImplSP(new StringSummaryFormat(
428         GetOptions(), current_summary_ptr->GetSummaryString()));
429   }
430 
431   SetSP(new_sp);
432 
433   return nullptr != new_sp.get();
434 }
435 
436 bool SBTypeSummary::ChangeSummaryType(bool want_script) {
437   if (!IsValid())
438     return false;
439 
440   TypeSummaryImplSP new_sp;
441 
442   if (want_script ==
443       (m_opaque_sp->GetKind() == TypeSummaryImpl::Kind::eScript)) {
444     if (m_opaque_sp->GetKind() ==
445             lldb_private::TypeSummaryImpl::Kind::eCallback &&
446         !want_script)
447       new_sp = TypeSummaryImplSP(new StringSummaryFormat(GetOptions(), ""));
448     else
449       return CopyOnWrite_Impl();
450   }
451 
452   if (!new_sp) {
453     if (want_script)
454       new_sp = TypeSummaryImplSP(new ScriptSummaryFormat(GetOptions(), "", ""));
455     else
456       new_sp = TypeSummaryImplSP(new StringSummaryFormat(GetOptions(), ""));
457   }
458 
459   SetSP(new_sp);
460 
461   return true;
462 }
463