LLDB mainline
FormattersContainer.h
Go to the documentation of this file.
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
27
28namespace lldb_private {
29
31public:
32 virtual ~IFormatChangeListener() = default;
33
34 virtual void Changed() = 0;
35
36 virtual uint32_t GetCurrentRevision() = 0;
37};
38
39/// Class for matching type names.
41 /// Type name for exact match, or name of the python callback if m_match_type
42 /// is `eFormatterMatchCallback`.
45 /// Indicates what kind of matching strategy should be used:
46 /// - eFormatterMatchExact: match the exact type name in m_name.
47 /// - eFormatterMatchRegex: match using the RegularExpression object
48 /// `m_type_name_regex` instead.
49 /// - eFormatterMatchCallback: run the function in m_name to decide if a type
50 /// matches or not.
52
53 // if the user tries to add formatters for, say, "struct Foo" those will not
54 // match any type because of the way we strip qualifiers from typenames this
55 // method looks for the case where the user is adding a
56 // "class","struct","enum" or "union" Foo and strips the unnecessary qualifier
58 if (type.IsEmpty())
59 return type;
60
61 llvm::StringRef type_lexer(type.AsCString());
62
63 type_lexer.consume_front("class ");
64 type_lexer.consume_front("enum ");
65 type_lexer.consume_front("struct ");
66 type_lexer.consume_front("union ");
67 type_lexer = type_lexer.ltrim();
68
69 return ConstString(type_lexer);
70 }
71
72public:
73 TypeMatcher() = delete;
74 /// Creates a matcher that accepts any type with exactly the given type name.
76 : m_name(type_name), m_match_type(lldb::eFormatterMatchExact) {}
77 /// Creates a matcher that accepts any type matching the given regex.
79 : m_type_name_regex(std::move(regex)),
80 m_match_type(lldb::eFormatterMatchRegex) {}
81 /// Creates a matcher using the matching type and string from the given type
82 /// name specifier.
84 : m_name(type_specifier->GetName()),
85 m_match_type(type_specifier->GetMatchType()) {
87 m_type_name_regex = RegularExpression(type_specifier->GetName());
88 }
89
90 /// True iff this matches the given type.
91 bool Matches(FormattersMatchCandidate candidate_type) const {
92 ConstString type_name = candidate_type.GetTypeName();
93 switch (m_match_type) {
95 return m_name == type_name ||
96 StripTypeName(m_name) == StripTypeName(type_name);
98 return m_type_name_regex.Execute(type_name.GetStringRef());
100 // CommandObjectType{Synth,Filter}Add tries to prevent the user from
101 // creating both a synthetic child provider and a filter for the same type
102 // in the same category, but we don't have a type object at that point, so
103 // it creates a dummy candidate without type or script interpreter.
104 // Skip callback matching in these cases.
105 if (candidate_type.GetScriptInterpreter())
106 return candidate_type.GetScriptInterpreter()->FormatterCallbackFunction(
107 m_name.AsCString(),
108 std::make_shared<TypeImpl>(candidate_type.GetType()));
109 }
110 return false;
111 }
112
114
115 /// Returns the underlying match string for this TypeMatcher.
123
124 /// Returns true if this TypeMatcher and the given one were most created by
125 /// the same match string.
126 /// The main purpose of this function is to find existing TypeMatcher
127 /// instances by the user input that created them. This is necessary as LLDB
128 /// allows referencing existing TypeMatchers in commands by the user input
129 /// that originally created them:
130 /// (lldb) type summary add --summary-string \"A\" -x TypeName
131 /// (lldb) type summary delete TypeName
133 return GetMatchString() == other.GetMatchString();
134 }
135};
136
137template <typename ValueType> class FormattersContainer {
138public:
139 typedef typename std::shared_ptr<ValueType> ValueSP;
140 typedef std::vector<std::pair<TypeMatcher, ValueSP>> MapType;
141 typedef std::function<bool(const TypeMatcher &, const ValueSP &)>
143 typedef typename std::shared_ptr<FormattersContainer<ValueType>>
145
146 friend class TypeCategoryImpl;
147
149
150 void Add(TypeMatcher matcher, const ValueSP &entry) {
151 if (listener)
152 entry->GetRevision() = listener->GetCurrentRevision();
153 else
154 entry->GetRevision() = 0;
155
156 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
157 Delete(matcher);
158 m_map.emplace_back(std::move(matcher), std::move(entry));
159 if (listener)
160 listener->Changed();
161 }
162
163 bool Delete(TypeMatcher matcher) {
164 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
165 for (auto iter = m_map.begin(); iter != m_map.end(); ++iter)
166 if (iter->first.CreatedBySameMatchString(matcher)) {
167 m_map.erase(iter);
168 if (listener)
169 listener->Changed();
170 return true;
171 }
172 return false;
173 }
174
175 // Finds the first formatter in the container that matches `candidate`.
176 bool Get(FormattersMatchCandidate candidate, ValueSP &entry) {
177 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
178 for (auto &formatter : llvm::reverse(m_map)) {
179 if (formatter.first.Matches(candidate)) {
180 entry = formatter.second;
181 return true;
182 }
183 }
184 return false;
185 }
186
187 // Finds the first match between candidate types in `candidates` and
188 // formatters in this container.
189 bool Get(const FormattersMatchVector &candidates, ValueSP &entry) {
190 for (const FormattersMatchCandidate &candidate : candidates) {
191 if (Get(candidate, entry)) {
192 if (candidate.IsMatch(entry))
193 return true;
194 entry.reset();
195 continue;
196 }
197 }
198 return false;
199 }
200
201 bool GetExact(TypeMatcher matcher, ValueSP &entry) {
202 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
203 for (const auto &pos : m_map)
204 if (pos.first.CreatedBySameMatchString(matcher)) {
205 entry = pos.second;
206 return true;
207 }
208 return false;
209 }
210
211 ValueSP GetAtIndex(size_t index) {
212 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
213 if (index >= m_map.size())
214 return ValueSP();
215 return m_map[index].second;
216 }
217
219 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
220 if (index >= m_map.size())
222 TypeMatcher type_matcher = m_map[index].first;
223 return std::make_shared<TypeNameSpecifierImpl>(
224 type_matcher.GetMatchString().GetStringRef(),
225 type_matcher.GetMatchType());
226 }
227
228 void Clear() {
229 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
230 m_map.clear();
231 if (listener)
232 listener->Changed();
233 }
234
235 void ForEach(ForEachCallback callback) {
236 if (callback) {
237 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
238 for (const auto &pos : m_map) {
239 const TypeMatcher &type = pos.first;
240 if (!callback(type, pos.second))
241 break;
242 }
243 }
244 }
245
246 uint32_t GetCount() {
247 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
248 return m_map.size();
249 }
250
252 ForEach([&request](const TypeMatcher &matcher, const ValueSP &value) {
254 return true;
255 });
256 }
257
258protected:
261
263 std::recursive_mutex m_map_mutex;
265};
266
267} // namespace lldb_private
268
269#endif // LLDB_DATAFORMATTERS_FORMATTERSCONTAINER_H
static llvm::StringRef GetName(XcodeSDK::Type type)
Definition XcodeSDK.cpp:21
"lldb/Utility/ArgCompletionRequest.h"
void TryCompleteCurrentArg(llvm::StringRef completion, llvm::StringRef description="")
Adds a possible completion string if the completion would complete the current argument.
A uniqued constant string class.
Definition ConstString.h:40
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
bool IsEmpty() const
Test for empty string.
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
void AutoComplete(CompletionRequest &request)
bool Get(FormattersMatchCandidate candidate, ValueSP &entry)
void Add(TypeMatcher matcher, const ValueSP &entry)
bool Get(const FormattersMatchVector &candidates, ValueSP &entry)
std::shared_ptr< FormattersContainer< TypeSummaryImpl > > SharedPointer
FormattersContainer(const FormattersContainer &)=delete
FormattersContainer(IFormatChangeListener *lst)
lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index)
std::function< bool(const TypeMatcher &, const ValueSP &)> ForEachCallback
const FormattersContainer & operator=(const FormattersContainer &)=delete
std::vector< std::pair< TypeMatcher, ValueSP > > MapType
bool GetExact(TypeMatcher matcher, ValueSP &entry)
void ForEach(ForEachCallback callback)
ScriptInterpreter * GetScriptInterpreter() const
virtual ~IFormatChangeListener()=default
virtual uint32_t GetCurrentRevision()=0
virtual bool FormatterCallbackFunction(const char *function_name, lldb::TypeImplSP type_impl_sp)
Class for matching type names.
ConstString GetMatchString() const
Returns the underlying match string for this TypeMatcher.
TypeMatcher(lldb::TypeNameSpecifierImplSP type_specifier)
Creates a matcher using the matching type and string from the given type name specifier.
TypeMatcher(ConstString type_name)
Creates a matcher that accepts any type with exactly the given type name.
lldb::FormatterMatchType m_match_type
Indicates what kind of matching strategy should be used:
RegularExpression m_type_name_regex
lldb::FormatterMatchType GetMatchType() const
static ConstString StripTypeName(ConstString type)
bool CreatedBySameMatchString(TypeMatcher other) const
Returns true if this TypeMatcher and the given one were most created by the same match string.
TypeMatcher(RegularExpression regex)
Creates a matcher that accepts any type matching the given regex.
ConstString m_name
Type name for exact match, or name of the python callback if m_match_type is eFormatterMatchCallback.
bool Matches(FormattersMatchCandidate candidate_type) const
True iff this matches the given type.
A class that represents a running process on the host machine.
std::vector< FormattersMatchCandidate > FormattersMatchVector
std::shared_ptr< lldb_private::TypeNameSpecifierImpl > TypeNameSpecifierImplSP
FormatterMatchType
Type of match to be performed when looking for a formatter for a data type.
@ eFormatterMatchExact
@ eFormatterMatchRegex
@ eFormatterMatchCallback