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`.
43 std::string m_name;
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
57 static llvm::StringRef StripTypeName(llvm::StringRef type) {
58 if (type.empty())
59 return type;
60
61 llvm::StringRef type_lexer(type);
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 type_lexer;
70 }
71
72public:
73 TypeMatcher() = delete;
74 /// Creates a matcher that accepts any type with exactly the given type name.
75 TypeMatcher(std::string type_name)
76 : m_name(std::move(type_name)), m_match_type(lldb::eFormatterMatchExact) {
77 }
78 /// Creates a matcher that accepts any type matching the given regex.
80 : m_type_name_regex(std::move(regex)),
81 m_match_type(lldb::eFormatterMatchRegex) {}
82 /// Creates a matcher using the matching type and string from the given type
83 /// name specifier.
85 : m_name(type_specifier->GetName()),
86 m_match_type(type_specifier->GetMatchType()) {
88 m_type_name_regex = RegularExpression(type_specifier->GetName());
89 }
90
91 /// True iff this matches the given type.
92 bool Matches(FormattersMatchCandidate candidate_type) const {
93 llvm::StringRef type_name = candidate_type.GetTypeName().GetStringRef();
94 switch (m_match_type) {
96 return m_name == type_name ||
97 StripTypeName(m_name) == StripTypeName(type_name);
99 return m_type_name_regex.Execute(type_name);
101 // CommandObjectType{Synth,Filter}Add tries to prevent the user from
102 // creating both a synthetic child provider and a filter for the same type
103 // in the same category, but we don't have a type object at that point, so
104 // it creates a dummy candidate without type or script interpreter.
105 // Skip callback matching in these cases.
106 if (candidate_type.GetScriptInterpreter())
107 return candidate_type.GetScriptInterpreter()->FormatterCallbackFunction(
108 m_name.c_str(),
109 std::make_shared<TypeImpl>(candidate_type.GetType()));
110 }
111 return false;
112 }
113
115
116 /// Returns the underlying match string for this TypeMatcher.
117 llvm::StringRef GetMatchString() const {
119 return StripTypeName(m_name);
121 return m_type_name_regex.GetText();
122 return m_name;
123 }
124
125 /// Returns true if this TypeMatcher and the given one were most created by
126 /// the same match string.
127 /// The main purpose of this function is to find existing TypeMatcher
128 /// instances by the user input that created them. This is necessary as LLDB
129 /// allows referencing existing TypeMatchers in commands by the user input
130 /// that originally created them:
131 /// (lldb) type summary add --summary-string \"A\" -x TypeName
132 /// (lldb) type summary delete TypeName
134 return GetMatchString() == other.GetMatchString();
135 }
136};
137
138template <typename ValueType> class FormattersContainer {
139public:
140 typedef typename std::shared_ptr<ValueType> ValueSP;
141 typedef std::vector<std::pair<TypeMatcher, ValueSP>> MapType;
142 typedef std::function<bool(const TypeMatcher &, const ValueSP &)>
144 typedef typename std::shared_ptr<FormattersContainer<ValueType>>
146
147 friend class TypeCategoryImpl;
148
150
151 void Add(TypeMatcher matcher, const ValueSP &entry) {
152 if (listener)
153 entry->GetRevision() = listener->GetCurrentRevision();
154 else
155 entry->GetRevision() = 0;
156
157 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
158 Delete(matcher);
159 m_map.emplace_back(std::move(matcher), std::move(entry));
160 if (listener)
161 listener->Changed();
162 }
163
164 bool Delete(TypeMatcher matcher) {
165 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
166 for (auto iter = m_map.begin(); iter != m_map.end(); ++iter)
167 if (iter->first.CreatedBySameMatchString(matcher)) {
168 m_map.erase(iter);
169 if (listener)
170 listener->Changed();
171 return true;
172 }
173 return false;
174 }
175
176 // Finds the first formatter in the container that matches `candidate`.
177 bool Get(FormattersMatchCandidate candidate, ValueSP &entry) {
178 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
179 for (auto &formatter : llvm::reverse(m_map)) {
180 if (formatter.first.Matches(candidate)) {
181 entry = formatter.second;
182 return true;
183 }
184 }
185 return false;
186 }
187
188 // Finds the first match between candidate types in `candidates` and
189 // formatters in this container.
190 bool Get(const FormattersMatchVector &candidates, ValueSP &entry) {
191 for (const FormattersMatchCandidate &candidate : candidates) {
192 if (Get(candidate, entry)) {
193 if (candidate.IsMatch(entry))
194 return true;
195 entry.reset();
196 continue;
197 }
198 }
199 return false;
200 }
201
202 bool GetExact(TypeMatcher matcher, ValueSP &entry) {
203 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
204 for (const auto &pos : m_map)
205 if (pos.first.CreatedBySameMatchString(matcher)) {
206 entry = pos.second;
207 return true;
208 }
209 return false;
210 }
211
212 ValueSP GetAtIndex(size_t index) {
213 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
214 if (index >= m_map.size())
215 return ValueSP();
216 return m_map[index].second;
217 }
218
220 std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
221 if (index >= m_map.size())
223 TypeMatcher type_matcher = m_map[index].first;
224 return std::make_shared<TypeNameSpecifierImpl>(
225 type_matcher.GetMatchString(), 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) {
253 request.TryCompleteCurrentArg(matcher.GetMatchString());
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.
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.
TypeMatcher(lldb::TypeNameSpecifierImplSP type_specifier)
Creates a matcher using the matching type and string from the given type name specifier.
lldb::FormatterMatchType m_match_type
Indicates what kind of matching strategy should be used:
llvm::StringRef GetMatchString() const
Returns the underlying match string for this TypeMatcher.
RegularExpression m_type_name_regex
lldb::FormatterMatchType GetMatchType() const
std::string m_name
Type name for exact match, or name of the python callback if m_match_type is eFormatterMatchCallback.
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.
bool Matches(FormattersMatchCandidate candidate_type) const
True iff this matches the given type.
TypeMatcher(std::string type_name)
Creates a matcher that accepts any type with exactly the given type name.
static llvm::StringRef StripTypeName(llvm::StringRef 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.
@ eFormatterMatchCallback