File indexing completed on 2026-05-10 08:42:46
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef LLDB_DATAFORMATTERS_FORMATTERSCONTAINER_H
0010 #define LLDB_DATAFORMATTERS_FORMATTERSCONTAINER_H
0011
0012 #include <functional>
0013 #include <map>
0014 #include <memory>
0015 #include <mutex>
0016 #include <string>
0017
0018 #include "lldb/lldb-public.h"
0019
0020 #include "lldb/DataFormatters/FormatClasses.h"
0021 #include "lldb/DataFormatters/TypeFormat.h"
0022 #include "lldb/DataFormatters/TypeSummary.h"
0023 #include "lldb/DataFormatters/TypeSynthetic.h"
0024 #include "lldb/Symbol/CompilerType.h"
0025 #include "lldb/Utility/RegularExpression.h"
0026 #include "lldb/Utility/StringLexer.h"
0027 #include "lldb/ValueObject/ValueObject.h"
0028
0029 namespace lldb_private {
0030
0031 class IFormatChangeListener {
0032 public:
0033 virtual ~IFormatChangeListener() = default;
0034
0035 virtual void Changed() = 0;
0036
0037 virtual uint32_t GetCurrentRevision() = 0;
0038 };
0039
0040
0041 class TypeMatcher {
0042
0043
0044 ConstString m_name;
0045 RegularExpression m_type_name_regex;
0046
0047
0048
0049
0050
0051
0052 lldb::FormatterMatchType m_match_type;
0053
0054
0055
0056
0057
0058 static ConstString StripTypeName(ConstString type) {
0059 if (type.IsEmpty())
0060 return type;
0061
0062 std::string type_cstr(type.AsCString());
0063 StringLexer type_lexer(type_cstr);
0064
0065 type_lexer.AdvanceIf("class ");
0066 type_lexer.AdvanceIf("enum ");
0067 type_lexer.AdvanceIf("struct ");
0068 type_lexer.AdvanceIf("union ");
0069
0070 while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first)
0071 ;
0072
0073 return ConstString(type_lexer.GetUnlexed());
0074 }
0075
0076 public:
0077 TypeMatcher() = delete;
0078
0079 TypeMatcher(ConstString type_name)
0080 : m_name(type_name), m_match_type(lldb::eFormatterMatchExact) {}
0081
0082 TypeMatcher(RegularExpression regex)
0083 : m_type_name_regex(std::move(regex)),
0084 m_match_type(lldb::eFormatterMatchRegex) {}
0085
0086
0087 TypeMatcher(lldb::TypeNameSpecifierImplSP type_specifier)
0088 : m_name(type_specifier->GetName()),
0089 m_match_type(type_specifier->GetMatchType()) {
0090 if (m_match_type == lldb::eFormatterMatchRegex)
0091 m_type_name_regex = RegularExpression(type_specifier->GetName());
0092 }
0093
0094
0095 bool Matches(FormattersMatchCandidate candidate_type) const {
0096 ConstString type_name = candidate_type.GetTypeName();
0097 switch (m_match_type) {
0098 case lldb::eFormatterMatchExact:
0099 return m_name == type_name ||
0100 StripTypeName(m_name) == StripTypeName(type_name);
0101 case lldb::eFormatterMatchRegex:
0102 return m_type_name_regex.Execute(type_name.GetStringRef());
0103 case lldb::eFormatterMatchCallback:
0104
0105
0106
0107
0108
0109 if (candidate_type.GetScriptInterpreter())
0110 return candidate_type.GetScriptInterpreter()->FormatterCallbackFunction(
0111 m_name.AsCString(),
0112 std::make_shared<TypeImpl>(candidate_type.GetType()));
0113 }
0114 return false;
0115 }
0116
0117 lldb::FormatterMatchType GetMatchType() const { return m_match_type; }
0118
0119
0120 ConstString GetMatchString() const {
0121 if (m_match_type == lldb::eFormatterMatchExact)
0122 return StripTypeName(m_name);
0123 if (m_match_type == lldb::eFormatterMatchRegex)
0124 return ConstString(m_type_name_regex.GetText());
0125 return m_name;
0126 }
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136 bool CreatedBySameMatchString(TypeMatcher other) const {
0137 return GetMatchString() == other.GetMatchString();
0138 }
0139 };
0140
0141 template <typename ValueType> class FormattersContainer {
0142 public:
0143 typedef typename std::shared_ptr<ValueType> ValueSP;
0144 typedef std::vector<std::pair<TypeMatcher, ValueSP>> MapType;
0145 typedef std::function<bool(const TypeMatcher &, const ValueSP &)>
0146 ForEachCallback;
0147 typedef typename std::shared_ptr<FormattersContainer<ValueType>>
0148 SharedPointer;
0149
0150 friend class TypeCategoryImpl;
0151
0152 FormattersContainer(IFormatChangeListener *lst) : listener(lst) {}
0153
0154 void Add(TypeMatcher matcher, const ValueSP &entry) {
0155 if (listener)
0156 entry->GetRevision() = listener->GetCurrentRevision();
0157 else
0158 entry->GetRevision() = 0;
0159
0160 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0161 Delete(matcher);
0162 m_map.emplace_back(std::move(matcher), std::move(entry));
0163 if (listener)
0164 listener->Changed();
0165 }
0166
0167 bool Delete(TypeMatcher matcher) {
0168 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0169 for (auto iter = m_map.begin(); iter != m_map.end(); ++iter)
0170 if (iter->first.CreatedBySameMatchString(matcher)) {
0171 m_map.erase(iter);
0172 if (listener)
0173 listener->Changed();
0174 return true;
0175 }
0176 return false;
0177 }
0178
0179
0180 bool Get(FormattersMatchCandidate candidate, ValueSP &entry) {
0181 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0182 for (auto &formatter : llvm::reverse(m_map)) {
0183 if (formatter.first.Matches(candidate)) {
0184 entry = formatter.second;
0185 return true;
0186 }
0187 }
0188 return false;
0189 }
0190
0191
0192
0193 bool Get(const FormattersMatchVector &candidates, ValueSP &entry) {
0194 for (const FormattersMatchCandidate &candidate : candidates) {
0195 if (Get(candidate, entry)) {
0196 if (candidate.IsMatch(entry) == false) {
0197 entry.reset();
0198 continue;
0199 } else {
0200 return true;
0201 }
0202 }
0203 }
0204 return false;
0205 }
0206
0207 bool GetExact(TypeMatcher matcher, ValueSP &entry) {
0208 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0209 for (const auto &pos : m_map)
0210 if (pos.first.CreatedBySameMatchString(matcher)) {
0211 entry = pos.second;
0212 return true;
0213 }
0214 return false;
0215 }
0216
0217 ValueSP GetAtIndex(size_t index) {
0218 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0219 if (index >= m_map.size())
0220 return ValueSP();
0221 return m_map[index].second;
0222 }
0223
0224 lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) {
0225 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0226 if (index >= m_map.size())
0227 return lldb::TypeNameSpecifierImplSP();
0228 TypeMatcher type_matcher = m_map[index].first;
0229 return std::make_shared<TypeNameSpecifierImpl>(
0230 type_matcher.GetMatchString().GetStringRef(),
0231 type_matcher.GetMatchType());
0232 }
0233
0234 void Clear() {
0235 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0236 m_map.clear();
0237 if (listener)
0238 listener->Changed();
0239 }
0240
0241 void ForEach(ForEachCallback callback) {
0242 if (callback) {
0243 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0244 for (const auto &pos : m_map) {
0245 const TypeMatcher &type = pos.first;
0246 if (!callback(type, pos.second))
0247 break;
0248 }
0249 }
0250 }
0251
0252 uint32_t GetCount() {
0253 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
0254 return m_map.size();
0255 }
0256
0257 void AutoComplete(CompletionRequest &request) {
0258 ForEach([&request](const TypeMatcher &matcher, const ValueSP &value) {
0259 request.TryCompleteCurrentArg(matcher.GetMatchString().GetStringRef());
0260 return true;
0261 });
0262 }
0263
0264 protected:
0265 FormattersContainer(const FormattersContainer &) = delete;
0266 const FormattersContainer &operator=(const FormattersContainer &) = delete;
0267
0268 MapType m_map;
0269 std::recursive_mutex m_map_mutex;
0270 IFormatChangeListener *listener;
0271 };
0272
0273 }
0274
0275 #endif