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(
111 m_name.AsCString(),
112 std::make_shared<TypeImpl>(candidate_type.GetType()));
113 }
114 return false;
115 }
116
118
119 /// Returns the underlying match string for this TypeMatcher.
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))
197 return true;
198 entry.reset();
199 continue;
200 }
201 }
202 return false;
203 }
204
205 bool GetExact(TypeMatcher matcher, ValueSP &entry) {
206 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
207 for (const auto &pos : m_map)
208 if (pos.first.CreatedBySameMatchString(matcher)) {
209 entry = pos.second;
210 return true;
211 }
212 return false;
213 }
214
215 ValueSP GetAtIndex(size_t index) {
216 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
217 if (index >= m_map.size())
218 return ValueSP();
219 return m_map[index].second;
220 }
221
223 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
224 if (index >= m_map.size())
226 TypeMatcher type_matcher = m_map[index].first;
227 return std::make_shared<TypeNameSpecifierImpl>(
228 type_matcher.GetMatchString().GetStringRef(),
229 type_matcher.GetMatchType());
230 }
231
232 void Clear() {
233 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
234 m_map.clear();
235 if (listener)
236 listener->Changed();
237 }
238
239 void ForEach(ForEachCallback callback) {
240 if (callback) {
241 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
242 for (const auto &pos : m_map) {
243 const TypeMatcher &type = pos.first;
244 if (!callback(type, pos.second))
245 break;
246 }
247 }
248 }
249
250 uint32_t GetCount() {
251 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
252 return m_map.size();
253 }
254
256 ForEach([&request](const TypeMatcher &matcher, const ValueSP &value) {
258 return true;
259 });
260 }
261
262protected:
265
267 std::recursive_mutex m_map_mutex;
269};
270
271} // namespace lldb_private
272
273#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)
bool AdvanceIf(const std::string &token)
bool NextIf(Character c)
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