1 //===-- ValueObjectSyntheticFilter.cpp -----------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/lldb-python.h"
11 
12 #include "lldb/Core/ValueObjectSyntheticFilter.h"
13 
14 // C Includes
15 // C++ Includes
16 // Other libraries and framework includes
17 // Project includes
18 #include "lldb/Core/ValueObject.h"
19 #include "lldb/DataFormatters/FormatClasses.h"
20 
21 using namespace lldb_private;
22 
23 class DummySyntheticFrontEnd : public SyntheticChildrenFrontEnd
24 {
25 public:
DummySyntheticFrontEnd(ValueObject & backend)26     DummySyntheticFrontEnd(ValueObject &backend) :
27     SyntheticChildrenFrontEnd(backend)
28     {}
29 
30     size_t
CalculateNumChildren()31     CalculateNumChildren()
32     {
33         return 0;
34     }
35 
36     lldb::ValueObjectSP
GetChildAtIndex(size_t idx)37     GetChildAtIndex (size_t idx)
38     {
39         return lldb::ValueObjectSP();
40     }
41 
42     size_t
GetIndexOfChildWithName(const ConstString & name)43     GetIndexOfChildWithName (const ConstString &name)
44     {
45         return UINT32_MAX;
46     }
47 
48     bool
MightHaveChildren()49     MightHaveChildren ()
50     {
51         return true;
52     }
53 
54     bool
Update()55     Update()
56     {
57         return false;
58     }
59 
60 };
61 
ValueObjectSynthetic(ValueObject & parent,lldb::SyntheticChildrenSP filter)62 ValueObjectSynthetic::ValueObjectSynthetic (ValueObject &parent, lldb::SyntheticChildrenSP filter) :
63     ValueObject(parent),
64     m_synth_sp(filter),
65     m_children_byindex(),
66     m_name_toindex(),
67     m_synthetic_children_count(UINT32_MAX),
68     m_parent_type_name(parent.GetTypeName()),
69     m_might_have_children(eLazyBoolCalculate)
70 {
71 #ifdef LLDB_CONFIGURATION_DEBUG
72     std::string new_name(parent.GetName().AsCString());
73     new_name += "$$__synth__";
74     SetName (ConstString(new_name.c_str()));
75 #else
76     SetName(parent.GetName());
77 #endif
78     CopyParentData();
79     CreateSynthFilter();
80 }
81 
~ValueObjectSynthetic()82 ValueObjectSynthetic::~ValueObjectSynthetic()
83 {
84 }
85 
86 ClangASTType
GetClangTypeImpl()87 ValueObjectSynthetic::GetClangTypeImpl ()
88 {
89     return m_parent->GetClangType();
90 }
91 
92 ConstString
GetTypeName()93 ValueObjectSynthetic::GetTypeName()
94 {
95     return m_parent->GetTypeName();
96 }
97 
98 ConstString
GetQualifiedTypeName()99 ValueObjectSynthetic::GetQualifiedTypeName()
100 {
101     return m_parent->GetQualifiedTypeName();
102 }
103 
104 size_t
CalculateNumChildren()105 ValueObjectSynthetic::CalculateNumChildren()
106 {
107     UpdateValueIfNeeded();
108     if (m_synthetic_children_count < UINT32_MAX)
109         return m_synthetic_children_count;
110     return (m_synthetic_children_count = m_synth_filter_ap->CalculateNumChildren());
111 }
112 
113 lldb::ValueObjectSP
GetDynamicValue(lldb::DynamicValueType valueType)114 ValueObjectSynthetic::GetDynamicValue (lldb::DynamicValueType valueType)
115 {
116     if (!m_parent)
117         return lldb::ValueObjectSP();
118     if (IsDynamic() && GetDynamicValueType() == valueType)
119         return GetSP();
120     return m_parent->GetDynamicValue(valueType);
121 }
122 
123 bool
MightHaveChildren()124 ValueObjectSynthetic::MightHaveChildren()
125 {
126     if (m_might_have_children == eLazyBoolCalculate)
127         m_might_have_children = (m_synth_filter_ap->MightHaveChildren() ? eLazyBoolYes : eLazyBoolNo);
128     return (m_might_have_children == eLazyBoolNo ? false : true);
129 }
130 
131 uint64_t
GetByteSize()132 ValueObjectSynthetic::GetByteSize()
133 {
134     return m_parent->GetByteSize();
135 }
136 
137 lldb::ValueType
GetValueType() const138 ValueObjectSynthetic::GetValueType() const
139 {
140     return m_parent->GetValueType();
141 }
142 
143 void
CreateSynthFilter()144 ValueObjectSynthetic::CreateSynthFilter ()
145 {
146     m_synth_filter_ap = (m_synth_sp->GetFrontEnd(*m_parent));
147     if (!m_synth_filter_ap.get())
148         m_synth_filter_ap.reset(new DummySyntheticFrontEnd(*m_parent));
149 }
150 
151 bool
UpdateValue()152 ValueObjectSynthetic::UpdateValue ()
153 {
154     SetValueIsValid (false);
155     m_error.Clear();
156 
157     if (!m_parent->UpdateValueIfNeeded(false))
158     {
159         // our parent could not update.. as we are meaningless without a parent, just stop
160         if (m_parent->GetError().Fail())
161             m_error = m_parent->GetError();
162         return false;
163     }
164 
165     // regenerate the synthetic filter if our typename changes
166     // <rdar://problem/12424824>
167     ConstString new_parent_type_name = m_parent->GetTypeName();
168     if (new_parent_type_name != m_parent_type_name)
169     {
170         m_parent_type_name = new_parent_type_name;
171         CreateSynthFilter();
172     }
173 
174     // let our backend do its update
175     if (m_synth_filter_ap->Update() == false)
176     {
177         // filter said that cached values are stale
178         m_children_byindex.clear();
179         m_name_toindex.clear();
180         // usually, an object's value can change but this does not alter its children count
181         // for a synthetic VO that might indeed happen, so we need to tell the upper echelons
182         // that they need to come back to us asking for children
183         m_children_count_valid = false;
184         m_synthetic_children_count = UINT32_MAX;
185         m_might_have_children = eLazyBoolCalculate;
186     }
187 
188     CopyParentData();
189 
190     SetValueIsValid(true);
191     return true;
192 }
193 
194 lldb::ValueObjectSP
GetChildAtIndex(size_t idx,bool can_create)195 ValueObjectSynthetic::GetChildAtIndex (size_t idx, bool can_create)
196 {
197     UpdateValueIfNeeded();
198 
199     ByIndexIterator iter = m_children_byindex.find(idx);
200 
201     if (iter == m_children_byindex.end())
202     {
203         if (can_create && m_synth_filter_ap.get() != NULL)
204         {
205             lldb::ValueObjectSP synth_guy = m_synth_filter_ap->GetChildAtIndex (idx);
206             if (!synth_guy)
207                 return synth_guy;
208             m_children_byindex[idx]= synth_guy.get();
209             return synth_guy;
210         }
211         else
212             return lldb::ValueObjectSP();
213     }
214     else
215         return iter->second->GetSP();
216 }
217 
218 lldb::ValueObjectSP
GetChildMemberWithName(const ConstString & name,bool can_create)219 ValueObjectSynthetic::GetChildMemberWithName (const ConstString &name, bool can_create)
220 {
221     UpdateValueIfNeeded();
222 
223     uint32_t index = GetIndexOfChildWithName(name);
224 
225     if (index == UINT32_MAX)
226         return lldb::ValueObjectSP();
227 
228     return GetChildAtIndex(index, can_create);
229 }
230 
231 size_t
GetIndexOfChildWithName(const ConstString & name)232 ValueObjectSynthetic::GetIndexOfChildWithName (const ConstString &name)
233 {
234     UpdateValueIfNeeded();
235 
236     NameToIndexIterator iter = m_name_toindex.find(name.GetCString());
237 
238     if (iter == m_name_toindex.end() && m_synth_filter_ap.get() != NULL)
239     {
240         uint32_t index = m_synth_filter_ap->GetIndexOfChildWithName (name);
241         if (index == UINT32_MAX)
242             return index;
243         m_name_toindex[name.GetCString()] = index;
244         return index;
245     }
246     else if (iter == m_name_toindex.end() && m_synth_filter_ap.get() == NULL)
247         return UINT32_MAX;
248     else /*if (iter != m_name_toindex.end())*/
249         return iter->second;
250 }
251 
252 bool
IsInScope()253 ValueObjectSynthetic::IsInScope ()
254 {
255     return m_parent->IsInScope();
256 }
257 
258 lldb::ValueObjectSP
GetNonSyntheticValue()259 ValueObjectSynthetic::GetNonSyntheticValue ()
260 {
261     return m_parent->GetSP();
262 }
263 
264 void
CopyParentData()265 ValueObjectSynthetic::CopyParentData ()
266 {
267     m_value = m_parent->GetValue();
268     ExecutionContext exe_ctx (GetExecutionContextRef());
269     m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
270 }
271