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