//===-- FormattersContainer.h ----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef lldb_FormattersContainer_h_ #define lldb_FormattersContainer_h_ // C Includes // C++ Includes // Other libraries and framework includes #include "clang/AST/DeclCXX.h" #include "clang/AST/Type.h" #include "clang/AST/DeclObjC.h" // Project includes #include "lldb/lldb-public.h" #include "lldb/Core/Log.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/FormatClasses.h" #include "lldb/DataFormatters/TypeFormat.h" #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/DataFormatters/TypeSynthetic.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ClangASTType.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/TargetList.h" namespace lldb_private { // this file (and its. cpp) contain the low-level implementation of LLDB Data Visualization // class DataVisualization is the high-level front-end of this feature // clients should refer to that class as the entry-point into the data formatters // unless they have a good reason to bypass it and prefer to use this file's objects directly class IFormatChangeListener { public: virtual void Changed () = 0; virtual ~IFormatChangeListener () {} virtual uint32_t GetCurrentRevision () = 0; }; static inline bool IsWhitespace (char c) { return ( (c == ' ') || (c == '\t') || (c == '\v') || (c == '\f') ); } static inline bool HasPrefix (const char* str1, const char* str2) { return ( ::strstr(str1, str2) == str1 ); } // if the user tries to add formatters for, say, "struct Foo" // those will not match any type because of the way we strip qualifiers from typenames // this method looks for the case where the user is adding a "class","struct","enum" or "union" Foo // and strips the unnecessary qualifier static inline ConstString GetValidTypeName_Impl (const ConstString& type) { int strip_len = 0; if ((bool)type == false) return type; const char* type_cstr = type.AsCString(); if ( HasPrefix(type_cstr, "class ") ) strip_len = 6; else if ( HasPrefix(type_cstr, "enum ") ) strip_len = 5; else if ( HasPrefix(type_cstr, "struct ") ) strip_len = 7; else if ( HasPrefix(type_cstr, "union ") ) strip_len = 6; if (strip_len == 0) return type; type_cstr += strip_len; while (IsWhitespace(*type_cstr) && ++type_cstr) ; return ConstString(type_cstr); } template class FormattersContainer; template class FormatMap { public: typedef typename ValueType::SharedPointer ValueSP; typedef std::map MapType; typedef typename MapType::iterator MapIterator; typedef bool(*CallbackType)(void*, KeyType, const ValueSP&); FormatMap(IFormatChangeListener* lst) : m_map(), m_map_mutex(Mutex::eMutexTypeRecursive), listener(lst) { } void Add(KeyType name, const ValueSP& entry) { if (listener) entry->GetRevision() = listener->GetCurrentRevision(); else entry->GetRevision() = 0; Mutex::Locker locker(m_map_mutex); m_map[name] = entry; if (listener) listener->Changed(); } bool Delete (KeyType name) { Mutex::Locker locker(m_map_mutex); MapIterator iter = m_map.find(name); if (iter == m_map.end()) return false; m_map.erase(name); if (listener) listener->Changed(); return true; } void Clear () { Mutex::Locker locker(m_map_mutex); m_map.clear(); if (listener) listener->Changed(); } bool Get(KeyType name, ValueSP& entry) { Mutex::Locker locker(m_map_mutex); MapIterator iter = m_map.find(name); if (iter == m_map.end()) return false; entry = iter->second; return true; } void LoopThrough (CallbackType callback, void* param) { if (callback) { Mutex::Locker locker(m_map_mutex); MapIterator pos, end = m_map.end(); for (pos = m_map.begin(); pos != end; pos++) { KeyType type = pos->first; if (!callback(param, type, pos->second)) break; } } } uint32_t GetCount () { return m_map.size(); } ValueSP GetValueAtIndex (size_t index) { Mutex::Locker locker(m_map_mutex); MapIterator iter = m_map.begin(); MapIterator end = m_map.end(); while (index > 0) { iter++; index--; if (end == iter) return ValueSP(); } return iter->second; } KeyType GetKeyAtIndex (size_t index) { Mutex::Locker locker(m_map_mutex); MapIterator iter = m_map.begin(); MapIterator end = m_map.end(); while (index > 0) { iter++; index--; if (end == iter) return KeyType(); } return iter->first; } protected: MapType m_map; Mutex m_map_mutex; IFormatChangeListener* listener; MapType& map () { return m_map; } Mutex& mutex () { return m_map_mutex; } friend class FormattersContainer; friend class FormatManager; }; template class FormattersContainer { protected: typedef FormatMap BackEndType; public: typedef typename BackEndType::MapType MapType; typedef typename MapType::iterator MapIterator; typedef typename MapType::key_type MapKeyType; typedef typename MapType::mapped_type MapValueType; typedef typename BackEndType::CallbackType CallbackType; typedef typename std::shared_ptr > SharedPointer; friend class TypeCategoryImpl; FormattersContainer(std::string name, IFormatChangeListener* lst) : m_format_map(lst), m_name(name), m_id_cs(ConstString("id")) { } void Add (const MapKeyType &type, const MapValueType& entry) { Add_Impl(type, entry, (KeyType*)NULL); } bool Delete (ConstString type) { return Delete_Impl(type, (KeyType*)NULL); } bool Get(ValueObject& valobj, MapValueType& entry, lldb::DynamicValueType use_dynamic, uint32_t* why = NULL) { uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice; ClangASTType ast_type(valobj.GetClangType()); bool ret = Get(valobj, ast_type, entry, use_dynamic, value); if (ret) entry = MapValueType(entry); else entry = MapValueType(); if (why) *why = value; return ret; } bool Get (ConstString type, MapValueType& entry) { return Get_Impl(type, entry, (KeyType*)NULL); } bool GetExact (ConstString type, MapValueType& entry) { return GetExact_Impl(type, entry, (KeyType*)NULL); } MapValueType GetAtIndex (size_t index) { return m_format_map.GetValueAtIndex(index); } lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex (size_t index) { return GetTypeNameSpecifierAtIndex_Impl(index, (KeyType*)NULL); } void Clear () { m_format_map.Clear(); } void LoopThrough (CallbackType callback, void* param) { m_format_map.LoopThrough(callback,param); } uint32_t GetCount () { return m_format_map.GetCount(); } protected: BackEndType m_format_map; std::string m_name; DISALLOW_COPY_AND_ASSIGN(FormattersContainer); ConstString m_id_cs; void Add_Impl (const MapKeyType &type, const MapValueType& entry, lldb::RegularExpressionSP *dummy) { m_format_map.Add(type,entry); } void Add_Impl (const ConstString &type, const MapValueType& entry, ConstString *dummy) { m_format_map.Add(GetValidTypeName_Impl(type), entry); } bool Delete_Impl (ConstString type, ConstString *dummy) { return m_format_map.Delete(type); } bool Delete_Impl (ConstString type, lldb::RegularExpressionSP *dummy) { Mutex& x_mutex = m_format_map.mutex(); lldb_private::Mutex::Locker locker(x_mutex); MapIterator pos, end = m_format_map.map().end(); for (pos = m_format_map.map().begin(); pos != end; pos++) { lldb::RegularExpressionSP regex = pos->first; if ( ::strcmp(type.AsCString(),regex->GetText()) == 0) { m_format_map.map().erase(pos); if (m_format_map.listener) m_format_map.listener->Changed(); return true; } } return false; } bool Get_Impl (ConstString type, MapValueType& entry, ConstString *dummy) { return m_format_map.Get(type, entry); } bool GetExact_Impl (ConstString type, MapValueType& entry, ConstString *dummy) { return Get_Impl(type,entry, (KeyType*)0); } lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex_Impl (size_t index, ConstString *dummy) { ConstString key = m_format_map.GetKeyAtIndex(index); if (key) return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(key.AsCString(), false)); else return lldb::TypeNameSpecifierImplSP(); } lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex_Impl (size_t index, lldb::RegularExpressionSP *dummy) { lldb::RegularExpressionSP regex = m_format_map.GetKeyAtIndex(index); if (regex.get() == NULL) return lldb::TypeNameSpecifierImplSP(); return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(regex->GetText(), true)); } bool Get_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy) { const char* key_cstr = key.AsCString(); if (!key_cstr) return false; Mutex& x_mutex = m_format_map.mutex(); lldb_private::Mutex::Locker locker(x_mutex); MapIterator pos, end = m_format_map.map().end(); for (pos = m_format_map.map().begin(); pos != end; pos++) { lldb::RegularExpressionSP regex = pos->first; if (regex->Execute(key_cstr)) { value = pos->second; return true; } } return false; } bool GetExact_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy) { Mutex& x_mutex = m_format_map.mutex(); lldb_private::Mutex::Locker locker(x_mutex); MapIterator pos, end = m_format_map.map().end(); for (pos = m_format_map.map().begin(); pos != end; pos++) { lldb::RegularExpressionSP regex = pos->first; if (strcmp(regex->GetText(),key.AsCString()) == 0) { value = pos->second; return true; } } return false; } bool Get (const FormattersMatchVector& candidates, MapValueType& entry, uint32_t *reason) { for (const FormattersMatchCandidate& candidate : candidates) { // FIXME: could we do the IsMatch() check first? if (Get(candidate.GetTypeName(),entry)) { if (candidate.IsMatch(entry) == false) { entry.reset(); continue; } else { if(reason) *reason = candidate.GetReason(); return true; } } } return false; } }; } // namespace lldb_private #endif // lldb_FormattersContainer_h_