diff options
Diffstat (limited to 'include/lldb/DataFormatters/FormattersContainer.h')
-rw-r--r-- | include/lldb/DataFormatters/FormattersContainer.h | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/include/lldb/DataFormatters/FormattersContainer.h b/include/lldb/DataFormatters/FormattersContainer.h new file mode 100644 index 000000000000..de838d1ab9c1 --- /dev/null +++ b/include/lldb/DataFormatters/FormattersContainer.h @@ -0,0 +1,495 @@ +//===-- 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<typename KeyType, typename ValueType> +class FormattersContainer; + +template<typename KeyType, typename ValueType> +class FormatMap +{ +public: + + typedef typename ValueType::SharedPointer ValueSP; + typedef std::map<KeyType, ValueSP> 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<KeyType, ValueType>; + friend class FormatManager; + +}; + +template<typename KeyType, typename ValueType> +class FormattersContainer +{ +protected: + typedef FormatMap<KeyType,ValueType> 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<FormattersContainer<KeyType, ValueType> > 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_ |