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