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
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 
71   FormatMap(IFormatChangeListener *lst)
72       : m_map(), m_map_mutex(), listener(lst) {}
73 
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 
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 
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 
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 
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 
127   uint32_t GetCount() { return m_map.size(); }
128 
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.
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 
149   MapType &map() { return m_map; }
150 
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 
172   FormattersContainer(std::string name, IFormatChangeListener *lst)
173       : m_format_map(lst), m_name(name) {}
174 
175   void Add(MapKeyType type, const MapValueType &entry) {
176     Add_Impl(std::move(type), entry, static_cast<KeyType *>(nullptr));
177   }
178 
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 
197   bool Get(ConstString type, MapValueType &entry) {
198     return Get_Impl(type, entry, static_cast<KeyType *>(nullptr));
199   }
200 
201   bool GetExact(ConstString type, MapValueType &entry) {
202     return GetExact_Impl(type, entry, static_cast<KeyType *>(nullptr));
203   }
204 
205   MapValueType GetAtIndex(size_t index) {
206     return m_format_map.GetValueAtIndex(index);
207   }
208 
209   lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) {
210     return GetTypeNameSpecifierAtIndex_Impl(index,
211                                             static_cast<KeyType *>(nullptr));
212   }
213 
214   void Clear() { m_format_map.Clear(); }
215 
216   void ForEach(ForEachCallback callback) { m_format_map.ForEach(callback); }
217 
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 
226   void Add_Impl(MapKeyType type, const MapValueType &entry,
227                 RegularExpression *dummy) {
228     m_format_map.Add(std::move(type), entry);
229   }
230 
231   void Add_Impl(ConstString type, const MapValueType &entry,
232                 ConstString *dummy) {
233     m_format_map.Add(GetValidTypeName_Impl(type), entry);
234   }
235 
236   bool Delete_Impl(ConstString type, ConstString *dummy) {
237     return m_format_map.Delete(type);
238   }
239 
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 &regex = 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 
255   bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) {
256     return m_format_map.Get(type, entry);
257   }
258 
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
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
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 
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 &regex = pos.first;
290       if (regex.Execute(key_str)) {
291         value = pos.second;
292         return true;
293       }
294     }
295     return false;
296   }
297 
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 &regex = pos.first;
303       if (regex.GetText() == key.GetStringRef()) {
304         value = pos.second;
305         return true;
306       }
307     }
308     return false;
309   }
310 
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