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