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   LLDB_RECORD_DUMMY(
163       lldb::SBTypeSummary, SBTypeSummary, CreateWithCallback,
164       (lldb::SBTypeSummary::FormatCallback, uint32_t, const char *), cb,
165       options, description);
166 
167   SBTypeSummary retval;
168   if (cb) {
169     retval.SetSP(TypeSummaryImplSP(new CXXFunctionSummaryFormat(
170         options,
171         [cb](ValueObject &valobj, Stream &stm,
172              const TypeSummaryOptions &opt) -> bool {
173           SBStream stream;
174           SBValue sb_value(valobj.GetSP());
175           SBTypeSummaryOptions options(&opt);
176           if (!cb(sb_value, options, stream))
177             return false;
178           stm.Write(stream.GetData(), stream.GetSize());
179           return true;
180         },
181         description ? description : "callback summary formatter")));
182   }
183 
184   return retval;
185 }
186 
187 SBTypeSummary::SBTypeSummary(const lldb::SBTypeSummary &rhs)
188     : m_opaque_sp(rhs.m_opaque_sp) {
189   LLDB_RECORD_CONSTRUCTOR(SBTypeSummary, (const lldb::SBTypeSummary &), rhs);
190 }
191 
192 SBTypeSummary::~SBTypeSummary() {}
193 
194 bool SBTypeSummary::IsValid() const {
195   LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBTypeSummary, IsValid);
196 
197   return m_opaque_sp.get() != NULL;
198 }
199 
200 bool SBTypeSummary::IsFunctionCode() {
201   LLDB_RECORD_METHOD_NO_ARGS(bool, SBTypeSummary, IsFunctionCode);
202 
203   if (!IsValid())
204     return false;
205   if (ScriptSummaryFormat *script_summary_ptr =
206           llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get())) {
207     const char *ftext = script_summary_ptr->GetPythonScript();
208     return (ftext && *ftext != 0);
209   }
210   return false;
211 }
212 
213 bool SBTypeSummary::IsFunctionName() {
214   LLDB_RECORD_METHOD_NO_ARGS(bool, SBTypeSummary, IsFunctionName);
215 
216   if (!IsValid())
217     return false;
218   if (ScriptSummaryFormat *script_summary_ptr =
219           llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get())) {
220     const char *ftext = script_summary_ptr->GetPythonScript();
221     return (!ftext || *ftext == 0);
222   }
223   return false;
224 }
225 
226 bool SBTypeSummary::IsSummaryString() {
227   LLDB_RECORD_METHOD_NO_ARGS(bool, SBTypeSummary, IsSummaryString);
228 
229   if (!IsValid())
230     return false;
231 
232   return m_opaque_sp->GetKind() == TypeSummaryImpl::Kind::eSummaryString;
233 }
234 
235 const char *SBTypeSummary::GetData() {
236   LLDB_RECORD_METHOD_NO_ARGS(const char *, SBTypeSummary, GetData);
237 
238   if (!IsValid())
239     return NULL;
240   if (ScriptSummaryFormat *script_summary_ptr =
241           llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get())) {
242     const char *fname = script_summary_ptr->GetFunctionName();
243     const char *ftext = script_summary_ptr->GetPythonScript();
244     if (ftext && *ftext)
245       return ftext;
246     return fname;
247   } else if (StringSummaryFormat *string_summary_ptr =
248                  llvm::dyn_cast<StringSummaryFormat>(m_opaque_sp.get()))
249     return string_summary_ptr->GetSummaryString();
250   return nullptr;
251 }
252 
253 uint32_t SBTypeSummary::GetOptions() {
254   LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBTypeSummary, GetOptions);
255 
256   if (!IsValid())
257     return lldb::eTypeOptionNone;
258   return m_opaque_sp->GetOptions();
259 }
260 
261 void SBTypeSummary::SetOptions(uint32_t value) {
262   LLDB_RECORD_METHOD(void, SBTypeSummary, SetOptions, (uint32_t), value);
263 
264   if (!CopyOnWrite_Impl())
265     return;
266   m_opaque_sp->SetOptions(value);
267 }
268 
269 void SBTypeSummary::SetSummaryString(const char *data) {
270   LLDB_RECORD_METHOD(void, SBTypeSummary, SetSummaryString, (const char *),
271                      data);
272 
273   if (!IsValid())
274     return;
275   if (!llvm::isa<StringSummaryFormat>(m_opaque_sp.get()))
276     ChangeSummaryType(false);
277   if (StringSummaryFormat *string_summary_ptr =
278           llvm::dyn_cast<StringSummaryFormat>(m_opaque_sp.get()))
279     string_summary_ptr->SetSummaryString(data);
280 }
281 
282 void SBTypeSummary::SetFunctionName(const char *data) {
283   LLDB_RECORD_METHOD(void, SBTypeSummary, SetFunctionName, (const char *),
284                      data);
285 
286   if (!IsValid())
287     return;
288   if (!llvm::isa<ScriptSummaryFormat>(m_opaque_sp.get()))
289     ChangeSummaryType(true);
290   if (ScriptSummaryFormat *script_summary_ptr =
291           llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get()))
292     script_summary_ptr->SetFunctionName(data);
293 }
294 
295 void SBTypeSummary::SetFunctionCode(const char *data) {
296   LLDB_RECORD_METHOD(void, SBTypeSummary, SetFunctionCode, (const char *),
297                      data);
298 
299   if (!IsValid())
300     return;
301   if (!llvm::isa<ScriptSummaryFormat>(m_opaque_sp.get()))
302     ChangeSummaryType(true);
303   if (ScriptSummaryFormat *script_summary_ptr =
304           llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get()))
305     script_summary_ptr->SetPythonScript(data);
306 }
307 
308 bool SBTypeSummary::GetDescription(lldb::SBStream &description,
309                                    lldb::DescriptionLevel description_level) {
310   LLDB_RECORD_METHOD(bool, SBTypeSummary, GetDescription,
311                      (lldb::SBStream &, lldb::DescriptionLevel), description,
312                      description_level);
313 
314   if (!CopyOnWrite_Impl())
315     return false;
316   else {
317     description.Printf("%s\n", m_opaque_sp->GetDescription().c_str());
318     return true;
319   }
320 }
321 
322 bool SBTypeSummary::DoesPrintValue(lldb::SBValue value) {
323   LLDB_RECORD_METHOD(bool, SBTypeSummary, DoesPrintValue, (lldb::SBValue),
324                      value);
325 
326   if (!IsValid())
327     return false;
328   lldb::ValueObjectSP value_sp = value.GetSP();
329   return m_opaque_sp->DoesPrintValue(value_sp.get());
330 }
331 
332 lldb::SBTypeSummary &SBTypeSummary::operator=(const lldb::SBTypeSummary &rhs) {
333   LLDB_RECORD_METHOD(lldb::SBTypeSummary &,
334                      SBTypeSummary, operator=,(const lldb::SBTypeSummary &),
335                      rhs);
336 
337   if (this != &rhs) {
338     m_opaque_sp = rhs.m_opaque_sp;
339   }
340   return *this;
341 }
342 
343 bool SBTypeSummary::operator==(lldb::SBTypeSummary &rhs) {
344   LLDB_RECORD_METHOD(bool, SBTypeSummary, operator==,(lldb::SBTypeSummary &),
345                      rhs);
346 
347   if (!IsValid())
348     return !rhs.IsValid();
349   return m_opaque_sp == rhs.m_opaque_sp;
350 }
351 
352 bool SBTypeSummary::IsEqualTo(lldb::SBTypeSummary &rhs) {
353   LLDB_RECORD_METHOD(bool, SBTypeSummary, IsEqualTo, (lldb::SBTypeSummary &),
354                      rhs);
355 
356   if (IsValid()) {
357     // valid and invalid are different
358     if (!rhs.IsValid())
359       return false;
360   } else {
361     // invalid and valid are different
362     if (rhs.IsValid())
363       return false;
364     else
365       // both invalid are the same
366       return true;
367   }
368 
369   if (m_opaque_sp->GetKind() != rhs.m_opaque_sp->GetKind())
370     return false;
371 
372   switch (m_opaque_sp->GetKind()) {
373   case TypeSummaryImpl::Kind::eCallback:
374     return llvm::dyn_cast<CXXFunctionSummaryFormat>(m_opaque_sp.get()) ==
375            llvm::dyn_cast<CXXFunctionSummaryFormat>(rhs.m_opaque_sp.get());
376   case TypeSummaryImpl::Kind::eScript:
377     if (IsFunctionCode() != rhs.IsFunctionCode())
378       return false;
379     if (IsFunctionName() != rhs.IsFunctionName())
380       return false;
381     return GetOptions() == rhs.GetOptions();
382   case TypeSummaryImpl::Kind::eSummaryString:
383     if (IsSummaryString() != rhs.IsSummaryString())
384       return false;
385     return GetOptions() == rhs.GetOptions();
386   case TypeSummaryImpl::Kind::eInternal:
387     return (m_opaque_sp.get() == rhs.m_opaque_sp.get());
388   }
389 
390   return false;
391 }
392 
393 bool SBTypeSummary::operator!=(lldb::SBTypeSummary &rhs) {
394   LLDB_RECORD_METHOD(bool, SBTypeSummary, operator!=,(lldb::SBTypeSummary &),
395                      rhs);
396 
397   if (!IsValid())
398     return !rhs.IsValid();
399   return m_opaque_sp != rhs.m_opaque_sp;
400 }
401 
402 lldb::TypeSummaryImplSP SBTypeSummary::GetSP() { return m_opaque_sp; }
403 
404 void SBTypeSummary::SetSP(const lldb::TypeSummaryImplSP &typesummary_impl_sp) {
405   m_opaque_sp = typesummary_impl_sp;
406 }
407 
408 SBTypeSummary::SBTypeSummary(const lldb::TypeSummaryImplSP &typesummary_impl_sp)
409     : m_opaque_sp(typesummary_impl_sp) {}
410 
411 bool SBTypeSummary::CopyOnWrite_Impl() {
412   if (!IsValid())
413     return false;
414 
415   if (m_opaque_sp.unique())
416     return true;
417 
418   TypeSummaryImplSP new_sp;
419 
420   if (CXXFunctionSummaryFormat *current_summary_ptr =
421           llvm::dyn_cast<CXXFunctionSummaryFormat>(m_opaque_sp.get())) {
422     new_sp = TypeSummaryImplSP(new CXXFunctionSummaryFormat(
423         GetOptions(), current_summary_ptr->m_impl,
424         current_summary_ptr->m_description.c_str()));
425   } else if (ScriptSummaryFormat *current_summary_ptr =
426                  llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get())) {
427     new_sp = TypeSummaryImplSP(new ScriptSummaryFormat(
428         GetOptions(), current_summary_ptr->GetFunctionName(),
429         current_summary_ptr->GetPythonScript()));
430   } else if (StringSummaryFormat *current_summary_ptr =
431                  llvm::dyn_cast<StringSummaryFormat>(m_opaque_sp.get())) {
432     new_sp = TypeSummaryImplSP(new StringSummaryFormat(
433         GetOptions(), current_summary_ptr->GetSummaryString()));
434   }
435 
436   SetSP(new_sp);
437 
438   return nullptr != new_sp.get();
439 }
440 
441 bool SBTypeSummary::ChangeSummaryType(bool want_script) {
442   if (!IsValid())
443     return false;
444 
445   TypeSummaryImplSP new_sp;
446 
447   if (want_script ==
448       (m_opaque_sp->GetKind() == TypeSummaryImpl::Kind::eScript)) {
449     if (m_opaque_sp->GetKind() ==
450             lldb_private::TypeSummaryImpl::Kind::eCallback &&
451         !want_script)
452       new_sp = TypeSummaryImplSP(new StringSummaryFormat(GetOptions(), ""));
453     else
454       return CopyOnWrite_Impl();
455   }
456 
457   if (!new_sp) {
458     if (want_script)
459       new_sp = TypeSummaryImplSP(new ScriptSummaryFormat(GetOptions(), "", ""));
460     else
461       new_sp = TypeSummaryImplSP(new StringSummaryFormat(GetOptions(), ""));
462   }
463 
464   SetSP(new_sp);
465 
466   return true;
467 }
468