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 
23 using namespace lldb;
24 using namespace lldb_private;
25 
26 void 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(path);
33   else
34     m_expression_paths.push_back(std::string(".") + path);
35 }
36 
37 bool 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 
52 size_t
53 TypeFilterImpl::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(name_cstr, expr_cstr))
66           return i;
67       }
68     }
69   }
70   return UINT32_MAX;
71 }
72 
73 std::string TypeFilterImpl::GetDescription() {
74   StreamString sstr;
75   sstr.Printf("%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("    %s\n", GetExpressionPathAtIndex(i));
81   }
82 
83   sstr.Printf("}");
84   return std::string(sstr.GetString());
85 }
86 
87 std::string CXXSyntheticChildren::GetDescription() {
88   StreamString sstr;
89   sstr.Printf("%s%s%s %s", Cascades() ? "" : " (not cascading)",
90               SkipsPointers() ? " (skip pointers)" : "",
91               SkipsReferences() ? " (skip references)" : "",
92               m_description.c_str());
93 
94   return std::string(sstr.GetString());
95 }
96 
97 lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromExpression(
98     llvm::StringRef name, llvm::StringRef expression,
99     const ExecutionContext &exe_ctx) {
100   ValueObjectSP valobj_sp(
101       ValueObject::CreateValueObjectFromExpression(name, expression, exe_ctx));
102   if (valobj_sp)
103     valobj_sp->SetSyntheticChildrenGenerated(true);
104   return valobj_sp;
105 }
106 
107 lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromAddress(
108     llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx,
109     CompilerType type) {
110   ValueObjectSP valobj_sp(
111       ValueObject::CreateValueObjectFromAddress(name, address, exe_ctx, type));
112   if (valobj_sp)
113     valobj_sp->SetSyntheticChildrenGenerated(true);
114   return valobj_sp;
115 }
116 
117 lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromData(
118     llvm::StringRef name, const DataExtractor &data,
119     const ExecutionContext &exe_ctx, CompilerType type) {
120   ValueObjectSP valobj_sp(
121       ValueObject::CreateValueObjectFromData(name, data, exe_ctx, type));
122   if (valobj_sp)
123     valobj_sp->SetSyntheticChildrenGenerated(true);
124   return valobj_sp;
125 }
126 
127 ScriptedSyntheticChildren::FrontEnd::FrontEnd(std::string pclass,
128                                               ValueObject &backend)
129     : SyntheticChildrenFrontEnd(backend), m_python_class(pclass),
130       m_wrapper_sp(), m_interpreter(nullptr) {
131   if (backend.GetID() == LLDB_INVALID_UID)
132     return;
133 
134   TargetSP target_sp = backend.GetTargetSP();
135 
136   if (!target_sp)
137     return;
138 
139   m_interpreter = target_sp->GetDebugger().GetScriptInterpreter();
140 
141   if (m_interpreter != nullptr)
142     m_wrapper_sp = m_interpreter->CreateSyntheticScriptedProvider(
143         m_python_class.c_str(), backend.GetSP());
144 }
145 
146 ScriptedSyntheticChildren::FrontEnd::~FrontEnd() = default;
147 
148 lldb::ValueObjectSP
149 ScriptedSyntheticChildren::FrontEnd::GetChildAtIndex(size_t idx) {
150   if (!m_wrapper_sp || !m_interpreter)
151     return lldb::ValueObjectSP();
152 
153   return m_interpreter->GetChildAtIndex(m_wrapper_sp, idx);
154 }
155 
156 bool ScriptedSyntheticChildren::FrontEnd::IsValid() {
157   return (m_wrapper_sp && m_wrapper_sp->IsValid() && m_interpreter);
158 }
159 
160 size_t ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren() {
161   if (!m_wrapper_sp || m_interpreter == nullptr)
162     return 0;
163   return m_interpreter->CalculateNumChildren(m_wrapper_sp, UINT32_MAX);
164 }
165 
166 size_t ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren(uint32_t max) {
167   if (!m_wrapper_sp || m_interpreter == nullptr)
168     return 0;
169   return m_interpreter->CalculateNumChildren(m_wrapper_sp, max);
170 }
171 
172 bool ScriptedSyntheticChildren::FrontEnd::Update() {
173   if (!m_wrapper_sp || m_interpreter == nullptr)
174     return false;
175 
176   return m_interpreter->UpdateSynthProviderInstance(m_wrapper_sp);
177 }
178 
179 bool ScriptedSyntheticChildren::FrontEnd::MightHaveChildren() {
180   if (!m_wrapper_sp || m_interpreter == nullptr)
181     return false;
182 
183   return m_interpreter->MightHaveChildrenSynthProviderInstance(m_wrapper_sp);
184 }
185 
186 size_t ScriptedSyntheticChildren::FrontEnd::GetIndexOfChildWithName(
187     ConstString name) {
188   if (!m_wrapper_sp || m_interpreter == nullptr)
189     return UINT32_MAX;
190   return m_interpreter->GetIndexOfChildWithName(m_wrapper_sp,
191                                                 name.GetCString());
192 }
193 
194 lldb::ValueObjectSP ScriptedSyntheticChildren::FrontEnd::GetSyntheticValue() {
195   if (!m_wrapper_sp || m_interpreter == nullptr)
196     return nullptr;
197 
198   return m_interpreter->GetSyntheticValue(m_wrapper_sp);
199 }
200 
201 ConstString ScriptedSyntheticChildren::FrontEnd::GetSyntheticTypeName() {
202   if (!m_wrapper_sp || m_interpreter == nullptr)
203     return ConstString();
204 
205   return m_interpreter->GetSyntheticTypeName(m_wrapper_sp);
206 }
207 
208 std::string ScriptedSyntheticChildren::GetDescription() {
209   StreamString sstr;
210   sstr.Printf("%s%s%s Python class %s", Cascades() ? "" : " (not cascading)",
211               SkipsPointers() ? " (skip pointers)" : "",
212               SkipsReferences() ? " (skip references)" : "",
213               m_python_class.c_str());
214 
215   return std::string(sstr.GetString());
216 }
217