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