1 //===-- FormattersContainer.h -----------------------------------*- 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 #ifndef lldb_FormattersContainer_h_
11 #define lldb_FormattersContainer_h_
12
13 #include <functional>
14 #include <map>
15 #include <memory>
16 #include <mutex>
17 #include <string>
18
19 #include "lldb/lldb-public.h"
20
21 #include "lldb/Core/ValueObject.h"
22 #include "lldb/DataFormatters/FormatClasses.h"
23 #include "lldb/DataFormatters/TypeFormat.h"
24 #include "lldb/DataFormatters/TypeSummary.h"
25 #include "lldb/DataFormatters/TypeSynthetic.h"
26 #include "lldb/DataFormatters/TypeValidator.h"
27 #include "lldb/Symbol/CompilerType.h"
28 #include "lldb/Utility/RegularExpression.h"
29 #include "lldb/Utility/StringLexer.h"
30
31 namespace lldb_private {
32
33 class IFormatChangeListener {
34 public:
35 virtual ~IFormatChangeListener() = default;
36
37 virtual void Changed() = 0;
38
39 virtual uint32_t GetCurrentRevision() = 0;
40 };
41
42 // if the user tries to add formatters for, say, "struct Foo" those will not
43 // match any type because of the way we strip qualifiers from typenames this
44 // method looks for the case where the user is adding a "class","struct","enum"
45 // or "union" Foo and strips the unnecessary qualifier
GetValidTypeName_Impl(const ConstString & type)46 static inline ConstString GetValidTypeName_Impl(const ConstString &type) {
47 if (type.IsEmpty())
48 return type;
49
50 std::string type_cstr(type.AsCString());
51 lldb_utility::StringLexer type_lexer(type_cstr);
52
53 type_lexer.AdvanceIf("class ");
54 type_lexer.AdvanceIf("enum ");
55 type_lexer.AdvanceIf("struct ");
56 type_lexer.AdvanceIf("union ");
57
58 while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first)
59 ;
60
61 return ConstString(type_lexer.GetUnlexed());
62 }
63
64 template <typename KeyType, typename ValueType> class FormattersContainer;
65
66 template <typename KeyType, typename ValueType> class FormatMap {
67 public:
68 typedef typename ValueType::SharedPointer ValueSP;
69 typedef std::map<KeyType, ValueSP> MapType;
70 typedef typename MapType::iterator MapIterator;
71 typedef std::function<bool(KeyType, const ValueSP &)> ForEachCallback;
72
FormatMap(IFormatChangeListener * lst)73 FormatMap(IFormatChangeListener *lst)
74 : m_map(), m_map_mutex(), listener(lst) {}
75
Add(KeyType name,const ValueSP & entry)76 void Add(KeyType name, const ValueSP &entry) {
77 if (listener)
78 entry->GetRevision() = listener->GetCurrentRevision();
79 else
80 entry->GetRevision() = 0;
81
82 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
83 m_map[name] = entry;
84 if (listener)
85 listener->Changed();
86 }
87
Delete(KeyType name)88 bool Delete(KeyType name) {
89 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
90 MapIterator iter = m_map.find(name);
91 if (iter == m_map.end())
92 return false;
93 m_map.erase(name);
94 if (listener)
95 listener->Changed();
96 return true;
97 }
98
Clear()99 void Clear() {
100 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
101 m_map.clear();
102 if (listener)
103 listener->Changed();
104 }
105
Get(KeyType name,ValueSP & entry)106 bool Get(KeyType name, ValueSP &entry) {
107 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
108 MapIterator iter = m_map.find(name);
109 if (iter == m_map.end())
110 return false;
111 entry = iter->second;
112 return true;
113 }
114
ForEach(ForEachCallback callback)115 void ForEach(ForEachCallback callback) {
116 if (callback) {
117 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
118 MapIterator pos, end = m_map.end();
119 for (pos = m_map.begin(); pos != end; pos++) {
120 KeyType type = pos->first;
121 if (!callback(type, pos->second))
122 break;
123 }
124 }
125 }
126
GetCount()127 uint32_t GetCount() { return m_map.size(); }
128
GetValueAtIndex(size_t index)129 ValueSP GetValueAtIndex(size_t index) {
130 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
131 MapIterator iter = m_map.begin();
132 MapIterator end = m_map.end();
133 while (index > 0) {
134 iter++;
135 index--;
136 if (end == iter)
137 return ValueSP();
138 }
139 return iter->second;
140 }
141
GetKeyAtIndex(size_t index)142 KeyType GetKeyAtIndex(size_t index) {
143 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
144 MapIterator iter = m_map.begin();
145 MapIterator end = m_map.end();
146 while (index > 0) {
147 iter++;
148 index--;
149 if (end == iter)
150 return KeyType();
151 }
152 return iter->first;
153 }
154
155 protected:
156 MapType m_map;
157 std::recursive_mutex m_map_mutex;
158 IFormatChangeListener *listener;
159
map()160 MapType &map() { return m_map; }
161
mutex()162 std::recursive_mutex &mutex() { return m_map_mutex; }
163
164 friend class FormattersContainer<KeyType, ValueType>;
165 friend class FormatManager;
166 };
167
168 template <typename KeyType, typename ValueType> class FormattersContainer {
169 protected:
170 typedef FormatMap<KeyType, ValueType> BackEndType;
171
172 public:
173 typedef typename BackEndType::MapType MapType;
174 typedef typename MapType::iterator MapIterator;
175 typedef typename MapType::key_type MapKeyType;
176 typedef typename MapType::mapped_type MapValueType;
177 typedef typename BackEndType::ForEachCallback ForEachCallback;
178 typedef typename std::shared_ptr<FormattersContainer<KeyType, ValueType>>
179 SharedPointer;
180
181 friend class TypeCategoryImpl;
182
FormattersContainer(std::string name,IFormatChangeListener * lst)183 FormattersContainer(std::string name, IFormatChangeListener *lst)
184 : m_format_map(lst), m_name(name) {}
185
Add(const MapKeyType & type,const MapValueType & entry)186 void Add(const MapKeyType &type, const MapValueType &entry) {
187 Add_Impl(type, entry, static_cast<KeyType *>(nullptr));
188 }
189
Delete(ConstString type)190 bool Delete(ConstString type) {
191 return Delete_Impl(type, static_cast<KeyType *>(nullptr));
192 }
193
194 bool Get(ValueObject &valobj, MapValueType &entry,
195 lldb::DynamicValueType use_dynamic, uint32_t *why = nullptr) {
196 uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice;
197 CompilerType ast_type(valobj.GetCompilerType());
198 bool ret = Get(valobj, ast_type, entry, use_dynamic, value);
199 if (ret)
200 entry = MapValueType(entry);
201 else
202 entry = MapValueType();
203 if (why)
204 *why = value;
205 return ret;
206 }
207
Get(ConstString type,MapValueType & entry)208 bool Get(ConstString type, MapValueType &entry) {
209 return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));
210 }
211
GetExact(ConstString type,MapValueType & entry)212 bool GetExact(ConstString type, MapValueType &entry) {
213 return GetExact_Impl(type, entry, static_cast<KeyType *>(nullptr));
214 }
215
GetAtIndex(size_t index)216 MapValueType GetAtIndex(size_t index) {
217 return m_format_map.GetValueAtIndex(index);
218 }
219
GetTypeNameSpecifierAtIndex(size_t index)220 lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) {
221 return GetTypeNameSpecifierAtIndex_Impl(index,
222 static_cast<KeyType *>(nullptr));
223 }
224
Clear()225 void Clear() { m_format_map.Clear(); }
226
ForEach(ForEachCallback callback)227 void ForEach(ForEachCallback callback) { m_format_map.ForEach(callback); }
228
GetCount()229 uint32_t GetCount() { return m_format_map.GetCount(); }
230
231 protected:
232 BackEndType m_format_map;
233 std::string m_name;
234
235 DISALLOW_COPY_AND_ASSIGN(FormattersContainer);
236
Add_Impl(const MapKeyType & type,const MapValueType & entry,lldb::RegularExpressionSP * dummy)237 void Add_Impl(const MapKeyType &type, const MapValueType &entry,
238 lldb::RegularExpressionSP *dummy) {
239 m_format_map.Add(type, entry);
240 }
241
Add_Impl(const ConstString & type,const MapValueType & entry,ConstString * dummy)242 void Add_Impl(const ConstString &type, const MapValueType &entry,
243 ConstString *dummy) {
244 m_format_map.Add(GetValidTypeName_Impl(type), entry);
245 }
246
Delete_Impl(ConstString type,ConstString * dummy)247 bool Delete_Impl(ConstString type, ConstString *dummy) {
248 return m_format_map.Delete(type);
249 }
250
Delete_Impl(ConstString type,lldb::RegularExpressionSP * dummy)251 bool Delete_Impl(ConstString type, lldb::RegularExpressionSP *dummy) {
252 std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
253 MapIterator pos, end = m_format_map.map().end();
254 for (pos = m_format_map.map().begin(); pos != end; pos++) {
255 lldb::RegularExpressionSP regex = pos->first;
256 if (type.GetStringRef() == regex->GetText()) {
257 m_format_map.map().erase(pos);
258 if (m_format_map.listener)
259 m_format_map.listener->Changed();
260 return true;
261 }
262 }
263 return false;
264 }
265
Get_Impl(ConstString type,MapValueType & entry,ConstString * dummy)266 bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) {
267 return m_format_map.Get(type, entry);
268 }
269
GetExact_Impl(ConstString type,MapValueType & entry,ConstString * dummy)270 bool GetExact_Impl(ConstString type, MapValueType &entry,
271 ConstString *dummy) {
272 return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));
273 }
274
275 lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierAtIndex_Impl(size_t index,ConstString * dummy)276 GetTypeNameSpecifierAtIndex_Impl(size_t index, ConstString *dummy) {
277 ConstString key = m_format_map.GetKeyAtIndex(index);
278 if (key)
279 return lldb::TypeNameSpecifierImplSP(
280 new TypeNameSpecifierImpl(key.AsCString(), false));
281 else
282 return lldb::TypeNameSpecifierImplSP();
283 }
284
285 lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierAtIndex_Impl(size_t index,lldb::RegularExpressionSP * dummy)286 GetTypeNameSpecifierAtIndex_Impl(size_t index,
287 lldb::RegularExpressionSP *dummy) {
288 lldb::RegularExpressionSP regex = m_format_map.GetKeyAtIndex(index);
289 if (regex.get() == nullptr)
290 return lldb::TypeNameSpecifierImplSP();
291 return lldb::TypeNameSpecifierImplSP(
292 new TypeNameSpecifierImpl(regex->GetText().str().c_str(), true));
293 }
294
Get_Impl(ConstString key,MapValueType & value,lldb::RegularExpressionSP * dummy)295 bool Get_Impl(ConstString key, MapValueType &value,
296 lldb::RegularExpressionSP *dummy) {
297 llvm::StringRef key_str = key.GetStringRef();
298 std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
299 MapIterator pos, end = m_format_map.map().end();
300 for (pos = m_format_map.map().begin(); pos != end; pos++) {
301 lldb::RegularExpressionSP regex = pos->first;
302 if (regex->Execute(key_str)) {
303 value = pos->second;
304 return true;
305 }
306 }
307 return false;
308 }
309
GetExact_Impl(ConstString key,MapValueType & value,lldb::RegularExpressionSP * dummy)310 bool GetExact_Impl(ConstString key, MapValueType &value,
311 lldb::RegularExpressionSP *dummy) {
312 std::lock_guard<std::recursive_mutex> guard(m_format_map.mutex());
313 MapIterator pos, end = m_format_map.map().end();
314 for (pos = m_format_map.map().begin(); pos != end; pos++) {
315 lldb::RegularExpressionSP regex = pos->first;
316 if (regex->GetText() == key.GetStringRef()) {
317 value = pos->second;
318 return true;
319 }
320 }
321 return false;
322 }
323
Get(const FormattersMatchVector & candidates,MapValueType & entry,uint32_t * reason)324 bool Get(const FormattersMatchVector &candidates, MapValueType &entry,
325 uint32_t *reason) {
326 for (const FormattersMatchCandidate &candidate : candidates) {
327 if (Get(candidate.GetTypeName(), entry)) {
328 if (candidate.IsMatch(entry) == false) {
329 entry.reset();
330 continue;
331 } else {
332 if (reason)
333 *reason = candidate.GetReason();
334 return true;
335 }
336 }
337 }
338 return false;
339 }
340 };
341
342 } // namespace lldb_private
343
344 #endif // lldb_FormattersContainer_h_
345