FormattersContainer.h revision 269024
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// C Includes 14// C++ Includes 15 16// Other libraries and framework includes 17#include "clang/AST/DeclCXX.h" 18#include "clang/AST/Type.h" 19#include "clang/AST/DeclObjC.h" 20 21// Project includes 22#include "lldb/lldb-public.h" 23 24#include "lldb/Core/Log.h" 25#include "lldb/Core/RegularExpression.h" 26#include "lldb/Core/ValueObject.h" 27 28#include "lldb/DataFormatters/FormatClasses.h" 29#include "lldb/DataFormatters/TypeFormat.h" 30#include "lldb/DataFormatters/TypeSummary.h" 31#include "lldb/DataFormatters/TypeSynthetic.h" 32 33#include "lldb/Symbol/ClangASTContext.h" 34#include "lldb/Symbol/ClangASTType.h" 35 36#include "lldb/Target/ObjCLanguageRuntime.h" 37#include "lldb/Target/Process.h" 38#include "lldb/Target/StackFrame.h" 39#include "lldb/Target/TargetList.h" 40 41namespace lldb_private { 42 43// this file (and its. cpp) contain the low-level implementation of LLDB Data Visualization 44// class DataVisualization is the high-level front-end of this feature 45// clients should refer to that class as the entry-point into the data formatters 46// unless they have a good reason to bypass it and prefer to use this file's objects directly 47class IFormatChangeListener 48{ 49public: 50 virtual void 51 Changed () = 0; 52 53 virtual 54 ~IFormatChangeListener () {} 55 56 virtual uint32_t 57 GetCurrentRevision () = 0; 58 59}; 60 61static inline bool 62IsWhitespace (char c) 63{ 64 return ( (c == ' ') || (c == '\t') || (c == '\v') || (c == '\f') ); 65} 66 67static inline bool 68HasPrefix (const char* str1, const char* str2) 69{ 70 return ( ::strstr(str1, str2) == str1 ); 71} 72 73// if the user tries to add formatters for, say, "struct Foo" 74// those will not match any type because of the way we strip qualifiers from typenames 75// this method looks for the case where the user is adding a "class","struct","enum" or "union" Foo 76// and strips the unnecessary qualifier 77static inline ConstString 78GetValidTypeName_Impl (const ConstString& type) 79{ 80 int strip_len = 0; 81 82 if ((bool)type == false) 83 return type; 84 85 const char* type_cstr = type.AsCString(); 86 87 if ( HasPrefix(type_cstr, "class ") ) 88 strip_len = 6; 89 else if ( HasPrefix(type_cstr, "enum ") ) 90 strip_len = 5; 91 else if ( HasPrefix(type_cstr, "struct ") ) 92 strip_len = 7; 93 else if ( HasPrefix(type_cstr, "union ") ) 94 strip_len = 6; 95 96 if (strip_len == 0) 97 return type; 98 99 type_cstr += strip_len; 100 while (IsWhitespace(*type_cstr) && ++type_cstr) 101 ; 102 103 return ConstString(type_cstr); 104} 105 106template<typename KeyType, typename ValueType> 107class FormattersContainer; 108 109template<typename KeyType, typename ValueType> 110class FormatMap 111{ 112public: 113 114 typedef typename ValueType::SharedPointer ValueSP; 115 typedef std::map<KeyType, ValueSP> MapType; 116 typedef typename MapType::iterator MapIterator; 117 typedef bool(*CallbackType)(void*, KeyType, const ValueSP&); 118 119 FormatMap(IFormatChangeListener* lst) : 120 m_map(), 121 m_map_mutex(Mutex::eMutexTypeRecursive), 122 listener(lst) 123 { 124 } 125 126 void 127 Add(KeyType name, 128 const ValueSP& entry) 129 { 130 if (listener) 131 entry->GetRevision() = listener->GetCurrentRevision(); 132 else 133 entry->GetRevision() = 0; 134 135 Mutex::Locker locker(m_map_mutex); 136 m_map[name] = entry; 137 if (listener) 138 listener->Changed(); 139 } 140 141 bool 142 Delete (KeyType name) 143 { 144 Mutex::Locker locker(m_map_mutex); 145 MapIterator iter = m_map.find(name); 146 if (iter == m_map.end()) 147 return false; 148 m_map.erase(name); 149 if (listener) 150 listener->Changed(); 151 return true; 152 } 153 154 void 155 Clear () 156 { 157 Mutex::Locker locker(m_map_mutex); 158 m_map.clear(); 159 if (listener) 160 listener->Changed(); 161 } 162 163 bool 164 Get(KeyType name, 165 ValueSP& entry) 166 { 167 Mutex::Locker locker(m_map_mutex); 168 MapIterator iter = m_map.find(name); 169 if (iter == m_map.end()) 170 return false; 171 entry = iter->second; 172 return true; 173 } 174 175 void 176 LoopThrough (CallbackType callback, void* param) 177 { 178 if (callback) 179 { 180 Mutex::Locker locker(m_map_mutex); 181 MapIterator pos, end = m_map.end(); 182 for (pos = m_map.begin(); pos != end; pos++) 183 { 184 KeyType type = pos->first; 185 if (!callback(param, type, pos->second)) 186 break; 187 } 188 } 189 } 190 191 uint32_t 192 GetCount () 193 { 194 return m_map.size(); 195 } 196 197 ValueSP 198 GetValueAtIndex (size_t index) 199 { 200 Mutex::Locker locker(m_map_mutex); 201 MapIterator iter = m_map.begin(); 202 MapIterator end = m_map.end(); 203 while (index > 0) 204 { 205 iter++; 206 index--; 207 if (end == iter) 208 return ValueSP(); 209 } 210 return iter->second; 211 } 212 213 KeyType 214 GetKeyAtIndex (size_t index) 215 { 216 Mutex::Locker locker(m_map_mutex); 217 MapIterator iter = m_map.begin(); 218 MapIterator end = m_map.end(); 219 while (index > 0) 220 { 221 iter++; 222 index--; 223 if (end == iter) 224 return KeyType(); 225 } 226 return iter->first; 227 } 228 229protected: 230 MapType m_map; 231 Mutex m_map_mutex; 232 IFormatChangeListener* listener; 233 234 MapType& 235 map () 236 { 237 return m_map; 238 } 239 240 Mutex& 241 mutex () 242 { 243 return m_map_mutex; 244 } 245 246 friend class FormattersContainer<KeyType, ValueType>; 247 friend class FormatManager; 248 249}; 250 251template<typename KeyType, typename ValueType> 252class FormattersContainer 253{ 254protected: 255 typedef FormatMap<KeyType,ValueType> BackEndType; 256 257public: 258 typedef typename BackEndType::MapType MapType; 259 typedef typename MapType::iterator MapIterator; 260 typedef typename MapType::key_type MapKeyType; 261 typedef typename MapType::mapped_type MapValueType; 262 typedef typename BackEndType::CallbackType CallbackType; 263 typedef typename std::shared_ptr<FormattersContainer<KeyType, ValueType> > SharedPointer; 264 265 friend class TypeCategoryImpl; 266 267 FormattersContainer(std::string name, 268 IFormatChangeListener* lst) : 269 m_format_map(lst), 270 m_name(name), 271 m_id_cs(ConstString("id")) 272 { 273 } 274 275 void 276 Add (const MapKeyType &type, const MapValueType& entry) 277 { 278 Add_Impl(type, entry, (KeyType*)NULL); 279 } 280 281 bool 282 Delete (ConstString type) 283 { 284 return Delete_Impl(type, (KeyType*)NULL); 285 } 286 287 bool 288 Get(ValueObject& valobj, 289 MapValueType& entry, 290 lldb::DynamicValueType use_dynamic, 291 uint32_t* why = NULL) 292 { 293 uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice; 294 ClangASTType ast_type(valobj.GetClangType()); 295 bool ret = Get(valobj, ast_type, entry, use_dynamic, value); 296 if (ret) 297 entry = MapValueType(entry); 298 else 299 entry = MapValueType(); 300 if (why) 301 *why = value; 302 return ret; 303 } 304 305 bool 306 Get (ConstString type, MapValueType& entry) 307 { 308 return Get_Impl(type, entry, (KeyType*)NULL); 309 } 310 311 bool 312 GetExact (ConstString type, MapValueType& entry) 313 { 314 return GetExact_Impl(type, entry, (KeyType*)NULL); 315 } 316 317 MapValueType 318 GetAtIndex (size_t index) 319 { 320 return m_format_map.GetValueAtIndex(index); 321 } 322 323 lldb::TypeNameSpecifierImplSP 324 GetTypeNameSpecifierAtIndex (size_t index) 325 { 326 return GetTypeNameSpecifierAtIndex_Impl(index, (KeyType*)NULL); 327 } 328 329 void 330 Clear () 331 { 332 m_format_map.Clear(); 333 } 334 335 void 336 LoopThrough (CallbackType callback, void* param) 337 { 338 m_format_map.LoopThrough(callback,param); 339 } 340 341 uint32_t 342 GetCount () 343 { 344 return m_format_map.GetCount(); 345 } 346 347protected: 348 349 BackEndType m_format_map; 350 351 std::string m_name; 352 353 DISALLOW_COPY_AND_ASSIGN(FormattersContainer); 354 355 ConstString m_id_cs; 356 357 void 358 Add_Impl (const MapKeyType &type, const MapValueType& entry, lldb::RegularExpressionSP *dummy) 359 { 360 m_format_map.Add(type,entry); 361 } 362 363 void Add_Impl (const ConstString &type, const MapValueType& entry, ConstString *dummy) 364 { 365 m_format_map.Add(GetValidTypeName_Impl(type), entry); 366 } 367 368 bool 369 Delete_Impl (ConstString type, ConstString *dummy) 370 { 371 return m_format_map.Delete(type); 372 } 373 374 bool 375 Delete_Impl (ConstString type, lldb::RegularExpressionSP *dummy) 376 { 377 Mutex& x_mutex = m_format_map.mutex(); 378 lldb_private::Mutex::Locker locker(x_mutex); 379 MapIterator pos, end = m_format_map.map().end(); 380 for (pos = m_format_map.map().begin(); pos != end; pos++) 381 { 382 lldb::RegularExpressionSP regex = pos->first; 383 if ( ::strcmp(type.AsCString(),regex->GetText()) == 0) 384 { 385 m_format_map.map().erase(pos); 386 if (m_format_map.listener) 387 m_format_map.listener->Changed(); 388 return true; 389 } 390 } 391 return false; 392 } 393 394 bool 395 Get_Impl (ConstString type, MapValueType& entry, ConstString *dummy) 396 { 397 return m_format_map.Get(type, entry); 398 } 399 400 bool 401 GetExact_Impl (ConstString type, MapValueType& entry, ConstString *dummy) 402 { 403 return Get_Impl(type,entry, (KeyType*)0); 404 } 405 406 lldb::TypeNameSpecifierImplSP 407 GetTypeNameSpecifierAtIndex_Impl (size_t index, ConstString *dummy) 408 { 409 ConstString key = m_format_map.GetKeyAtIndex(index); 410 if (key) 411 return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(key.AsCString(), 412 false)); 413 else 414 return lldb::TypeNameSpecifierImplSP(); 415 } 416 417 lldb::TypeNameSpecifierImplSP 418 GetTypeNameSpecifierAtIndex_Impl (size_t index, lldb::RegularExpressionSP *dummy) 419 { 420 lldb::RegularExpressionSP regex = m_format_map.GetKeyAtIndex(index); 421 if (regex.get() == NULL) 422 return lldb::TypeNameSpecifierImplSP(); 423 return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(regex->GetText(), 424 true)); 425 } 426 427 bool 428 Get_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy) 429 { 430 const char* key_cstr = key.AsCString(); 431 if (!key_cstr) 432 return false; 433 Mutex& x_mutex = m_format_map.mutex(); 434 lldb_private::Mutex::Locker locker(x_mutex); 435 MapIterator pos, end = m_format_map.map().end(); 436 for (pos = m_format_map.map().begin(); pos != end; pos++) 437 { 438 lldb::RegularExpressionSP regex = pos->first; 439 if (regex->Execute(key_cstr)) 440 { 441 value = pos->second; 442 return true; 443 } 444 } 445 return false; 446 } 447 448 bool 449 GetExact_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy) 450 { 451 Mutex& x_mutex = m_format_map.mutex(); 452 lldb_private::Mutex::Locker locker(x_mutex); 453 MapIterator pos, end = m_format_map.map().end(); 454 for (pos = m_format_map.map().begin(); pos != end; pos++) 455 { 456 lldb::RegularExpressionSP regex = pos->first; 457 if (strcmp(regex->GetText(),key.AsCString()) == 0) 458 { 459 value = pos->second; 460 return true; 461 } 462 } 463 return false; 464 } 465 466 bool 467 Get (const FormattersMatchVector& candidates, 468 MapValueType& entry, 469 uint32_t *reason) 470 { 471 for (const FormattersMatchCandidate& candidate : candidates) 472 { 473 // FIXME: could we do the IsMatch() check first? 474 if (Get(candidate.GetTypeName(),entry)) 475 { 476 if (candidate.IsMatch(entry) == false) 477 { 478 entry.reset(); 479 continue; 480 } 481 else 482 { 483 if(reason) 484 *reason = candidate.GetReason(); 485 return true; 486 } 487 } 488 } 489 return false; 490 } 491}; 492 493} // namespace lldb_private 494 495#endif // lldb_FormattersContainer_h_ 496