1 //===-- TypeCategoryMap.cpp -----------------------------------------------===// 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 #include "lldb/DataFormatters/TypeCategoryMap.h" 10 11 #include "lldb/DataFormatters/FormatClasses.h" 12 #include "lldb/Utility/LLDBLog.h" 13 #include "lldb/Utility/Log.h" 14 15 using namespace lldb; 16 using namespace lldb_private; 17 18 TypeCategoryMap::TypeCategoryMap(IFormatChangeListener *lst) 19 : m_map_mutex(), listener(lst), m_map(), m_active_categories() { 20 ConstString default_cs("default"); 21 lldb::TypeCategoryImplSP default_sp = 22 lldb::TypeCategoryImplSP(new TypeCategoryImpl(listener, default_cs)); 23 Add(default_cs, default_sp); 24 Enable(default_cs, First); 25 } 26 27 void TypeCategoryMap::Add(KeyType name, const TypeCategoryImplSP &entry) { 28 { 29 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 30 m_map[name] = entry; 31 } 32 // Release the mutex to avoid a potential deadlock between 33 // TypeCategoryMap::m_map_mutex and 34 // FormatManager::m_language_categories_mutex which can be acquired in 35 // reverse order when calling FormatManager::Changed. 36 if (listener) 37 listener->Changed(); 38 } 39 40 bool TypeCategoryMap::Delete(KeyType name) { 41 { 42 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 43 MapIterator iter = m_map.find(name); 44 if (iter == m_map.end()) 45 return false; 46 m_map.erase(name); 47 Disable(name); 48 } 49 // Release the mutex to avoid a potential deadlock between 50 // TypeCategoryMap::m_map_mutex and 51 // FormatManager::m_language_categories_mutex which can be acquired in 52 // reverse order when calling FormatManager::Changed. 53 if (listener) 54 listener->Changed(); 55 return true; 56 } 57 58 bool TypeCategoryMap::Enable(KeyType category_name, Position pos) { 59 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 60 TypeCategoryImplSP category; 61 if (!Get(category_name, category)) 62 return false; 63 return Enable(category, pos); 64 } 65 66 bool TypeCategoryMap::Disable(KeyType category_name) { 67 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 68 TypeCategoryImplSP category; 69 if (!Get(category_name, category)) 70 return false; 71 return Disable(category); 72 } 73 74 bool TypeCategoryMap::Enable(TypeCategoryImplSP category, Position pos) { 75 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 76 if (category.get()) { 77 Position pos_w = pos; 78 if (pos == First || m_active_categories.size() == 0) 79 m_active_categories.push_front(category); 80 else if (pos == Last || pos == m_active_categories.size()) 81 m_active_categories.push_back(category); 82 else if (pos < m_active_categories.size()) { 83 ActiveCategoriesList::iterator iter = m_active_categories.begin(); 84 while (pos_w) { 85 pos_w--, iter++; 86 } 87 m_active_categories.insert(iter, category); 88 } else 89 return false; 90 category->Enable(true, pos); 91 return true; 92 } 93 return false; 94 } 95 96 bool TypeCategoryMap::Disable(TypeCategoryImplSP category) { 97 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 98 if (category.get()) { 99 m_active_categories.remove_if(delete_matching_categories(category)); 100 category->Disable(); 101 return true; 102 } 103 return false; 104 } 105 106 void TypeCategoryMap::EnableAllCategories() { 107 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 108 std::vector<TypeCategoryImplSP> sorted_categories(m_map.size(), TypeCategoryImplSP()); 109 MapType::iterator iter = m_map.begin(), end = m_map.end(); 110 for (; iter != end; ++iter) { 111 if (iter->second->IsEnabled()) 112 continue; 113 auto pos = iter->second->GetLastEnabledPosition(); 114 if (pos >= sorted_categories.size()) { 115 auto iter = std::find_if( 116 sorted_categories.begin(), sorted_categories.end(), 117 [](const TypeCategoryImplSP &sp) -> bool { return sp.get() == nullptr; }); 118 pos = std::distance(sorted_categories.begin(), iter); 119 } 120 sorted_categories.at(pos) = iter->second; 121 } 122 decltype(sorted_categories)::iterator viter = sorted_categories.begin(), 123 vend = sorted_categories.end(); 124 for (; viter != vend; viter++) 125 if (*viter) 126 Enable(*viter, Last); 127 } 128 129 void TypeCategoryMap::DisableAllCategories() { 130 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 131 for (Position p = First; !m_active_categories.empty(); p++) { 132 m_active_categories.front()->SetEnabledPosition(p); 133 Disable(m_active_categories.front()); 134 } 135 } 136 137 void TypeCategoryMap::Clear() { 138 { 139 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 140 m_map.clear(); 141 m_active_categories.clear(); 142 } 143 // Release the mutex to avoid a potential deadlock between 144 // TypeCategoryMap::m_map_mutex and 145 // FormatManager::m_language_categories_mutex which can be acquired in 146 // reverse order when calling FormatManager::Changed. 147 if (listener) 148 listener->Changed(); 149 } 150 151 bool TypeCategoryMap::Get(KeyType name, TypeCategoryImplSP &entry) { 152 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 153 MapIterator iter = m_map.find(name); 154 if (iter == m_map.end()) 155 return false; 156 entry = iter->second; 157 return true; 158 } 159 160 bool TypeCategoryMap::AnyMatches( 161 const FormattersMatchCandidate &candidate_type, 162 TypeCategoryImpl::FormatCategoryItems items, bool only_enabled, 163 const char **matching_category, 164 TypeCategoryImpl::FormatCategoryItems *matching_type) { 165 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 166 167 MapIterator pos, end = m_map.end(); 168 for (pos = m_map.begin(); pos != end; pos++) { 169 if (pos->second->AnyMatches(candidate_type, items, only_enabled, 170 matching_category, matching_type)) 171 return true; 172 } 173 return false; 174 } 175 176 template <typename ImplSP> 177 void TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) { 178 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 179 180 ActiveCategoriesIterator begin, end = m_active_categories.end(); 181 182 Log *log = GetLog(LLDBLog::DataFormatters); 183 184 if (log) { 185 for (auto match : match_data.GetMatchesVector()) { 186 LLDB_LOGF( 187 log, 188 "[%s] candidate match = %s %s %s %s", 189 __FUNCTION__, 190 match.GetTypeName().GetCString(), 191 match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers", 192 match.DidStripReference() ? "strip-reference" : "no-strip-reference", 193 match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef"); 194 } 195 } 196 197 for (begin = m_active_categories.begin(); begin != end; begin++) { 198 lldb::TypeCategoryImplSP category_sp = *begin; 199 ImplSP current_format; 200 LLDB_LOGF(log, "[%s] Trying to use category %s", __FUNCTION__, 201 category_sp->GetName()); 202 if (!category_sp->Get( 203 match_data.GetValueObject().GetObjectRuntimeLanguage(), 204 match_data.GetMatchesVector(), current_format)) 205 continue; 206 207 retval = std::move(current_format); 208 return; 209 } 210 LLDB_LOGF(log, "[%s] nothing found - returning empty SP", __FUNCTION__); 211 } 212 213 /// Explicit instantiations for the three types. 214 /// \{ 215 template void 216 TypeCategoryMap::Get<lldb::TypeFormatImplSP>(FormattersMatchData &match_data, 217 lldb::TypeFormatImplSP &retval); 218 template void 219 TypeCategoryMap::Get<lldb::TypeSummaryImplSP>(FormattersMatchData &match_data, 220 lldb::TypeSummaryImplSP &retval); 221 template void TypeCategoryMap::Get<lldb::SyntheticChildrenSP>( 222 FormattersMatchData &match_data, lldb::SyntheticChildrenSP &retval); 223 /// \} 224 225 void TypeCategoryMap::ForEach(ForEachCallback callback) { 226 if (callback) { 227 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 228 229 // loop through enabled categories in respective order 230 { 231 ActiveCategoriesIterator begin, end = m_active_categories.end(); 232 for (begin = m_active_categories.begin(); begin != end; begin++) { 233 lldb::TypeCategoryImplSP category = *begin; 234 if (!callback(category)) 235 break; 236 } 237 } 238 239 // loop through disabled categories in just any order 240 { 241 MapIterator pos, end = m_map.end(); 242 for (pos = m_map.begin(); pos != end; pos++) { 243 if (pos->second->IsEnabled()) 244 continue; 245 if (!callback(pos->second)) 246 break; 247 } 248 } 249 } 250 } 251 252 TypeCategoryImplSP TypeCategoryMap::GetAtIndex(uint32_t index) { 253 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 254 255 if (index < m_map.size()) { 256 MapIterator pos, end = m_map.end(); 257 for (pos = m_map.begin(); pos != end; pos++) { 258 if (index == 0) 259 return pos->second; 260 index--; 261 } 262 } 263 264 return TypeCategoryImplSP(); 265 } 266