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
28
29namespace lldb_private {
30
32public:
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.
42 /// Type name for exact match, or name of the python callback if m_match_type
43 /// is `eFormatterMatchCallback`.
46 /// Indicates what kind of matching strategy should be used:
47 /// - eFormatterMatchExact: match the exact type name in m_name.
48 /// - eFormatterMatchRegex: match using the RegularExpression object
49 /// `m_type_name_regex` instead.
50 /// - eFormatterMatchCallback: run the function in m_name to decide if a type
51 /// matches or not.
53
54 // if the user tries to add formatters for, say, "struct Foo" those will not
55 // match any type because of the way we strip qualifiers from typenames this
56 // method looks for the case where the user is adding a
57 // "class","struct","enum" or "union" Foo and strips the unnecessary qualifier
59 if (type.IsEmpty())
60 return type;
61
62 std::string type_cstr(type.AsCString());
63 StringLexer type_lexer(type_cstr);
64
65 type_lexer.AdvanceIf("class ");
66 type_lexer.AdvanceIf("enum ");
67 type_lexer.AdvanceIf("struct ");
68 type_lexer.AdvanceIf("union ");
69
70 while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first)
71 ;
72
73 return ConstString(type_lexer.GetUnlexed());
74 }
75
76public:
77 TypeMatcher() = delete;
78 /// Creates a matcher that accepts any type with exactly the given type name.
80 : m_name(type_name), m_match_type(lldb::eFormatterMatchExact) {}
81 /// Creates a matcher that accepts any type matching the given regex.
83 : m_type_name_regex(std::move(regex)),
84 m_match_type(lldb::eFormatterMatchRegex) {}
85 /// Creates a matcher using the matching type and string from the given type
86 /// name specifier.
88 : m_name(type_specifier->GetName()),
89 m_match_type(type_specifier->GetMatchType()) {
91 m_type_name_regex = RegularExpression(type_specifier->GetName());
92 }
93
94 /// True iff this matches the given type.
95 bool Matches(FormattersMatchCandidate candidate_type) const {
96 ConstString type_name = candidate_type.GetTypeName();
97 switch (m_match_type) {
99 return m_name == type_name ||
100 StripTypeName(m_name) == StripTypeName(type_name);
102 return m_type_name_regex.Execute(type_name.GetStringRef());
104 // CommandObjectType{Synth,Filter}Add tries to prevent the user from
105 // creating both a synthetic child provider and a filter for the same type
106 // in the same category, but we don't have a type object at that point, so
107 // it creates a dummy candidate without type or script interpreter.
108 // Skip callback matching in these cases.
109 if (candidate_type.GetScriptInterpreter())
110 return candidate_type.GetScriptInterpreter()->FormatterCallbackFunction(
112 std::make_shared<TypeImpl>(candidate_type.GetType()));
113 }
114 return false;
115 }
116
118
119 /// Returns the underlying match string for this TypeMatcher.
122 return StripTypeName(m_name);
125 return m_name;
126 }
127
128 /// Returns true if this TypeMatcher and the given one were most created by
129 /// the same match string.
130 /// The main purpose of this function is to find existing TypeMatcher
131 /// instances by the user input that created them. This is necessary as LLDB
132 /// allows referencing existing TypeMatchers in commands by the user input
133 /// that originally created them:
134 /// (lldb) type summary add --summary-string \"A\" -x TypeName
135 /// (lldb) type summary delete TypeName
137 return GetMatchString() == other.GetMatchString();
138 }
139};
140
141template <typename ValueType> class FormattersContainer {
142public:
143 typedef typename std::shared_ptr<ValueType> ValueSP;
144 typedef std::vector<std::pair<TypeMatcher, ValueSP>> MapType;
145 typedef std::function<bool(const TypeMatcher &, const ValueSP &)>
147 typedef typename std::shared_ptr<FormattersContainer<ValueType>>
149
150 friend class TypeCategoryImpl;
151
153
154 void Add(TypeMatcher matcher, const ValueSP &entry) {
155 if (listener)
156 entry->GetRevision() = listener->GetCurrentRevision();
157 else
158 entry->GetRevision() = 0;
159
160 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
161 Delete(matcher);
162 m_map.emplace_back(std::move(matcher), std::move(entry));
163 if (listener)
164 listener->Changed();
165 }
166
167 bool Delete(TypeMatcher matcher) {
168 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
169 for (auto iter = m_map.begin(); iter != m_map.end(); ++iter)
170 if (iter->first.CreatedBySameMatchString(matcher)) {
171 m_map.erase(iter);
172 if (listener)
173 listener->Changed();
174 return true;
175 }
176 return false;
177 }
178
179 // Finds the first formatter in the container that matches `candidate`.
180 bool Get(FormattersMatchCandidate candidate, ValueSP &entry) {
181 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
182 for (auto &formatter : llvm::reverse(m_map)) {
183 if (formatter.first.Matches(candidate)) {
184 entry = formatter.second;
185 return true;
186 }
187 }
188 return false;
189 }
190
191 // Finds the first match between candidate types in `candidates` and
192 // formatters in this container.
193 bool Get(const FormattersMatchVector &candidates, ValueSP &entry) {
194 for (const FormattersMatchCandidate &candidate : candidates) {
195 if (Get(candidate, entry)) {
196 if (candidate.IsMatch(entry) == false) {
197 entry.reset();
198 continue;
199 } else {
200 return true;
201 }
202 }
203 }
204 return false;
205 }
206
207 bool GetExact(TypeMatcher matcher, ValueSP &entry) {
208 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
209 for (const auto &pos : m_map)
210 if (pos.first.CreatedBySameMatchString(matcher)) {
211 entry = pos.second;
212 return true;
213 }
214 return false;
215 }
216
217 ValueSP GetAtIndex(size_t index) {
218 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
219 if (index >= m_map.size())
220 return ValueSP();
221 return m_map[index].second;
222 }
223
225 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
226 if (index >= m_map.size())
228 TypeMatcher type_matcher = m_map[index].first;
229 return std::make_shared<TypeNameSpecifierImpl>(
230 type_matcher.GetMatchString().GetStringRef(),
231 type_matcher.GetMatchType());
232 }
233
234 void Clear() {
235 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
236 m_map.clear();
237 if (listener)
238 listener->Changed();
239 }
240
241 void ForEach(ForEachCallback callback) {
242 if (callback) {
243 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
244 for (const auto &pos : m_map) {
245 const TypeMatcher &type = pos.first;
246 if (!callback(type, pos.second))
247 break;
248 }
249 }
250 }
251
252 uint32_t GetCount() {
253 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
254 return m_map.size();
255 }
256
258 ForEach([&request](const TypeMatcher &matcher, const ValueSP &value) {
260 return true;
261 });
262 }
263
264protected:
267
269 std::recursive_mutex m_map_mutex;
271};
272
273} // namespace lldb_private
274
275#endif // LLDB_DATAFORMATTERS_FORMATTERSCONTAINER_H
static const char * GetName(DWARFDeclContext::Entry entry)
Returns the name of entry if it has one, or the appropriate "anonymous {namespace,...
"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.
Definition: ConstString.h:188
bool IsEmpty() const
Test for empty string.
Definition: ConstString.h:302
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
Definition: ConstString.h:197
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< ValueType > > SharedPointer
FormattersContainer(const FormattersContainer &)=delete
FormattersContainer(IFormatChangeListener *lst)
lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index)
std::shared_ptr< ValueType > ValueSP
std::function< bool(const TypeMatcher &, const ValueSP &)> ForEachCallback
bool Delete(TypeMatcher matcher)
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
Definition: FormatClasses.h:89
virtual ~IFormatChangeListener()=default
virtual uint32_t GetCurrentRevision()=0
bool Execute(llvm::StringRef string, llvm::SmallVectorImpl< llvm::StringRef > *matches=nullptr) const
Execute a regular expression match using the compiled regular expression that is already in this obje...
llvm::StringRef GetText() const
Access the regular expression text.
virtual bool FormatterCallbackFunction(const char *function_name, lldb::TypeImplSP type_impl_sp)
bool AdvanceIf(const std::string &token)
Definition: StringLexer.cpp:42
bool NextIf(Character c)
Definition: StringLexer.cpp:21
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.
Definition: SBAttachInfo.h:14
std::vector< FormattersMatchCandidate > FormattersMatchVector
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::TypeNameSpecifierImpl > TypeNameSpecifierImplSP
Definition: lldb-forward.h:462
FormatterMatchType
Type of match to be performed when looking for a formatter for a data type.
@ eFormatterMatchExact
@ eFormatterMatchRegex
@ eFormatterMatchCallback