1//===-- TypeSynthetic.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
10
11
12#include "lldb/lldb-enumerations.h"
13#include "lldb/lldb-public.h"
14
15#include "lldb/Core/Debugger.h"
16#include "lldb/DataFormatters/TypeSynthetic.h"
17#include "lldb/Interpreter/CommandInterpreter.h"
18#include "lldb/Interpreter/ScriptInterpreter.h"
19#include "lldb/Symbol/CompilerType.h"
20#include "lldb/Target/Target.h"
21#include "lldb/Utility/StreamString.h"
22
23using namespace lldb;
24using namespace lldb_private;
25
26void TypeFilterImpl::AddExpressionPath(const std::string &path) {
27 bool need_add_dot = true;
28 if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[')
29 need_add_dot = false;
30 // add a '.' symbol to help forgetful users
31 if (!need_add_dot)
32 m_expression_paths.push_back(x: path);
33 else
34 m_expression_paths.push_back(x: std::string(".") + path);
35}
36
37bool TypeFilterImpl::SetExpressionPathAtIndex(size_t i,
38 const std::string &path) {
39 if (i >= GetCount())
40 return false;
41 bool need_add_dot = true;
42 if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[')
43 need_add_dot = false;
44 // add a '.' symbol to help forgetful users
45 if (!need_add_dot)
46 m_expression_paths[i] = path;
47 else
48 m_expression_paths[i] = std::string(".") + path;
49 return true;
50}
51
52size_t
53TypeFilterImpl::FrontEnd::GetIndexOfChildWithName(ConstString name) {
54 const char *name_cstr = name.GetCString();
55 if (name_cstr) {
56 for (size_t i = 0; i < filter->GetCount(); i++) {
57 const char *expr_cstr = filter->GetExpressionPathAtIndex(i);
58 if (expr_cstr) {
59 if (*expr_cstr == '.')
60 expr_cstr++;
61 else if (*expr_cstr == '-' && *(expr_cstr + 1) == '>')
62 expr_cstr += 2;
63 }
64 if (expr_cstr) {
65 if (!::strcmp(s1: name_cstr, s2: expr_cstr))
66 return i;
67 }
68 }
69 }
70 return UINT32_MAX;
71}
72
73std::string TypeFilterImpl::GetDescription() {
74 StreamString sstr;
75 sstr.Printf(format: "%s%s%s {\n", Cascades() ? "" : " (not cascading)",
76 SkipsPointers() ? " (skip pointers)" : "",
77 SkipsReferences() ? " (skip references)" : "");
78
79 for (size_t i = 0; i < GetCount(); i++) {
80 sstr.Printf(format: " %s\n", GetExpressionPathAtIndex(i));
81 }
82
83 sstr.Printf(format: "}");
84 return std::string(sstr.GetString());
85}
86
87SyntheticChildren::SyntheticChildren(const Flags &flags) : m_flags(flags) {}
88
89SyntheticChildren::~SyntheticChildren() = default;
90
91CXXSyntheticChildren::CXXSyntheticChildren(
92 const SyntheticChildren::Flags &flags, const char *description,
93 CreateFrontEndCallback callback)
94 : SyntheticChildren(flags), m_create_callback(std::move(callback)),
95 m_description(description ? description : "") {}
96
97CXXSyntheticChildren::~CXXSyntheticChildren() = default;
98
99bool SyntheticChildren::IsScripted() { return false; }
100
101std::string SyntheticChildren::GetDescription() { return ""; }
102
103SyntheticChildrenFrontEnd::AutoPointer
104SyntheticChildren::GetFrontEnd(ValueObject &backend) {
105 return nullptr;
106}
107
108std::string CXXSyntheticChildren::GetDescription() {
109 StreamString sstr;
110 sstr.Printf(format: "%s%s%s %s", Cascades() ? "" : " (not cascading)",
111 SkipsPointers() ? " (skip pointers)" : "",
112 SkipsReferences() ? " (skip references)" : "",
113 m_description.c_str());
114
115 return std::string(sstr.GetString());
116}
117
118lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromExpression(
119 llvm::StringRef name, llvm::StringRef expression,
120 const ExecutionContext &exe_ctx) {
121 ValueObjectSP valobj_sp(
122 ValueObject::CreateValueObjectFromExpression(name, expression, exe_ctx));
123 if (valobj_sp)
124 valobj_sp->SetSyntheticChildrenGenerated(true);
125 return valobj_sp;
126}
127
128lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromAddress(
129 llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx,
130 CompilerType type) {
131 ValueObjectSP valobj_sp(
132 ValueObject::CreateValueObjectFromAddress(name, address, exe_ctx, type));
133 if (valobj_sp)
134 valobj_sp->SetSyntheticChildrenGenerated(true);
135 return valobj_sp;
136}
137
138lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromData(
139 llvm::StringRef name, const DataExtractor &data,
140 const ExecutionContext &exe_ctx, CompilerType type) {
141 ValueObjectSP valobj_sp(
142 ValueObject::CreateValueObjectFromData(name, data, exe_ctx, type));
143 if (valobj_sp)
144 valobj_sp->SetSyntheticChildrenGenerated(true);
145 return valobj_sp;
146}
147
148ScriptedSyntheticChildren::FrontEnd::FrontEnd(std::string pclass,
149 ValueObject &backend)
150 : SyntheticChildrenFrontEnd(backend), m_python_class(pclass),
151 m_wrapper_sp(), m_interpreter(nullptr) {
152 if (backend.GetID() == LLDB_INVALID_UID)
153 return;
154
155 TargetSP target_sp = backend.GetTargetSP();
156
157 if (!target_sp)
158 return;
159
160 m_interpreter = target_sp->GetDebugger().GetScriptInterpreter();
161
162 if (m_interpreter != nullptr)
163 m_wrapper_sp = m_interpreter->CreateSyntheticScriptedProvider(
164 class_name: m_python_class.c_str(), valobj: backend.GetSP());
165}
166
167ScriptedSyntheticChildren::FrontEnd::~FrontEnd() = default;
168
169lldb::ValueObjectSP
170ScriptedSyntheticChildren::FrontEnd::GetChildAtIndex(size_t idx) {
171 if (!m_wrapper_sp || !m_interpreter)
172 return lldb::ValueObjectSP();
173
174 return m_interpreter->GetChildAtIndex(implementor: m_wrapper_sp, idx);
175}
176
177bool ScriptedSyntheticChildren::FrontEnd::IsValid() {
178 return (m_wrapper_sp && m_wrapper_sp->IsValid() && m_interpreter);
179}
180
181size_t ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren() {
182 if (!m_wrapper_sp || m_interpreter == nullptr)
183 return 0;
184 return m_interpreter->CalculateNumChildren(implementor: m_wrapper_sp, UINT32_MAX);
185}
186
187size_t ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren(uint32_t max) {
188 if (!m_wrapper_sp || m_interpreter == nullptr)
189 return 0;
190 return m_interpreter->CalculateNumChildren(implementor: m_wrapper_sp, max);
191}
192
193lldb::ChildCacheState ScriptedSyntheticChildren::FrontEnd::Update() {
194 if (!m_wrapper_sp || m_interpreter == nullptr)
195 return lldb::ChildCacheState::eRefetch;
196
197 return m_interpreter->UpdateSynthProviderInstance(implementor: m_wrapper_sp)
198 ? lldb::ChildCacheState::eReuse
199 : lldb::ChildCacheState::eRefetch;
200}
201
202bool ScriptedSyntheticChildren::FrontEnd::MightHaveChildren() {
203 if (!m_wrapper_sp || m_interpreter == nullptr)
204 return false;
205
206 return m_interpreter->MightHaveChildrenSynthProviderInstance(implementor: m_wrapper_sp);
207}
208
209size_t ScriptedSyntheticChildren::FrontEnd::GetIndexOfChildWithName(
210 ConstString name) {
211 if (!m_wrapper_sp || m_interpreter == nullptr)
212 return UINT32_MAX;
213 return m_interpreter->GetIndexOfChildWithName(implementor: m_wrapper_sp,
214 child_name: name.GetCString());
215}
216
217lldb::ValueObjectSP ScriptedSyntheticChildren::FrontEnd::GetSyntheticValue() {
218 if (!m_wrapper_sp || m_interpreter == nullptr)
219 return nullptr;
220
221 return m_interpreter->GetSyntheticValue(implementor: m_wrapper_sp);
222}
223
224ConstString ScriptedSyntheticChildren::FrontEnd::GetSyntheticTypeName() {
225 if (!m_wrapper_sp || m_interpreter == nullptr)
226 return ConstString();
227
228 return m_interpreter->GetSyntheticTypeName(implementor: m_wrapper_sp);
229}
230
231std::string ScriptedSyntheticChildren::GetDescription() {
232 StreamString sstr;
233 sstr.Printf(format: "%s%s%s Python class %s", Cascades() ? "" : " (not cascading)",
234 SkipsPointers() ? " (skip pointers)" : "",
235 SkipsReferences() ? " (skip references)" : "",
236 m_python_class.c_str());
237
238 return std::string(sstr.GetString());
239}
240

source code of lldb/source/DataFormatters/TypeSynthetic.cpp