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_DATAFORMATTERS_FORMATTERSCONTAINER_H 10 #define LLDB_DATAFORMATTERS_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 /// Class for matching type names. 41 class TypeMatcher { 42 RegularExpression m_type_name_regex; 43 ConstString m_type_name; 44 /// False if m_type_name_regex should be used for matching. False if this is 45 /// just matching by comparing with m_type_name string. 46 bool m_is_regex; 47 48 // if the user tries to add formatters for, say, "struct Foo" those will not 49 // match any type because of the way we strip qualifiers from typenames this 50 // method looks for the case where the user is adding a 51 // "class","struct","enum" or "union" Foo and strips the unnecessary qualifier StripTypeName(ConstString type)52 static ConstString StripTypeName(ConstString type) { 53 if (type.IsEmpty()) 54 return type; 55 56 std::string type_cstr(type.AsCString()); 57 StringLexer type_lexer(type_cstr); 58 59 type_lexer.AdvanceIf("class "); 60 type_lexer.AdvanceIf("enum "); 61 type_lexer.AdvanceIf("struct "); 62 type_lexer.AdvanceIf("union "); 63 64 while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first) 65 ; 66 67 return ConstString(type_lexer.GetUnlexed()); 68 } 69 70 public: 71 TypeMatcher() = delete; 72 /// Creates a matcher that accepts any type with exactly the given type name. TypeMatcher(ConstString type_name)73 TypeMatcher(ConstString type_name) 74 : m_type_name(type_name), m_is_regex(false) {} 75 /// Creates a matcher that accepts any type matching the given regex. TypeMatcher(RegularExpression regex)76 TypeMatcher(RegularExpression regex) 77 : m_type_name_regex(std::move(regex)), m_is_regex(true) {} 78 79 /// True iff this matches the given type name. Matches(ConstString type_name)80 bool Matches(ConstString type_name) const { 81 if (m_is_regex) 82 return m_type_name_regex.Execute(type_name.GetStringRef()); 83 return m_type_name == type_name || 84 StripTypeName(m_type_name) == StripTypeName(type_name); 85 } 86 87 /// Returns the underlying match string for this TypeMatcher. GetMatchString()88 ConstString GetMatchString() const { 89 if (m_is_regex) 90 return ConstString(m_type_name_regex.GetText()); 91 return StripTypeName(m_type_name); 92 } 93 94 /// Returns true if this TypeMatcher and the given one were most created by 95 /// the same match string. 96 /// The main purpose of this function is to find existing TypeMatcher 97 /// instances by the user input that created them. This is necessary as LLDB 98 /// allows referencing existing TypeMatchers in commands by the user input 99 /// that originally created them: 100 /// (lldb) type summary add --summary-string \"A\" -x TypeName 101 /// (lldb) type summary delete TypeName CreatedBySameMatchString(TypeMatcher other)102 bool CreatedBySameMatchString(TypeMatcher other) const { 103 return GetMatchString() == other.GetMatchString(); 104 } 105 }; 106 107 template <typename ValueType> class FormattersContainer { 108 public: 109 typedef typename std::shared_ptr<ValueType> ValueSP; 110 typedef std::vector<std::pair<TypeMatcher, ValueSP>> MapType; 111 typedef std::function<bool(const TypeMatcher &, const ValueSP &)> 112 ForEachCallback; 113 typedef typename std::shared_ptr<FormattersContainer<ValueType>> 114 SharedPointer; 115 116 friend class TypeCategoryImpl; 117 FormattersContainer(IFormatChangeListener * lst)118 FormattersContainer(IFormatChangeListener *lst) : listener(lst) {} 119 Add(TypeMatcher matcher,const ValueSP & entry)120 void Add(TypeMatcher matcher, const ValueSP &entry) { 121 if (listener) 122 entry->GetRevision() = listener->GetCurrentRevision(); 123 else 124 entry->GetRevision() = 0; 125 126 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 127 Delete(matcher); 128 m_map.emplace_back(std::move(matcher), std::move(entry)); 129 if (listener) 130 listener->Changed(); 131 } 132 Delete(TypeMatcher matcher)133 bool Delete(TypeMatcher matcher) { 134 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 135 for (auto iter = m_map.begin(); iter != m_map.end(); ++iter) 136 if (iter->first.CreatedBySameMatchString(matcher)) { 137 m_map.erase(iter); 138 if (listener) 139 listener->Changed(); 140 return true; 141 } 142 return false; 143 } 144 Get(ConstString type,ValueSP & entry)145 bool Get(ConstString type, ValueSP &entry) { 146 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 147 for (auto &formatter : llvm::reverse(m_map)) { 148 if (formatter.first.Matches(type)) { 149 entry = formatter.second; 150 return true; 151 } 152 } 153 return false; 154 } 155 GetExact(TypeMatcher matcher,ValueSP & entry)156 bool GetExact(TypeMatcher matcher, ValueSP &entry) { 157 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 158 for (const auto &pos : m_map) 159 if (pos.first.CreatedBySameMatchString(matcher)) { 160 entry = pos.second; 161 return true; 162 } 163 return false; 164 } 165 GetAtIndex(size_t index)166 ValueSP GetAtIndex(size_t index) { 167 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 168 if (index >= m_map.size()) 169 return ValueSP(); 170 return m_map[index].second; 171 } 172 GetTypeNameSpecifierAtIndex(size_t index)173 lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) { 174 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 175 if (index >= m_map.size()) 176 return lldb::TypeNameSpecifierImplSP(); 177 TypeMatcher type_matcher = m_map[index].first; 178 return std::make_shared<TypeNameSpecifierImpl>( 179 type_matcher.GetMatchString().GetStringRef(), true); 180 } 181 Clear()182 void Clear() { 183 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 184 m_map.clear(); 185 if (listener) 186 listener->Changed(); 187 } 188 ForEach(ForEachCallback callback)189 void ForEach(ForEachCallback callback) { 190 if (callback) { 191 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 192 for (const auto &pos : m_map) { 193 const TypeMatcher &type = pos.first; 194 if (!callback(type, pos.second)) 195 break; 196 } 197 } 198 } 199 GetCount()200 uint32_t GetCount() { 201 std::lock_guard<std::recursive_mutex> guard(m_map_mutex); 202 return m_map.size(); 203 } 204 AutoComplete(CompletionRequest & request)205 void AutoComplete(CompletionRequest &request) { 206 ForEach([&request](const TypeMatcher &matcher, const ValueSP &value) { 207 request.TryCompleteCurrentArg(matcher.GetMatchString().GetStringRef()); 208 return true; 209 }); 210 } 211 212 protected: 213 FormattersContainer(const FormattersContainer &) = delete; 214 const FormattersContainer &operator=(const FormattersContainer &) = delete; 215 Get(const FormattersMatchVector & candidates,ValueSP & entry)216 bool Get(const FormattersMatchVector &candidates, ValueSP &entry) { 217 for (const FormattersMatchCandidate &candidate : candidates) { 218 if (Get(candidate.GetTypeName(), entry)) { 219 if (candidate.IsMatch(entry) == false) { 220 entry.reset(); 221 continue; 222 } else { 223 return true; 224 } 225 } 226 } 227 return false; 228 } 229 230 MapType m_map; 231 std::recursive_mutex m_map_mutex; 232 IFormatChangeListener *listener; 233 }; 234 235 } // namespace lldb_private 236 237 #endif // LLDB_DATAFORMATTERS_FORMATTERSCONTAINER_H 238