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 ®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 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 ®ex = 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 ®ex = 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