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