clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name CommandObjectType.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-7/lib/clang/7.0.0 -D HAVE_ROUND -D LLDB_CONFIGURATION_RELEASE -D LLDB_USE_BUILTIN_DEMANGLER -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-7~svn326246/build-llvm/tools/lldb/source/Commands -I /build/llvm-toolchain-snapshot-7~svn326246/tools/lldb/source/Commands -I /build/llvm-toolchain-snapshot-7~svn326246/build-llvm/tools/lldb/include -I /build/llvm-toolchain-snapshot-7~svn326246/tools/lldb/include -I /build/llvm-toolchain-snapshot-7~svn326246/build-llvm/include -I /build/llvm-toolchain-snapshot-7~svn326246/include -I /usr/include/python2.7 -I /build/llvm-toolchain-snapshot-7~svn326246/tools/clang/include -I /build/llvm-toolchain-snapshot-7~svn326246/build-llvm/tools/lldb/../clang/include -I /build/llvm-toolchain-snapshot-7~svn326246/tools/lldb/source/. -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/backward -internal-isystem /usr/include/clang/7.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-strict-aliasing -Wno-deprecated-register -Wno-vla-extension -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-7~svn326246/build-llvm/tools/lldb/source/Commands -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-02-28-041547-14988-1 -x c++ /build/llvm-toolchain-snapshot-7~svn326246/tools/lldb/source/Commands/CommandObjectType.cpp
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | #include "CommandObjectType.h" |
11 | |
12 | |
13 | |
14 | #include <algorithm> |
15 | #include <cctype> |
16 | #include <functional> |
17 | |
18 | |
19 | #include "lldb/Core/Debugger.h" |
20 | #include "lldb/Core/IOHandler.h" |
21 | #include "lldb/Core/State.h" |
22 | #include "lldb/DataFormatters/DataVisualization.h" |
23 | #include "lldb/Host/OptionParser.h" |
24 | #include "lldb/Interpreter/CommandInterpreter.h" |
25 | #include "lldb/Interpreter/CommandObject.h" |
26 | #include "lldb/Interpreter/CommandReturnObject.h" |
27 | #include "lldb/Interpreter/OptionGroupFormat.h" |
28 | #include "lldb/Interpreter/OptionValueBoolean.h" |
29 | #include "lldb/Interpreter/OptionValueLanguage.h" |
30 | #include "lldb/Interpreter/OptionValueString.h" |
31 | #include "lldb/Interpreter/Options.h" |
32 | #include "lldb/Symbol/Symbol.h" |
33 | #include "lldb/Target/Language.h" |
34 | #include "lldb/Target/Process.h" |
35 | #include "lldb/Target/StackFrame.h" |
36 | #include "lldb/Target/Target.h" |
37 | #include "lldb/Target/Thread.h" |
38 | #include "lldb/Target/ThreadList.h" |
39 | #include "lldb/Utility/ConstString.h" |
40 | #include "lldb/Utility/RegularExpression.h" |
41 | #include "lldb/Utility/StringList.h" |
42 | |
43 | |
44 | #include "llvm/ADT/STLExtras.h" |
45 | |
46 | using namespace lldb; |
47 | using namespace lldb_private; |
48 | |
49 | class ScriptAddOptions { |
50 | public: |
51 | TypeSummaryImpl::Flags m_flags; |
52 | StringList m_target_types; |
53 | bool m_regex; |
54 | ConstString m_name; |
55 | std::string m_category; |
56 | |
57 | ScriptAddOptions(const TypeSummaryImpl::Flags &flags, bool regx, |
58 | const ConstString &name, std::string catg) |
59 | : m_flags(flags), m_regex(regx), m_name(name), m_category(catg) {} |
60 | |
61 | typedef std::shared_ptr<ScriptAddOptions> SharedPointer; |
62 | }; |
63 | |
64 | class SynthAddOptions { |
65 | public: |
66 | bool m_skip_pointers; |
67 | bool m_skip_references; |
68 | bool m_cascade; |
69 | bool m_regex; |
70 | StringList m_target_types; |
71 | std::string m_category; |
72 | |
73 | SynthAddOptions(bool sptr, bool sref, bool casc, bool regx, std::string catg) |
74 | : m_skip_pointers(sptr), m_skip_references(sref), m_cascade(casc), |
75 | m_regex(regx), m_target_types(), m_category(catg) {} |
76 | |
77 | typedef std::shared_ptr<SynthAddOptions> SharedPointer; |
78 | }; |
79 | |
80 | static bool WarnOnPotentialUnquotedUnsignedType(Args &command, |
81 | CommandReturnObject &result) { |
82 | if (command.empty()) |
83 | return false; |
84 | |
85 | for (auto entry : llvm::enumerate(command.entries().drop_back())) { |
86 | if (entry.value().ref != "unsigned") |
87 | continue; |
88 | auto next = command.entries()[entry.index() + 1].ref; |
89 | if (next == "int" || next == "short" || next == "char" || next == "long") { |
90 | result.AppendWarningWithFormat( |
91 | "unsigned %s being treated as two types. if you meant the combined " |
92 | "type " |
93 | "name use quotes, as in \"unsigned %s\"\n", |
94 | next.str().c_str(), next.str().c_str()); |
95 | return true; |
96 | } |
97 | } |
98 | return false; |
99 | } |
100 | |
101 | static OptionDefinition g_type_summary_add_options[] = { |
102 | |
103 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "category", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Add this to the given category instead of the default one." }, |
104 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "cascade", 'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, cascade through typedef chains." }, |
105 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "no-value", 'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't show the value, just show the summary, for this type." }, |
106 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-pointers", 'p', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects." }, |
107 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-references", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for references-to-type objects." }, |
108 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "regex", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Type names are actually regular expressions." }, |
109 | { LLDB_OPT_SET_1(1U << 0), true, "inline-children", 'c', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "If true, inline all child values into summary string." }, |
110 | { LLDB_OPT_SET_1(1U << 0), false, "omit-names", 'O', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "If true, omit value names in the summary display." }, |
111 | { LLDB_OPT_SET_2(1U << 1), true, "summary-string", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeSummaryString, "Summary string used to display text and object contents." }, |
112 | { LLDB_OPT_SET_3(1U << 2), false, "python-script", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonScript, "Give a one-liner Python script as part of the command." }, |
113 | { LLDB_OPT_SET_3(1U << 2), false, "python-function", 'F', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonFunction, "Give the name of a Python function to use for this type." }, |
114 | { LLDB_OPT_SET_3(1U << 2), false, "input-python", 'P', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Input Python code to use for this type manually." }, |
115 | { LLDB_OPT_SET_2(1U << 1) | LLDB_OPT_SET_3(1U << 2), false, "expand", 'e', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Expand aggregate data types to show children on separate lines." }, |
116 | { LLDB_OPT_SET_2(1U << 1) | LLDB_OPT_SET_3(1U << 2), false, "hide-empty", 'h', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Do not expand aggregate data types with no children." }, |
117 | { LLDB_OPT_SET_2(1U << 1) | LLDB_OPT_SET_3(1U << 2), false, "name", 'n', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "A name for this summary string." } |
118 | |
119 | }; |
120 | |
121 | class CommandObjectTypeSummaryAdd : public CommandObjectParsed, |
122 | public IOHandlerDelegateMultiline { |
123 | private: |
124 | class CommandOptions : public Options { |
125 | public: |
126 | CommandOptions(CommandInterpreter &interpreter) : Options() {} |
127 | |
128 | ~CommandOptions() override = default; |
129 | |
130 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
131 | ExecutionContext *execution_context) override; |
132 | |
133 | void OptionParsingStarting(ExecutionContext *execution_context) override; |
134 | |
135 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
136 | return llvm::makeArrayRef(g_type_summary_add_options); |
137 | } |
138 | |
139 | |
140 | |
141 | TypeSummaryImpl::Flags m_flags; |
142 | bool m_regex; |
143 | std::string m_format_string; |
144 | ConstString m_name; |
145 | std::string m_python_script; |
146 | std::string m_python_function; |
147 | bool m_is_add_script; |
148 | std::string m_category; |
149 | }; |
150 | |
151 | CommandOptions m_options; |
152 | |
153 | Options *GetOptions() override { return &m_options; } |
154 | |
155 | bool Execute_ScriptSummary(Args &command, CommandReturnObject &result); |
156 | |
157 | bool Execute_StringSummary(Args &command, CommandReturnObject &result); |
158 | |
159 | public: |
160 | enum SummaryFormatType { eRegularSummary, eRegexSummary, eNamedSummary }; |
161 | |
162 | CommandObjectTypeSummaryAdd(CommandInterpreter &interpreter); |
163 | |
164 | ~CommandObjectTypeSummaryAdd() override = default; |
165 | |
166 | void IOHandlerActivated(IOHandler &io_handler) override { |
167 | static const char *g_summary_addreader_instructions = |
168 | "Enter your Python command(s). Type 'DONE' to end.\n" |
169 | "def function (valobj,internal_dict):\n" |
170 | " \"\"\"valobj: an SBValue which you want to provide a summary " |
171 | "for\n" |
172 | " internal_dict: an LLDB support object not to be used\"\"\"\n"; |
173 | |
174 | StreamFileSP output_sp(io_handler.GetOutputStreamFile()); |
175 | if (output_sp) { |
176 | output_sp->PutCString(g_summary_addreader_instructions); |
177 | output_sp->Flush(); |
178 | } |
179 | } |
180 | |
181 | void IOHandlerInputComplete(IOHandler &io_handler, |
182 | std::string &data) override { |
183 | StreamFileSP error_sp = io_handler.GetErrorStreamFile(); |
184 | |
185 | #ifndef LLDB_DISABLE_PYTHON |
186 | ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); |
187 | if (interpreter) { |
188 | StringList lines; |
189 | lines.SplitIntoLines(data); |
190 | if (lines.GetSize() > 0) { |
191 | ScriptAddOptions *options_ptr = |
192 | ((ScriptAddOptions *)io_handler.GetUserData()); |
193 | if (options_ptr) { |
194 | ScriptAddOptions::SharedPointer options( |
195 | options_ptr); |
196 | |
197 | |
198 | ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); |
199 | if (interpreter) { |
200 | std::string funct_name_str; |
201 | if (interpreter->GenerateTypeScriptFunction(lines, |
202 | funct_name_str)) { |
203 | if (funct_name_str.empty()) { |
204 | error_sp->Printf("unable to obtain a valid function name from " |
205 | "the script interpreter.\n"); |
206 | error_sp->Flush(); |
207 | } else { |
208 | |
209 | |
210 | |
211 | TypeSummaryImplSP script_format; |
212 | script_format.reset(new ScriptSummaryFormat( |
213 | options->m_flags, funct_name_str.c_str(), |
214 | lines.CopyList(" ").c_str())); |
215 | |
216 | Status error; |
217 | |
218 | for (size_t i = 0; i < options->m_target_types.GetSize(); i++) { |
219 | const char *type_name = |
220 | options->m_target_types.GetStringAtIndex(i); |
221 | CommandObjectTypeSummaryAdd::AddSummary( |
222 | ConstString(type_name), script_format, |
223 | (options->m_regex |
224 | ? CommandObjectTypeSummaryAdd::eRegexSummary |
225 | : CommandObjectTypeSummaryAdd::eRegularSummary), |
226 | options->m_category, &error); |
227 | if (error.Fail()) { |
228 | error_sp->Printf("error: %s", error.AsCString()); |
229 | error_sp->Flush(); |
230 | } |
231 | } |
232 | |
233 | if (options->m_name) { |
234 | CommandObjectTypeSummaryAdd::AddSummary( |
235 | options->m_name, script_format, |
236 | CommandObjectTypeSummaryAdd::eNamedSummary, |
237 | options->m_category, &error); |
238 | if (error.Fail()) { |
239 | CommandObjectTypeSummaryAdd::AddSummary( |
240 | options->m_name, script_format, |
241 | CommandObjectTypeSummaryAdd::eNamedSummary, |
242 | options->m_category, &error); |
243 | if (error.Fail()) { |
244 | error_sp->Printf("error: %s", error.AsCString()); |
245 | error_sp->Flush(); |
246 | } |
247 | } else { |
248 | error_sp->Printf("error: %s", error.AsCString()); |
249 | error_sp->Flush(); |
250 | } |
251 | } else { |
252 | if (error.AsCString()) { |
253 | error_sp->Printf("error: %s", error.AsCString()); |
254 | error_sp->Flush(); |
255 | } |
256 | } |
257 | } |
258 | } else { |
259 | error_sp->Printf("error: unable to generate a function.\n"); |
260 | error_sp->Flush(); |
261 | } |
262 | } else { |
263 | error_sp->Printf("error: no script interpreter.\n"); |
264 | error_sp->Flush(); |
265 | } |
266 | } else { |
267 | error_sp->Printf("error: internal synchronization information " |
268 | "missing or invalid.\n"); |
269 | error_sp->Flush(); |
270 | } |
271 | } else { |
272 | error_sp->Printf("error: empty function, didn't add python command.\n"); |
273 | error_sp->Flush(); |
274 | } |
275 | } else { |
276 | error_sp->Printf( |
277 | "error: script interpreter missing, didn't add python command.\n"); |
278 | error_sp->Flush(); |
279 | } |
280 | #endif // LLDB_DISABLE_PYTHON |
281 | io_handler.SetIsDone(true); |
282 | } |
283 | |
284 | static bool AddSummary(ConstString type_name, lldb::TypeSummaryImplSP entry, |
285 | SummaryFormatType type, std::string category, |
286 | Status *error = nullptr); |
287 | |
288 | protected: |
289 | bool DoExecute(Args &command, CommandReturnObject &result) override; |
290 | }; |
291 | |
292 | static const char *g_synth_addreader_instructions = |
293 | "Enter your Python command(s). Type 'DONE' to end.\n" |
294 | "You must define a Python class with these methods:\n" |
295 | " def __init__(self, valobj, dict):\n" |
296 | " def num_children(self):\n" |
297 | " def get_child_at_index(self, index):\n" |
298 | " def get_child_index(self, name):\n" |
299 | " def update(self):\n" |
300 | " '''Optional'''\n" |
301 | "class synthProvider:\n"; |
302 | |
303 | static OptionDefinition g_type_synth_add_options[] = { |
304 | |
305 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "cascade", 'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, cascade through typedef chains." }, |
306 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-pointers", 'p', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects." }, |
307 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-references", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for references-to-type objects." }, |
308 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "category", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Add this to the given category instead of the default one." }, |
309 | { LLDB_OPT_SET_2(1U << 1), false, "python-class", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "Use this Python class to produce synthetic children." }, |
310 | { LLDB_OPT_SET_3(1U << 2), false, "input-python", 'P', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Type Python code to generate a class that provides synthetic children." }, |
311 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "regex", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Type names are actually regular expressions." } |
312 | |
313 | }; |
314 | |
315 | class CommandObjectTypeSynthAdd : public CommandObjectParsed, |
316 | public IOHandlerDelegateMultiline { |
317 | private: |
318 | class CommandOptions : public Options { |
319 | public: |
320 | CommandOptions() : Options() {} |
321 | |
322 | ~CommandOptions() override = default; |
323 | |
324 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
325 | ExecutionContext *execution_context) override { |
326 | Status error; |
327 | const int short_option = m_getopt_table[option_idx].val; |
328 | bool success; |
329 | |
330 | switch (short_option) { |
331 | case 'C': |
332 | m_cascade = Args::StringToBoolean(option_arg, true, &success); |
333 | if (!success) |
334 | error.SetErrorStringWithFormat("invalid value for cascade: %s", |
335 | option_arg.str().c_str()); |
336 | break; |
337 | case 'P': |
338 | handwrite_python = true; |
339 | break; |
340 | case 'l': |
341 | m_class_name = std::string(option_arg); |
342 | is_class_based = true; |
343 | break; |
344 | case 'p': |
345 | m_skip_pointers = true; |
346 | break; |
347 | case 'r': |
348 | m_skip_references = true; |
349 | break; |
350 | case 'w': |
351 | m_category = std::string(option_arg); |
352 | break; |
353 | case 'x': |
354 | m_regex = true; |
355 | break; |
356 | default: |
357 | error.SetErrorStringWithFormat("unrecognized option '%c'", |
358 | short_option); |
359 | break; |
360 | } |
361 | |
362 | return error; |
363 | } |
364 | |
365 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
366 | m_cascade = true; |
367 | m_class_name = ""; |
368 | m_skip_pointers = false; |
369 | m_skip_references = false; |
370 | m_category = "default"; |
371 | is_class_based = false; |
372 | handwrite_python = false; |
373 | m_regex = false; |
374 | } |
375 | |
376 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
377 | return llvm::makeArrayRef(g_type_synth_add_options); |
378 | } |
379 | |
380 | |
381 | |
382 | bool m_cascade; |
383 | bool m_skip_references; |
384 | bool m_skip_pointers; |
385 | std::string m_class_name; |
386 | bool m_input_python; |
387 | std::string m_category; |
388 | bool is_class_based; |
389 | bool handwrite_python; |
390 | bool m_regex; |
391 | }; |
392 | |
393 | CommandOptions m_options; |
394 | |
395 | Options *GetOptions() override { return &m_options; } |
396 | |
397 | bool Execute_HandwritePython(Args &command, CommandReturnObject &result); |
398 | |
399 | bool Execute_PythonClass(Args &command, CommandReturnObject &result); |
400 | |
401 | protected: |
402 | bool DoExecute(Args &command, CommandReturnObject &result) override { |
403 | WarnOnPotentialUnquotedUnsignedType(command, result); |
404 | |
405 | if (m_options.handwrite_python) |
406 | return Execute_HandwritePython(command, result); |
407 | else if (m_options.is_class_based) |
408 | return Execute_PythonClass(command, result); |
409 | else { |
410 | result.AppendError("must either provide a children list, a Python class " |
411 | "name, or use -P and type a Python class " |
412 | "line-by-line"); |
413 | result.SetStatus(eReturnStatusFailed); |
414 | return false; |
415 | } |
416 | } |
417 | |
418 | void IOHandlerActivated(IOHandler &io_handler) override { |
419 | StreamFileSP output_sp(io_handler.GetOutputStreamFile()); |
420 | if (output_sp) { |
421 | output_sp->PutCString(g_synth_addreader_instructions); |
422 | output_sp->Flush(); |
423 | } |
424 | } |
425 | |
426 | void IOHandlerInputComplete(IOHandler &io_handler, |
427 | std::string &data) override { |
428 | StreamFileSP error_sp = io_handler.GetErrorStreamFile(); |
429 | |
430 | #ifndef LLDB_DISABLE_PYTHON |
431 | ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); |
432 | if (interpreter) { |
433 | StringList lines; |
434 | lines.SplitIntoLines(data); |
435 | if (lines.GetSize() > 0) { |
436 | SynthAddOptions *options_ptr = |
437 | ((SynthAddOptions *)io_handler.GetUserData()); |
438 | if (options_ptr) { |
439 | SynthAddOptions::SharedPointer options( |
440 | options_ptr); |
441 | |
442 | |
443 | ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); |
444 | if (interpreter) { |
445 | std::string class_name_str; |
446 | if (interpreter->GenerateTypeSynthClass(lines, class_name_str)) { |
447 | if (class_name_str.empty()) { |
448 | error_sp->Printf( |
449 | "error: unable to obtain a proper name for the class.\n"); |
450 | error_sp->Flush(); |
451 | } else { |
452 | |
453 | |
454 | |
455 | SyntheticChildrenSP synth_provider; |
456 | synth_provider.reset(new ScriptedSyntheticChildren( |
457 | SyntheticChildren::Flags() |
458 | .SetCascades(options->m_cascade) |
459 | .SetSkipPointers(options->m_skip_pointers) |
460 | .SetSkipReferences(options->m_skip_references), |
461 | class_name_str.c_str())); |
462 | |
463 | lldb::TypeCategoryImplSP category; |
464 | DataVisualization::Categories::GetCategory( |
465 | ConstString(options->m_category.c_str()), category); |
466 | |
467 | Status error; |
468 | |
469 | for (size_t i = 0; i < options->m_target_types.GetSize(); i++) { |
470 | const char *type_name = |
471 | options->m_target_types.GetStringAtIndex(i); |
472 | ConstString const_type_name(type_name); |
473 | if (const_type_name) { |
474 | if (!CommandObjectTypeSynthAdd::AddSynth( |
475 | const_type_name, synth_provider, |
476 | options->m_regex |
477 | ? CommandObjectTypeSynthAdd::eRegexSynth |
478 | : CommandObjectTypeSynthAdd::eRegularSynth, |
479 | options->m_category, &error)) { |
480 | error_sp->Printf("error: %s\n", error.AsCString()); |
481 | error_sp->Flush(); |
482 | break; |
483 | } |
484 | } else { |
485 | error_sp->Printf("error: invalid type name.\n"); |
486 | error_sp->Flush(); |
487 | break; |
488 | } |
489 | } |
490 | } |
491 | } else { |
492 | error_sp->Printf("error: unable to generate a class.\n"); |
493 | error_sp->Flush(); |
494 | } |
495 | } else { |
496 | error_sp->Printf("error: no script interpreter.\n"); |
497 | error_sp->Flush(); |
498 | } |
499 | } else { |
500 | error_sp->Printf("error: internal synchronization data missing.\n"); |
501 | error_sp->Flush(); |
502 | } |
503 | } else { |
504 | error_sp->Printf("error: empty function, didn't add python command.\n"); |
505 | error_sp->Flush(); |
506 | } |
507 | } else { |
508 | error_sp->Printf( |
509 | "error: script interpreter missing, didn't add python command.\n"); |
510 | error_sp->Flush(); |
511 | } |
512 | |
513 | #endif // LLDB_DISABLE_PYTHON |
514 | io_handler.SetIsDone(true); |
515 | } |
516 | |
517 | public: |
518 | enum SynthFormatType { eRegularSynth, eRegexSynth }; |
519 | |
520 | CommandObjectTypeSynthAdd(CommandInterpreter &interpreter); |
521 | |
522 | ~CommandObjectTypeSynthAdd() override = default; |
523 | |
524 | static bool AddSynth(ConstString type_name, lldb::SyntheticChildrenSP entry, |
525 | SynthFormatType type, std::string category_name, |
526 | Status *error); |
527 | }; |
528 | |
529 | |
530 | |
531 | |
532 | |
533 | static OptionDefinition g_type_format_add_options[] = { |
534 | |
535 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "category", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Add this to the given category instead of the default one." }, |
536 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "cascade", 'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, cascade through typedef chains." }, |
537 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-pointers", 'p', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects." }, |
538 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-references", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for references-to-type objects." }, |
539 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "regex", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Type names are actually regular expressions." }, |
540 | { LLDB_OPT_SET_2(1U << 1), false, "type", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Format variables as if they were of this type." } |
541 | |
542 | }; |
543 | |
544 | class CommandObjectTypeFormatAdd : public CommandObjectParsed { |
545 | private: |
546 | class CommandOptions : public OptionGroup { |
547 | public: |
548 | CommandOptions() : OptionGroup() {} |
549 | |
550 | ~CommandOptions() override = default; |
551 | |
552 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
553 | return llvm::makeArrayRef(g_type_format_add_options); |
554 | } |
555 | |
556 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
557 | m_cascade = true; |
558 | m_skip_pointers = false; |
559 | m_skip_references = false; |
560 | m_regex = false; |
561 | m_category.assign("default"); |
562 | m_custom_type_name.clear(); |
563 | } |
564 | |
565 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, |
566 | ExecutionContext *execution_context) override { |
567 | Status error; |
568 | const int short_option = |
569 | g_type_format_add_options[option_idx].short_option; |
570 | bool success; |
571 | |
572 | switch (short_option) { |
573 | case 'C': |
574 | m_cascade = Args::StringToBoolean(option_value, true, &success); |
575 | if (!success) |
576 | error.SetErrorStringWithFormat("invalid value for cascade: %s", |
577 | option_value.str().c_str()); |
578 | break; |
579 | case 'p': |
580 | m_skip_pointers = true; |
581 | break; |
582 | case 'w': |
583 | m_category.assign(option_value); |
584 | break; |
585 | case 'r': |
586 | m_skip_references = true; |
587 | break; |
588 | case 'x': |
589 | m_regex = true; |
590 | break; |
591 | case 't': |
592 | m_custom_type_name.assign(option_value); |
593 | break; |
594 | default: |
595 | error.SetErrorStringWithFormat("unrecognized option '%c'", |
596 | short_option); |
597 | break; |
598 | } |
599 | |
600 | return error; |
601 | } |
602 | |
603 | |
604 | |
605 | bool m_cascade; |
606 | bool m_skip_references; |
607 | bool m_skip_pointers; |
608 | bool m_regex; |
609 | std::string m_category; |
610 | std::string m_custom_type_name; |
611 | }; |
612 | |
613 | OptionGroupOptions m_option_group; |
614 | OptionGroupFormat m_format_options; |
615 | CommandOptions m_command_options; |
616 | |
617 | Options *GetOptions() override { return &m_option_group; } |
618 | |
619 | public: |
620 | CommandObjectTypeFormatAdd(CommandInterpreter &interpreter) |
621 | : CommandObjectParsed(interpreter, "type format add", |
622 | "Add a new formatting style for a type.", nullptr), |
623 | m_option_group(), m_format_options(eFormatInvalid), |
624 | m_command_options() { |
625 | CommandArgumentEntry type_arg; |
626 | CommandArgumentData type_style_arg; |
627 | |
628 | type_style_arg.arg_type = eArgTypeName; |
629 | type_style_arg.arg_repetition = eArgRepeatPlus; |
630 | |
631 | type_arg.push_back(type_style_arg); |
632 | |
633 | m_arguments.push_back(type_arg); |
634 | |
635 | SetHelpLong( |
636 | R"( |
637 | The following examples of 'type format add' refer to this code snippet for context: |
638 | |
639 | typedef int Aint; |
640 | typedef float Afloat; |
641 | typedef Aint Bint; |
642 | typedef Afloat Bfloat; |
643 | |
644 | Aint ix = 5; |
645 | Bint iy = 5; |
646 | |
647 | Afloat fx = 3.14; |
648 | BFloat fy = 3.14; |
649 | |
650 | Adding default formatting: |
651 | |
652 | (lldb) type format add -f hex AInt |
653 | (lldb) frame variable iy |
654 | |
655 | )" |
656 | " Produces hexadecimal display of iy, because no formatter is available for Bint and \ |
657 | the one for Aint is used instead." |
658 | R"( |
659 | |
660 | To prevent this use the cascade option '-C no' to prevent evaluation of typedef chains: |
661 | |
662 | |
663 | (lldb) type format add -f hex -C no AInt |
664 | |
665 | Similar reasoning applies to this: |
666 | |
667 | (lldb) type format add -f hex -C no float -p |
668 | |
669 | )" |
670 | " All float values and float references are now formatted as hexadecimal, but not \ |
671 | pointers to floats. Nor will it change the default display for Afloat and Bfloat objects."); |
672 | |
673 | |
674 | m_option_group.Append(&m_format_options, |
675 | OptionGroupFormat::OPTION_GROUP_FORMAT, |
676 | LLDB_OPT_SET_1(1U << 0)); |
677 | m_option_group.Append(&m_command_options); |
678 | m_option_group.Finalize(); |
679 | } |
680 | |
681 | ~CommandObjectTypeFormatAdd() override = default; |
682 | |
683 | protected: |
684 | bool DoExecute(Args &command, CommandReturnObject &result) override { |
685 | const size_t argc = command.GetArgumentCount(); |
686 | |
687 | if (argc < 1) { |
| |
| |
688 | result.AppendErrorWithFormat("%s takes one or more args.\n", |
689 | m_cmd_name.c_str()); |
690 | result.SetStatus(eReturnStatusFailed); |
691 | return false; |
692 | } |
693 | |
694 | const Format format = m_format_options.GetFormat(); |
695 | if (format == eFormatInvalid && |
| 3 | | Assuming 'format' is not equal to eFormatInvalid | |
|
696 | m_command_options.m_custom_type_name.empty()) { |
697 | result.AppendErrorWithFormat("%s needs a valid format.\n", |
698 | m_cmd_name.c_str()); |
699 | result.SetStatus(eReturnStatusFailed); |
700 | return false; |
701 | } |
702 | |
703 | TypeFormatImplSP entry; |
704 | |
705 | if (m_command_options.m_custom_type_name.empty()) |
| 4 | | Assuming the condition is false | |
|
| |
706 | entry.reset(new TypeFormatImpl_Format( |
707 | format, TypeFormatImpl::Flags() |
708 | .SetCascades(m_command_options.m_cascade) |
709 | .SetSkipPointers(m_command_options.m_skip_pointers) |
710 | .SetSkipReferences(m_command_options.m_skip_references))); |
711 | else |
712 | entry.reset(new TypeFormatImpl_EnumType( |
713 | ConstString(m_command_options.m_custom_type_name.c_str()), |
714 | TypeFormatImpl::Flags() |
715 | .SetCascades(m_command_options.m_cascade) |
716 | .SetSkipPointers(m_command_options.m_skip_pointers) |
717 | .SetSkipReferences(m_command_options.m_skip_references))); |
718 | |
719 | |
720 | |
721 | TypeCategoryImplSP category_sp; |
722 | DataVisualization::Categories::GetCategory( |
723 | ConstString(m_command_options.m_category), category_sp); |
724 | if (!category_sp) |
| |
725 | return false; |
726 | |
727 | WarnOnPotentialUnquotedUnsignedType(command, result); |
728 | |
729 | for (auto &arg_entry : command.entries()) { |
| 7 | | Assuming '__begin1' is not equal to '__end1' | |
|
730 | if (arg_entry.ref.empty()) { |
| 8 | | Assuming the condition is false | |
|
| |
| 12 | | Assuming the condition is false | |
|
| |
| 15 | | Assuming the condition is false | |
|
| |
| 46 | | Assuming the condition is false | |
|
| |
731 | result.AppendError("empty typenames not allowed"); |
732 | result.SetStatus(eReturnStatusFailed); |
733 | return false; |
734 | } |
735 | |
736 | ConstString typeCS(arg_entry.ref); |
737 | if (m_command_options.m_regex) { |
| 10 | | Assuming the condition is false | |
|
| |
| |
| |
| |
738 | RegularExpressionSP typeRX(new RegularExpression()); |
739 | if (!typeRX->Compile(arg_entry.ref)) { |
740 | result.AppendError( |
741 | "regex format error (maybe this is not really a regex?)"); |
742 | result.SetStatus(eReturnStatusFailed); |
743 | return false; |
744 | } |
745 | category_sp->GetRegexTypeSummariesContainer()->Delete(typeCS); |
746 | category_sp->GetRegexTypeFormatsContainer()->Add(typeRX, entry); |
747 | } else |
748 | category_sp->GetTypeFormatsContainer()->Add(typeCS, entry); |
| 18 | | Calling 'FormattersContainer::Add' | |
|
| 45 | | Returning; memory was released | |
|
| 49 | | Calling 'FormattersContainer::Add' | |
|
749 | } |
750 | |
751 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
752 | return result.Succeeded(); |
753 | } |
754 | }; |
755 | |
756 | static OptionDefinition g_type_formatter_delete_options[] = { |
757 | |
758 | { LLDB_OPT_SET_1(1U << 0), false, "all", 'a', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Delete from every category." }, |
759 | { LLDB_OPT_SET_2(1U << 1), false, "category", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Delete from given category." }, |
760 | { LLDB_OPT_SET_3(1U << 2), false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Delete from given language's category." } |
761 | |
762 | }; |
763 | |
764 | class CommandObjectTypeFormatterDelete : public CommandObjectParsed { |
765 | protected: |
766 | class CommandOptions : public Options { |
767 | public: |
768 | CommandOptions() : Options() {} |
769 | |
770 | ~CommandOptions() override = default; |
771 | |
772 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
773 | ExecutionContext *execution_context) override { |
774 | Status error; |
775 | const int short_option = m_getopt_table[option_idx].val; |
776 | |
777 | switch (short_option) { |
778 | case 'a': |
779 | m_delete_all = true; |
780 | break; |
781 | case 'w': |
782 | m_category = std::string(option_arg); |
783 | break; |
784 | case 'l': |
785 | m_language = Language::GetLanguageTypeFromString(option_arg); |
786 | break; |
787 | default: |
788 | error.SetErrorStringWithFormat("unrecognized option '%c'", |
789 | short_option); |
790 | break; |
791 | } |
792 | |
793 | return error; |
794 | } |
795 | |
796 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
797 | m_delete_all = false; |
798 | m_category = "default"; |
799 | m_language = lldb::eLanguageTypeUnknown; |
800 | } |
801 | |
802 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
803 | return llvm::makeArrayRef(g_type_formatter_delete_options); |
804 | } |
805 | |
806 | |
807 | |
808 | bool m_delete_all; |
809 | std::string m_category; |
810 | lldb::LanguageType m_language; |
811 | }; |
812 | |
813 | CommandOptions m_options; |
814 | uint32_t m_formatter_kind_mask; |
815 | |
816 | Options *GetOptions() override { return &m_options; } |
817 | |
818 | public: |
819 | CommandObjectTypeFormatterDelete(CommandInterpreter &interpreter, |
820 | uint32_t formatter_kind_mask, |
821 | const char *name, const char *help) |
822 | : CommandObjectParsed(interpreter, name, help, nullptr), m_options(), |
823 | m_formatter_kind_mask(formatter_kind_mask) { |
824 | CommandArgumentEntry type_arg; |
825 | CommandArgumentData type_style_arg; |
826 | |
827 | type_style_arg.arg_type = eArgTypeName; |
828 | type_style_arg.arg_repetition = eArgRepeatPlain; |
829 | |
830 | type_arg.push_back(type_style_arg); |
831 | |
832 | m_arguments.push_back(type_arg); |
833 | } |
834 | |
835 | ~CommandObjectTypeFormatterDelete() override = default; |
836 | |
837 | protected: |
838 | virtual bool FormatterSpecificDeletion(ConstString typeCS) { return false; } |
839 | |
840 | bool DoExecute(Args &command, CommandReturnObject &result) override { |
841 | const size_t argc = command.GetArgumentCount(); |
842 | |
843 | if (argc != 1) { |
844 | result.AppendErrorWithFormat("%s takes 1 arg.\n", m_cmd_name.c_str()); |
845 | result.SetStatus(eReturnStatusFailed); |
846 | return false; |
847 | } |
848 | |
849 | const char *typeA = command.GetArgumentAtIndex(0); |
850 | ConstString typeCS(typeA); |
851 | |
852 | if (!typeCS) { |
853 | result.AppendError("empty typenames not allowed"); |
854 | result.SetStatus(eReturnStatusFailed); |
855 | return false; |
856 | } |
857 | |
858 | if (m_options.m_delete_all) { |
859 | DataVisualization::Categories::ForEach( |
860 | [this, typeCS](const lldb::TypeCategoryImplSP &category_sp) -> bool { |
861 | category_sp->Delete(typeCS, m_formatter_kind_mask); |
862 | return true; |
863 | }); |
864 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
865 | return result.Succeeded(); |
866 | } |
867 | |
868 | bool delete_category = false; |
869 | bool extra_deletion = false; |
870 | |
871 | if (m_options.m_language != lldb::eLanguageTypeUnknown) { |
872 | lldb::TypeCategoryImplSP category; |
873 | DataVisualization::Categories::GetCategory(m_options.m_language, |
874 | category); |
875 | if (category) |
876 | delete_category = category->Delete(typeCS, m_formatter_kind_mask); |
877 | extra_deletion = FormatterSpecificDeletion(typeCS); |
878 | } else { |
879 | lldb::TypeCategoryImplSP category; |
880 | DataVisualization::Categories::GetCategory( |
881 | ConstString(m_options.m_category.c_str()), category); |
882 | if (category) |
883 | delete_category = category->Delete(typeCS, m_formatter_kind_mask); |
884 | extra_deletion = FormatterSpecificDeletion(typeCS); |
885 | } |
886 | |
887 | if (delete_category || extra_deletion) { |
888 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
889 | return result.Succeeded(); |
890 | } else { |
891 | result.AppendErrorWithFormat("no custom formatter for %s.\n", typeA); |
892 | result.SetStatus(eReturnStatusFailed); |
893 | return false; |
894 | } |
895 | } |
896 | }; |
897 | |
898 | static OptionDefinition g_type_formatter_clear_options[] = { |
899 | |
900 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "all", 'a', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Clear every category." } |
901 | |
902 | }; |
903 | |
904 | class CommandObjectTypeFormatterClear : public CommandObjectParsed { |
905 | private: |
906 | class CommandOptions : public Options { |
907 | public: |
908 | CommandOptions() : Options() {} |
909 | |
910 | ~CommandOptions() override = default; |
911 | |
912 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
913 | ExecutionContext *execution_context) override { |
914 | Status error; |
915 | const int short_option = m_getopt_table[option_idx].val; |
916 | |
917 | switch (short_option) { |
918 | case 'a': |
919 | m_delete_all = true; |
920 | break; |
921 | default: |
922 | error.SetErrorStringWithFormat("unrecognized option '%c'", |
923 | short_option); |
924 | break; |
925 | } |
926 | |
927 | return error; |
928 | } |
929 | |
930 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
931 | m_delete_all = false; |
932 | } |
933 | |
934 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
935 | return llvm::makeArrayRef(g_type_formatter_clear_options); |
936 | } |
937 | |
938 | |
939 | bool m_delete_all; |
940 | }; |
941 | |
942 | CommandOptions m_options; |
943 | uint32_t m_formatter_kind_mask; |
944 | |
945 | Options *GetOptions() override { return &m_options; } |
946 | |
947 | public: |
948 | CommandObjectTypeFormatterClear(CommandInterpreter &interpreter, |
949 | uint32_t formatter_kind_mask, |
950 | const char *name, const char *help) |
951 | : CommandObjectParsed(interpreter, name, help, nullptr), m_options(), |
952 | m_formatter_kind_mask(formatter_kind_mask) {} |
953 | |
954 | ~CommandObjectTypeFormatterClear() override = default; |
955 | |
956 | protected: |
957 | virtual void FormatterSpecificDeletion() {} |
958 | |
959 | bool DoExecute(Args &command, CommandReturnObject &result) override { |
960 | if (m_options.m_delete_all) { |
961 | DataVisualization::Categories::ForEach( |
962 | [this](const TypeCategoryImplSP &category_sp) -> bool { |
963 | category_sp->Clear(m_formatter_kind_mask); |
964 | return true; |
965 | }); |
966 | } else { |
967 | lldb::TypeCategoryImplSP category; |
968 | if (command.GetArgumentCount() > 0) { |
969 | const char *cat_name = command.GetArgumentAtIndex(0); |
970 | ConstString cat_nameCS(cat_name); |
971 | DataVisualization::Categories::GetCategory(cat_nameCS, category); |
972 | } else { |
973 | DataVisualization::Categories::GetCategory(ConstString(nullptr), |
974 | category); |
975 | } |
976 | category->Clear(m_formatter_kind_mask); |
977 | } |
978 | |
979 | FormatterSpecificDeletion(); |
980 | |
981 | result.SetStatus(eReturnStatusSuccessFinishResult); |
982 | return result.Succeeded(); |
983 | } |
984 | }; |
985 | |
986 | |
987 | |
988 | |
989 | |
990 | class CommandObjectTypeFormatDelete : public CommandObjectTypeFormatterDelete { |
991 | public: |
992 | CommandObjectTypeFormatDelete(CommandInterpreter &interpreter) |
993 | : CommandObjectTypeFormatterDelete( |
994 | interpreter, |
995 | eFormatCategoryItemValue | eFormatCategoryItemRegexValue, |
996 | "type format delete", |
997 | "Delete an existing formatting style for a type.") {} |
998 | |
999 | ~CommandObjectTypeFormatDelete() override = default; |
1000 | }; |
1001 | |
1002 | |
1003 | |
1004 | |
1005 | |
1006 | class CommandObjectTypeFormatClear : public CommandObjectTypeFormatterClear { |
1007 | public: |
1008 | CommandObjectTypeFormatClear(CommandInterpreter &interpreter) |
1009 | : CommandObjectTypeFormatterClear( |
1010 | interpreter, |
1011 | eFormatCategoryItemValue | eFormatCategoryItemRegexValue, |
1012 | "type format clear", "Delete all existing format styles.") {} |
1013 | }; |
1014 | |
1015 | template <typename FormatterType> |
1016 | class CommandObjectTypeFormatterList : public CommandObjectParsed { |
1017 | typedef typename FormatterType::SharedPointer FormatterSharedPointer; |
1018 | |
1019 | class CommandOptions : public Options { |
1020 | public: |
1021 | CommandOptions() |
1022 | : Options(), m_category_regex("", ""), |
1023 | m_category_language(lldb::eLanguageTypeUnknown, |
1024 | lldb::eLanguageTypeUnknown) {} |
1025 | |
1026 | ~CommandOptions() override = default; |
1027 | |
1028 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
1029 | ExecutionContext *execution_context) override { |
1030 | Status error; |
1031 | const int short_option = m_getopt_table[option_idx].val; |
1032 | switch (short_option) { |
1033 | case 'w': |
1034 | m_category_regex.SetCurrentValue(option_arg); |
1035 | m_category_regex.SetOptionWasSet(); |
1036 | break; |
1037 | case 'l': |
1038 | error = m_category_language.SetValueFromString(option_arg); |
1039 | if (error.Success()) |
1040 | m_category_language.SetOptionWasSet(); |
1041 | break; |
1042 | default: |
1043 | error.SetErrorStringWithFormat("unrecognized option '%c'", |
1044 | short_option); |
1045 | break; |
1046 | } |
1047 | |
1048 | return error; |
1049 | } |
1050 | |
1051 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
1052 | m_category_regex.Clear(); |
1053 | m_category_language.Clear(); |
1054 | } |
1055 | |
1056 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
1057 | static OptionDefinition g_option_table[] = { |
1058 | |
1059 | {LLDB_OPT_SET_1(1U << 0), false, "category-regex", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Only show categories matching this filter."}, |
1060 | {LLDB_OPT_SET_2(1U << 1), false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Only show the category for a specific language."} |
1061 | |
1062 | }; |
1063 | return llvm::ArrayRef<OptionDefinition>(g_option_table); |
1064 | } |
1065 | |
1066 | |
1067 | |
1068 | OptionValueString m_category_regex; |
1069 | OptionValueLanguage m_category_language; |
1070 | }; |
1071 | |
1072 | CommandOptions m_options; |
1073 | |
1074 | Options *GetOptions() override { return &m_options; } |
1075 | |
1076 | public: |
1077 | CommandObjectTypeFormatterList(CommandInterpreter &interpreter, |
1078 | const char *name, const char *help) |
1079 | : CommandObjectParsed(interpreter, name, help, nullptr), m_options() { |
1080 | CommandArgumentEntry type_arg; |
1081 | CommandArgumentData type_style_arg; |
1082 | |
1083 | type_style_arg.arg_type = eArgTypeName; |
1084 | type_style_arg.arg_repetition = eArgRepeatOptional; |
1085 | |
1086 | type_arg.push_back(type_style_arg); |
1087 | |
1088 | m_arguments.push_back(type_arg); |
1089 | } |
1090 | |
1091 | ~CommandObjectTypeFormatterList() override = default; |
1092 | |
1093 | protected: |
1094 | virtual bool FormatterSpecificList(CommandReturnObject &result) { |
1095 | return false; |
1096 | } |
1097 | |
1098 | bool DoExecute(Args &command, CommandReturnObject &result) override { |
1099 | const size_t argc = command.GetArgumentCount(); |
1100 | |
1101 | std::unique_ptr<RegularExpression> category_regex; |
1102 | std::unique_ptr<RegularExpression> formatter_regex; |
1103 | |
1104 | if (m_options.m_category_regex.OptionWasSet()) { |
1105 | category_regex.reset(new RegularExpression()); |
1106 | if (!category_regex->Compile( |
1107 | m_options.m_category_regex.GetCurrentValueAsRef())) { |
1108 | result.AppendErrorWithFormat( |
1109 | "syntax error in category regular expression '%s'", |
1110 | m_options.m_category_regex.GetCurrentValueAsRef().str().c_str()); |
1111 | result.SetStatus(eReturnStatusFailed); |
1112 | return false; |
1113 | } |
1114 | } |
1115 | |
1116 | if (argc == 1) { |
1117 | const char *arg = command.GetArgumentAtIndex(0); |
1118 | formatter_regex.reset(new RegularExpression()); |
1119 | if (!formatter_regex->Compile(llvm::StringRef::withNullAsEmpty(arg))) { |
1120 | result.AppendErrorWithFormat("syntax error in regular expression '%s'", |
1121 | arg); |
1122 | result.SetStatus(eReturnStatusFailed); |
1123 | return false; |
1124 | } |
1125 | } |
1126 | |
1127 | bool any_printed = false; |
1128 | |
1129 | auto category_closure = [&result, &formatter_regex, &any_printed]( |
1130 | const lldb::TypeCategoryImplSP &category) -> void { |
1131 | result.GetOutputStream().Printf( |
1132 | "-----------------------\nCategory: %s%s\n-----------------------\n", |
1133 | category->GetName(), category->IsEnabled() ? "" : " (disabled)"); |
1134 | |
1135 | TypeCategoryImpl::ForEachCallbacks<FormatterType> foreach; |
1136 | foreach |
1137 | .SetExact([&result, &formatter_regex, &any_printed]( |
1138 | ConstString name, |
1139 | const FormatterSharedPointer &format_sp) -> bool { |
1140 | if (formatter_regex) { |
1141 | bool escape = true; |
1142 | if (name.GetStringRef() == formatter_regex->GetText()) { |
1143 | escape = false; |
1144 | } else if (formatter_regex->Execute(name.GetStringRef())) { |
1145 | escape = false; |
1146 | } |
1147 | |
1148 | if (escape) |
1149 | return true; |
1150 | } |
1151 | |
1152 | any_printed = true; |
1153 | result.GetOutputStream().Printf("%s: %s\n", name.AsCString(), |
1154 | format_sp->GetDescription().c_str()); |
1155 | return true; |
1156 | }); |
1157 | |
1158 | foreach |
1159 | .SetWithRegex([&result, &formatter_regex, &any_printed]( |
1160 | RegularExpressionSP regex_sp, |
1161 | const FormatterSharedPointer &format_sp) -> bool { |
1162 | if (formatter_regex) { |
1163 | bool escape = true; |
1164 | if (regex_sp->GetText() == formatter_regex->GetText()) { |
1165 | escape = false; |
1166 | } else if (formatter_regex->Execute(regex_sp->GetText())) { |
1167 | escape = false; |
1168 | } |
1169 | |
1170 | if (escape) |
1171 | return true; |
1172 | } |
1173 | |
1174 | any_printed = true; |
1175 | result.GetOutputStream().Printf("%s: %s\n", |
1176 | regex_sp->GetText().str().c_str(), |
1177 | format_sp->GetDescription().c_str()); |
1178 | return true; |
1179 | }); |
1180 | |
1181 | category->ForEach(foreach); |
1182 | }; |
1183 | |
1184 | if (m_options.m_category_language.OptionWasSet()) { |
1185 | lldb::TypeCategoryImplSP category_sp; |
1186 | DataVisualization::Categories::GetCategory( |
1187 | m_options.m_category_language.GetCurrentValue(), category_sp); |
1188 | if (category_sp) |
1189 | category_closure(category_sp); |
1190 | } else { |
1191 | DataVisualization::Categories::ForEach( |
1192 | [&category_regex, &category_closure]( |
1193 | const lldb::TypeCategoryImplSP &category) -> bool { |
1194 | if (category_regex) { |
1195 | bool escape = true; |
1196 | if (category->GetName() == category_regex->GetText()) { |
1197 | escape = false; |
1198 | } else if (category_regex->Execute( |
1199 | llvm::StringRef::withNullAsEmpty( |
1200 | category->GetName()))) { |
1201 | escape = false; |
1202 | } |
1203 | |
1204 | if (escape) |
1205 | return true; |
1206 | } |
1207 | |
1208 | category_closure(category); |
1209 | |
1210 | return true; |
1211 | }); |
1212 | |
1213 | any_printed = FormatterSpecificList(result) | any_printed; |
1214 | } |
1215 | |
1216 | if (any_printed) |
1217 | result.SetStatus(eReturnStatusSuccessFinishResult); |
1218 | else { |
1219 | result.GetOutputStream().PutCString("no matching results found.\n"); |
1220 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
1221 | } |
1222 | return result.Succeeded(); |
1223 | } |
1224 | }; |
1225 | |
1226 | |
1227 | |
1228 | |
1229 | |
1230 | class CommandObjectTypeFormatList |
1231 | : public CommandObjectTypeFormatterList<TypeFormatImpl> { |
1232 | public: |
1233 | CommandObjectTypeFormatList(CommandInterpreter &interpreter) |
1234 | : CommandObjectTypeFormatterList(interpreter, "type format list", |
1235 | "Show a list of current formats.") {} |
1236 | }; |
1237 | |
1238 | #ifndef LLDB_DISABLE_PYTHON |
1239 | |
1240 | |
1241 | |
1242 | |
1243 | |
1244 | #endif // LLDB_DISABLE_PYTHON |
1245 | |
1246 | Status CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue( |
1247 | uint32_t option_idx, llvm::StringRef option_arg, |
1248 | ExecutionContext *execution_context) { |
1249 | Status error; |
1250 | const int short_option = m_getopt_table[option_idx].val; |
1251 | bool success; |
1252 | |
1253 | switch (short_option) { |
1254 | case 'C': |
1255 | m_flags.SetCascades(Args::StringToBoolean(option_arg, true, &success)); |
1256 | if (!success) |
1257 | error.SetErrorStringWithFormat("invalid value for cascade: %s", |
1258 | option_arg.str().c_str()); |
1259 | break; |
1260 | case 'e': |
1261 | m_flags.SetDontShowChildren(false); |
1262 | break; |
1263 | case 'h': |
1264 | m_flags.SetHideEmptyAggregates(true); |
1265 | break; |
1266 | case 'v': |
1267 | m_flags.SetDontShowValue(true); |
1268 | break; |
1269 | case 'c': |
1270 | m_flags.SetShowMembersOneLiner(true); |
1271 | break; |
1272 | case 's': |
1273 | m_format_string = std::string(option_arg); |
1274 | break; |
1275 | case 'p': |
1276 | m_flags.SetSkipPointers(true); |
1277 | break; |
1278 | case 'r': |
1279 | m_flags.SetSkipReferences(true); |
1280 | break; |
1281 | case 'x': |
1282 | m_regex = true; |
1283 | break; |
1284 | case 'n': |
1285 | m_name.SetString(option_arg); |
1286 | break; |
1287 | case 'o': |
1288 | m_python_script = option_arg; |
1289 | m_is_add_script = true; |
1290 | break; |
1291 | case 'F': |
1292 | m_python_function = option_arg; |
1293 | m_is_add_script = true; |
1294 | break; |
1295 | case 'P': |
1296 | m_is_add_script = true; |
1297 | break; |
1298 | case 'w': |
1299 | m_category = std::string(option_arg); |
1300 | break; |
1301 | case 'O': |
1302 | m_flags.SetHideItemNames(true); |
1303 | break; |
1304 | default: |
1305 | error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); |
1306 | break; |
1307 | } |
1308 | |
1309 | return error; |
1310 | } |
1311 | |
1312 | void CommandObjectTypeSummaryAdd::CommandOptions::OptionParsingStarting( |
1313 | ExecutionContext *execution_context) { |
1314 | m_flags.Clear().SetCascades().SetDontShowChildren().SetDontShowValue(false); |
1315 | m_flags.SetShowMembersOneLiner(false) |
1316 | .SetSkipPointers(false) |
1317 | .SetSkipReferences(false) |
1318 | .SetHideItemNames(false); |
1319 | |
1320 | m_regex = false; |
1321 | m_name.Clear(); |
1322 | m_python_script = ""; |
1323 | m_python_function = ""; |
1324 | m_format_string = ""; |
1325 | m_is_add_script = false; |
1326 | m_category = "default"; |
1327 | } |
1328 | |
1329 | #ifndef LLDB_DISABLE_PYTHON |
1330 | |
1331 | bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary( |
1332 | Args &command, CommandReturnObject &result) { |
1333 | const size_t argc = command.GetArgumentCount(); |
1334 | |
1335 | if (argc < 1 && !m_options.m_name) { |
1336 | result.AppendErrorWithFormat("%s takes one or more args.\n", |
1337 | m_cmd_name.c_str()); |
1338 | result.SetStatus(eReturnStatusFailed); |
1339 | return false; |
1340 | } |
1341 | |
1342 | TypeSummaryImplSP script_format; |
1343 | |
1344 | if (!m_options.m_python_function |
1345 | .empty()) |
1346 | { |
1347 | const char *funct_name = m_options.m_python_function.c_str(); |
1348 | if (!funct_name || !funct_name[0]) { |
1349 | result.AppendError("function name empty.\n"); |
1350 | result.SetStatus(eReturnStatusFailed); |
1351 | return false; |
1352 | } |
1353 | |
1354 | std::string code = |
1355 | (" " + m_options.m_python_function + "(valobj,internal_dict)"); |
1356 | |
1357 | script_format.reset( |
1358 | new ScriptSummaryFormat(m_options.m_flags, funct_name, code.c_str())); |
1359 | |
1360 | ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); |
1361 | |
1362 | if (interpreter && !interpreter->CheckObjectExists(funct_name)) |
1363 | result.AppendWarningWithFormat( |
1364 | "The provided function \"%s\" does not exist - " |
1365 | "please define it before attempting to use this summary.\n", |
1366 | funct_name); |
1367 | } else if (!m_options.m_python_script |
1368 | .empty()) |
1369 | { |
1370 | ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); |
1371 | if (!interpreter) { |
1372 | result.AppendError("script interpreter missing - unable to generate " |
1373 | "function wrapper.\n"); |
1374 | result.SetStatus(eReturnStatusFailed); |
1375 | return false; |
1376 | } |
1377 | StringList funct_sl; |
1378 | funct_sl << m_options.m_python_script.c_str(); |
1379 | std::string funct_name_str; |
1380 | if (!interpreter->GenerateTypeScriptFunction(funct_sl, funct_name_str)) { |
1381 | result.AppendError("unable to generate function wrapper.\n"); |
1382 | result.SetStatus(eReturnStatusFailed); |
1383 | return false; |
1384 | } |
1385 | if (funct_name_str.empty()) { |
1386 | result.AppendError( |
1387 | "script interpreter failed to generate a valid function name.\n"); |
1388 | result.SetStatus(eReturnStatusFailed); |
1389 | return false; |
1390 | } |
1391 | |
1392 | std::string code = " " + m_options.m_python_script; |
1393 | |
1394 | script_format.reset(new ScriptSummaryFormat( |
1395 | m_options.m_flags, funct_name_str.c_str(), code.c_str())); |
1396 | } else { |
1397 | |
1398 | ScriptAddOptions *options = |
1399 | new ScriptAddOptions(m_options.m_flags, m_options.m_regex, |
1400 | m_options.m_name, m_options.m_category); |
1401 | |
1402 | for (auto &entry : command.entries()) { |
1403 | if (entry.ref.empty()) { |
1404 | result.AppendError("empty typenames not allowed"); |
1405 | result.SetStatus(eReturnStatusFailed); |
1406 | return false; |
1407 | } |
1408 | |
1409 | options->m_target_types << entry.ref; |
1410 | } |
1411 | |
1412 | m_interpreter.GetPythonCommandsFromIOHandler( |
1413 | " ", |
1414 | *this, |
1415 | true, |
1416 | options); |
1417 | |
1418 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
1419 | |
1420 | return result.Succeeded(); |
1421 | } |
1422 | |
1423 | |
1424 | |
1425 | |
1426 | Status error; |
1427 | |
1428 | for (auto &entry : command.entries()) { |
1429 | CommandObjectTypeSummaryAdd::AddSummary( |
1430 | ConstString(entry.ref), script_format, |
1431 | (m_options.m_regex ? eRegexSummary : eRegularSummary), |
1432 | m_options.m_category, &error); |
1433 | if (error.Fail()) { |
1434 | result.AppendError(error.AsCString()); |
1435 | result.SetStatus(eReturnStatusFailed); |
1436 | return false; |
1437 | } |
1438 | } |
1439 | |
1440 | if (m_options.m_name) { |
1441 | AddSummary(m_options.m_name, script_format, eNamedSummary, |
1442 | m_options.m_category, &error); |
1443 | if (error.Fail()) { |
1444 | result.AppendError(error.AsCString()); |
1445 | result.AppendError("added to types, but not given a name"); |
1446 | result.SetStatus(eReturnStatusFailed); |
1447 | return false; |
1448 | } |
1449 | } |
1450 | |
1451 | return result.Succeeded(); |
1452 | } |
1453 | |
1454 | #endif // LLDB_DISABLE_PYTHON |
1455 | |
1456 | bool CommandObjectTypeSummaryAdd::Execute_StringSummary( |
1457 | Args &command, CommandReturnObject &result) { |
1458 | const size_t argc = command.GetArgumentCount(); |
1459 | |
1460 | if (argc < 1 && !m_options.m_name) { |
1461 | result.AppendErrorWithFormat("%s takes one or more args.\n", |
1462 | m_cmd_name.c_str()); |
1463 | result.SetStatus(eReturnStatusFailed); |
1464 | return false; |
1465 | } |
1466 | |
1467 | if (!m_options.m_flags.GetShowMembersOneLiner() && |
1468 | m_options.m_format_string.empty()) { |
1469 | result.AppendError("empty summary strings not allowed"); |
1470 | result.SetStatus(eReturnStatusFailed); |
1471 | return false; |
1472 | } |
1473 | |
1474 | const char *format_cstr = (m_options.m_flags.GetShowMembersOneLiner() |
1475 | ? "" |
1476 | : m_options.m_format_string.c_str()); |
1477 | |
1478 | |
1479 | if (strcmp(format_cstr, "${var%S}") == 0) { |
1480 | result.AppendError("recursive summary not allowed"); |
1481 | result.SetStatus(eReturnStatusFailed); |
1482 | return false; |
1483 | } |
1484 | |
1485 | std::unique_ptr<StringSummaryFormat> string_format( |
1486 | new StringSummaryFormat(m_options.m_flags, format_cstr)); |
1487 | if (!string_format) { |
1488 | result.AppendError("summary creation failed"); |
1489 | result.SetStatus(eReturnStatusFailed); |
1490 | return false; |
1491 | } |
1492 | if (string_format->m_error.Fail()) { |
1493 | result.AppendErrorWithFormat("syntax error: %s", |
1494 | string_format->m_error.AsCString("<unknown>")); |
1495 | result.SetStatus(eReturnStatusFailed); |
1496 | return false; |
1497 | } |
1498 | lldb::TypeSummaryImplSP entry(string_format.release()); |
1499 | |
1500 | |
1501 | Status error; |
1502 | for (auto &arg_entry : command.entries()) { |
1503 | if (arg_entry.ref.empty()) { |
1504 | result.AppendError("empty typenames not allowed"); |
1505 | result.SetStatus(eReturnStatusFailed); |
1506 | return false; |
1507 | } |
1508 | ConstString typeCS(arg_entry.ref); |
1509 | |
1510 | AddSummary(typeCS, entry, |
1511 | (m_options.m_regex ? eRegexSummary : eRegularSummary), |
1512 | m_options.m_category, &error); |
1513 | |
1514 | if (error.Fail()) { |
1515 | result.AppendError(error.AsCString()); |
1516 | result.SetStatus(eReturnStatusFailed); |
1517 | return false; |
1518 | } |
1519 | } |
1520 | |
1521 | if (m_options.m_name) { |
1522 | AddSummary(m_options.m_name, entry, eNamedSummary, m_options.m_category, |
1523 | &error); |
1524 | if (error.Fail()) { |
1525 | result.AppendError(error.AsCString()); |
1526 | result.AppendError("added to types, but not given a name"); |
1527 | result.SetStatus(eReturnStatusFailed); |
1528 | return false; |
1529 | } |
1530 | } |
1531 | |
1532 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
1533 | return result.Succeeded(); |
1534 | } |
1535 | |
1536 | CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd( |
1537 | CommandInterpreter &interpreter) |
1538 | : CommandObjectParsed(interpreter, "type summary add", |
1539 | "Add a new summary style for a type.", nullptr), |
1540 | IOHandlerDelegateMultiline("DONE"), m_options(interpreter) { |
1541 | CommandArgumentEntry type_arg; |
1542 | CommandArgumentData type_style_arg; |
1543 | |
1544 | type_style_arg.arg_type = eArgTypeName; |
1545 | type_style_arg.arg_repetition = eArgRepeatPlus; |
1546 | |
1547 | type_arg.push_back(type_style_arg); |
1548 | |
1549 | m_arguments.push_back(type_arg); |
1550 | |
1551 | SetHelpLong( |
1552 | R"( |
1553 | The following examples of 'type summary add' refer to this code snippet for context: |
1554 | |
1555 | struct JustADemo |
1556 | { |
1557 | int* ptr; |
1558 | float value; |
1559 | JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {} |
1560 | }; |
1561 | JustADemo demo_instance(42, 3.14); |
1562 | |
1563 | typedef JustADemo NewDemo; |
1564 | NewDemo new_demo_instance(42, 3.14); |
1565 | |
1566 | (lldb) type summary add --summary-string "the answer is ${*var.ptr}" JustADemo |
1567 | |
1568 | Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42" |
1569 | |
1570 | (lldb) type summary add --summary-string "the answer is ${*var.ptr}, and the question is ${var.value}" JustADemo |
1571 | |
1572 | Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42 and the question is 3.14" |
1573 | |
1574 | )" |
1575 | "Alternatively, you could define formatting for all pointers to integers and \ |
1576 | rely on that when formatting JustADemo to obtain the same result:" |
1577 | R"( |
1578 | |
1579 | (lldb) type summary add --summary-string "${var%V} -> ${*var}" "int *" |
1580 | (lldb) type summary add --summary-string "the answer is ${var.ptr}, and the question is ${var.value}" JustADemo |
1581 | |
1582 | )" |
1583 | "Type summaries are automatically applied to derived typedefs, so the examples \ |
1584 | above apply to both JustADemo and NewDemo. The cascade option can be used to \ |
1585 | suppress this behavior:" |
1586 | R"( |
1587 | |
1588 | (lldb) type summary add --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo -C no |
1589 | |
1590 | The summary will now be used for values of JustADemo but not NewDemo. |
1591 | |
1592 | )" |
1593 | "By default summaries are shown for pointers and references to values of the \ |
1594 | specified type. To suppress formatting for pointers use the -p option, or apply \ |
1595 | the corresponding -r option to suppress formatting for references:" |
1596 | R"( |
1597 | |
1598 | (lldb) type summary add -p -r --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo |
1599 | |
1600 | )" |
1601 | "One-line summaries including all fields in a type can be inferred without supplying an \ |
1602 | explicit summary string by passing the -c option:" |
1603 | R"( |
1604 | |
1605 | (lldb) type summary add -c JustADemo |
1606 | (lldb) frame variable demo_instance |
1607 | (ptr=<address>, value=3.14) |
1608 | |
1609 | )" |
1610 | "Type summaries normally suppress the nested display of individual fields. To \ |
1611 | supply a summary to supplement the default structure add the -e option:" |
1612 | R"( |
1613 | |
1614 | (lldb) type summary add -e --summary-string "*ptr = ${*var.ptr}" JustADemo |
1615 | |
1616 | )" |
1617 | "Now when displaying JustADemo values the int* is displayed, followed by the \ |
1618 | standard LLDB sequence of children, one per line:" |
1619 | R"( |
1620 | |
1621 | *ptr = 42 { |
1622 | ptr = <address> |
1623 | value = 3.14 |
1624 | } |
1625 | |
1626 | )" |
1627 | "You can also add summaries written in Python. These scripts use lldb public API to \ |
1628 | gather information from your variables and produce a meaningful summary. To start a \ |
1629 | multi-line script use the -P option. The function declaration will be displayed along with \ |
1630 | a comment describing the two arguments. End your script with the word 'DONE' on a line by \ |
1631 | itself:" |
1632 | R"( |
1633 | |
1634 | (lldb) type summary add JustADemo -P |
1635 | def function (valobj,internal_dict): |
1636 | """valobj: an SBValue which you want to provide a summary for |
1637 | internal_dict: an LLDB support object not to be used""" |
1638 | value = valobj.GetChildMemberWithName('value'); |
1639 | return 'My value is ' + value.GetValue(); |
1640 | DONE |
1641 | |
1642 | Alternatively, the -o option can be used when providing a simple one-line Python script: |
1643 | |
1644 | (lldb) type summary add JustADemo -o "value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();")"); |
1645 | } |
1646 | |
1647 | bool CommandObjectTypeSummaryAdd::DoExecute(Args &command, |
1648 | CommandReturnObject &result) { |
1649 | WarnOnPotentialUnquotedUnsignedType(command, result); |
1650 | |
1651 | if (m_options.m_is_add_script) { |
1652 | #ifndef LLDB_DISABLE_PYTHON |
1653 | return Execute_ScriptSummary(command, result); |
1654 | #else |
1655 | result.AppendError("python is disabled"); |
1656 | result.SetStatus(eReturnStatusFailed); |
1657 | return false; |
1658 | #endif // LLDB_DISABLE_PYTHON |
1659 | } |
1660 | |
1661 | return Execute_StringSummary(command, result); |
1662 | } |
1663 | |
1664 | static bool FixArrayTypeNameWithRegex(ConstString &type_name) { |
1665 | llvm::StringRef type_name_ref(type_name.GetStringRef()); |
1666 | |
1667 | if (type_name_ref.endswith("[]")) { |
1668 | std::string type_name_str(type_name.GetCString()); |
1669 | type_name_str.resize(type_name_str.length() - 2); |
1670 | if (type_name_str.back() != ' ') |
1671 | type_name_str.append(" \\[[0-9]+\\]"); |
1672 | else |
1673 | type_name_str.append("\\[[0-9]+\\]"); |
1674 | type_name.SetCString(type_name_str.c_str()); |
1675 | return true; |
1676 | } |
1677 | return false; |
1678 | } |
1679 | |
1680 | bool CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name, |
1681 | TypeSummaryImplSP entry, |
1682 | SummaryFormatType type, |
1683 | std::string category_name, |
1684 | Status *error) { |
1685 | lldb::TypeCategoryImplSP category; |
1686 | DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()), |
1687 | category); |
1688 | |
1689 | if (type == eRegularSummary) { |
1690 | if (FixArrayTypeNameWithRegex(type_name)) |
1691 | type = eRegexSummary; |
1692 | } |
1693 | |
1694 | if (type == eRegexSummary) { |
1695 | RegularExpressionSP typeRX(new RegularExpression()); |
1696 | if (!typeRX->Compile(type_name.GetStringRef())) { |
1697 | if (error) |
1698 | error->SetErrorString( |
1699 | "regex format error (maybe this is not really a regex?)"); |
1700 | return false; |
1701 | } |
1702 | |
1703 | category->GetRegexTypeSummariesContainer()->Delete(type_name); |
1704 | category->GetRegexTypeSummariesContainer()->Add(typeRX, entry); |
1705 | |
1706 | return true; |
1707 | } else if (type == eNamedSummary) { |
1708 | |
1709 | DataVisualization::NamedSummaryFormats::Add(type_name, entry); |
1710 | return true; |
1711 | } else { |
1712 | category->GetTypeSummariesContainer()->Add(type_name, entry); |
1713 | return true; |
1714 | } |
1715 | } |
1716 | |
1717 | |
1718 | |
1719 | |
1720 | |
1721 | class CommandObjectTypeSummaryDelete : public CommandObjectTypeFormatterDelete { |
1722 | public: |
1723 | CommandObjectTypeSummaryDelete(CommandInterpreter &interpreter) |
1724 | : CommandObjectTypeFormatterDelete( |
1725 | interpreter, |
1726 | eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary, |
1727 | "type summary delete", "Delete an existing summary for a type.") {} |
1728 | |
1729 | ~CommandObjectTypeSummaryDelete() override = default; |
1730 | |
1731 | protected: |
1732 | bool FormatterSpecificDeletion(ConstString typeCS) override { |
1733 | if (m_options.m_language != lldb::eLanguageTypeUnknown) |
1734 | return false; |
1735 | return DataVisualization::NamedSummaryFormats::Delete(typeCS); |
1736 | } |
1737 | }; |
1738 | |
1739 | class CommandObjectTypeSummaryClear : public CommandObjectTypeFormatterClear { |
1740 | public: |
1741 | CommandObjectTypeSummaryClear(CommandInterpreter &interpreter) |
1742 | : CommandObjectTypeFormatterClear( |
1743 | interpreter, |
1744 | eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary, |
1745 | "type summary clear", "Delete all existing summaries.") {} |
1746 | |
1747 | protected: |
1748 | void FormatterSpecificDeletion() override { |
1749 | DataVisualization::NamedSummaryFormats::Clear(); |
1750 | } |
1751 | }; |
1752 | |
1753 | |
1754 | |
1755 | |
1756 | |
1757 | class CommandObjectTypeSummaryList |
1758 | : public CommandObjectTypeFormatterList<TypeSummaryImpl> { |
1759 | public: |
1760 | CommandObjectTypeSummaryList(CommandInterpreter &interpreter) |
1761 | : CommandObjectTypeFormatterList(interpreter, "type summary list", |
1762 | "Show a list of current summaries.") {} |
1763 | |
1764 | protected: |
1765 | bool FormatterSpecificList(CommandReturnObject &result) override { |
1766 | if (DataVisualization::NamedSummaryFormats::GetCount() > 0) { |
1767 | result.GetOutputStream().Printf("Named summaries:\n"); |
1768 | DataVisualization::NamedSummaryFormats::ForEach( |
1769 | [&result](ConstString name, |
1770 | const TypeSummaryImplSP &summary_sp) -> bool { |
1771 | result.GetOutputStream().Printf( |
1772 | "%s: %s\n", name.AsCString(), |
1773 | summary_sp->GetDescription().c_str()); |
1774 | return true; |
1775 | }); |
1776 | return true; |
1777 | } |
1778 | return false; |
1779 | } |
1780 | }; |
1781 | |
1782 | |
1783 | |
1784 | |
1785 | |
1786 | static OptionDefinition g_type_category_define_options[] = { |
1787 | |
1788 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "enabled", 'e', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "If specified, this category will be created enabled." }, |
1789 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Specify the language that this category is supported for." } |
1790 | |
1791 | }; |
1792 | |
1793 | class CommandObjectTypeCategoryDefine : public CommandObjectParsed { |
1794 | class CommandOptions : public Options { |
1795 | public: |
1796 | CommandOptions() |
1797 | : Options(), m_define_enabled(false, false), |
1798 | m_cate_language(eLanguageTypeUnknown, eLanguageTypeUnknown) {} |
1799 | |
1800 | ~CommandOptions() override = default; |
1801 | |
1802 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
1803 | ExecutionContext *execution_context) override { |
1804 | Status error; |
1805 | const int short_option = m_getopt_table[option_idx].val; |
1806 | |
1807 | switch (short_option) { |
1808 | case 'e': |
1809 | m_define_enabled.SetValueFromString(llvm::StringRef("true")); |
1810 | break; |
1811 | case 'l': |
1812 | error = m_cate_language.SetValueFromString(option_arg); |
1813 | break; |
1814 | default: |
1815 | error.SetErrorStringWithFormat("unrecognized option '%c'", |
1816 | short_option); |
1817 | break; |
1818 | } |
1819 | |
1820 | return error; |
1821 | } |
1822 | |
1823 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
1824 | m_define_enabled.Clear(); |
1825 | m_cate_language.Clear(); |
1826 | } |
1827 | |
1828 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
1829 | return llvm::makeArrayRef(g_type_category_define_options); |
1830 | } |
1831 | |
1832 | |
1833 | |
1834 | OptionValueBoolean m_define_enabled; |
1835 | OptionValueLanguage m_cate_language; |
1836 | }; |
1837 | |
1838 | CommandOptions m_options; |
1839 | |
1840 | Options *GetOptions() override { return &m_options; } |
1841 | |
1842 | public: |
1843 | CommandObjectTypeCategoryDefine(CommandInterpreter &interpreter) |
1844 | : CommandObjectParsed(interpreter, "type category define", |
1845 | "Define a new category as a source of formatters.", |
1846 | nullptr), |
1847 | m_options() { |
1848 | CommandArgumentEntry type_arg; |
1849 | CommandArgumentData type_style_arg; |
1850 | |
1851 | type_style_arg.arg_type = eArgTypeName; |
1852 | type_style_arg.arg_repetition = eArgRepeatPlus; |
1853 | |
1854 | type_arg.push_back(type_style_arg); |
1855 | |
1856 | m_arguments.push_back(type_arg); |
1857 | } |
1858 | |
1859 | ~CommandObjectTypeCategoryDefine() override = default; |
1860 | |
1861 | protected: |
1862 | bool DoExecute(Args &command, CommandReturnObject &result) override { |
1863 | const size_t argc = command.GetArgumentCount(); |
1864 | |
1865 | if (argc < 1) { |
1866 | result.AppendErrorWithFormat("%s takes 1 or more args.\n", |
1867 | m_cmd_name.c_str()); |
1868 | result.SetStatus(eReturnStatusFailed); |
1869 | return false; |
1870 | } |
1871 | |
1872 | for (auto &entry : command.entries()) { |
1873 | TypeCategoryImplSP category_sp; |
1874 | if (DataVisualization::Categories::GetCategory(ConstString(entry.ref), |
1875 | category_sp) && |
1876 | category_sp) { |
1877 | category_sp->AddLanguage(m_options.m_cate_language.GetCurrentValue()); |
1878 | if (m_options.m_define_enabled.GetCurrentValue()) |
1879 | DataVisualization::Categories::Enable(category_sp, |
1880 | TypeCategoryMap::Default); |
1881 | } |
1882 | } |
1883 | |
1884 | result.SetStatus(eReturnStatusSuccessFinishResult); |
1885 | return result.Succeeded(); |
1886 | } |
1887 | }; |
1888 | |
1889 | |
1890 | |
1891 | |
1892 | |
1893 | static OptionDefinition g_type_category_enable_options[] = { |
1894 | |
1895 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Enable the category for this language." }, |
1896 | |
1897 | }; |
1898 | |
1899 | class CommandObjectTypeCategoryEnable : public CommandObjectParsed { |
1900 | class CommandOptions : public Options { |
1901 | public: |
1902 | CommandOptions() : Options() {} |
1903 | |
1904 | ~CommandOptions() override = default; |
1905 | |
1906 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
1907 | ExecutionContext *execution_context) override { |
1908 | Status error; |
1909 | const int short_option = m_getopt_table[option_idx].val; |
1910 | |
1911 | switch (short_option) { |
1912 | case 'l': |
1913 | if (!option_arg.empty()) { |
1914 | m_language = Language::GetLanguageTypeFromString(option_arg); |
1915 | if (m_language == lldb::eLanguageTypeUnknown) |
1916 | error.SetErrorStringWithFormat("unrecognized language '%s'", |
1917 | option_arg.str().c_str()); |
1918 | } |
1919 | break; |
1920 | default: |
1921 | error.SetErrorStringWithFormat("unrecognized option '%c'", |
1922 | short_option); |
1923 | break; |
1924 | } |
1925 | |
1926 | return error; |
1927 | } |
1928 | |
1929 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
1930 | m_language = lldb::eLanguageTypeUnknown; |
1931 | } |
1932 | |
1933 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
1934 | return llvm::makeArrayRef(g_type_category_enable_options); |
1935 | } |
1936 | |
1937 | |
1938 | |
1939 | lldb::LanguageType m_language; |
1940 | }; |
1941 | |
1942 | CommandOptions m_options; |
1943 | |
1944 | Options *GetOptions() override { return &m_options; } |
1945 | |
1946 | public: |
1947 | CommandObjectTypeCategoryEnable(CommandInterpreter &interpreter) |
1948 | : CommandObjectParsed(interpreter, "type category enable", |
1949 | "Enable a category as a source of formatters.", |
1950 | nullptr), |
1951 | m_options() { |
1952 | CommandArgumentEntry type_arg; |
1953 | CommandArgumentData type_style_arg; |
1954 | |
1955 | type_style_arg.arg_type = eArgTypeName; |
1956 | type_style_arg.arg_repetition = eArgRepeatPlus; |
1957 | |
1958 | type_arg.push_back(type_style_arg); |
1959 | |
1960 | m_arguments.push_back(type_arg); |
1961 | } |
1962 | |
1963 | ~CommandObjectTypeCategoryEnable() override = default; |
1964 | |
1965 | protected: |
1966 | bool DoExecute(Args &command, CommandReturnObject &result) override { |
1967 | const size_t argc = command.GetArgumentCount(); |
1968 | |
1969 | if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) { |
1970 | result.AppendErrorWithFormat("%s takes arguments and/or a language", |
1971 | m_cmd_name.c_str()); |
1972 | result.SetStatus(eReturnStatusFailed); |
1973 | return false; |
1974 | } |
1975 | |
1976 | if (argc == 1 && strcmp(command.GetArgumentAtIndex(0), "*") == 0) { |
1977 | DataVisualization::Categories::EnableStar(); |
1978 | } else if (argc > 0) { |
1979 | for (int i = argc - 1; i >= 0; i--) { |
1980 | const char *typeA = command.GetArgumentAtIndex(i); |
1981 | ConstString typeCS(typeA); |
1982 | |
1983 | if (!typeCS) { |
1984 | result.AppendError("empty category name not allowed"); |
1985 | result.SetStatus(eReturnStatusFailed); |
1986 | return false; |
1987 | } |
1988 | DataVisualization::Categories::Enable(typeCS); |
1989 | lldb::TypeCategoryImplSP cate; |
1990 | if (DataVisualization::Categories::GetCategory(typeCS, cate) && cate) { |
1991 | if (cate->GetCount() == 0) { |
1992 | result.AppendWarning("empty category enabled (typo?)"); |
1993 | } |
1994 | } |
1995 | } |
1996 | } |
1997 | |
1998 | if (m_options.m_language != lldb::eLanguageTypeUnknown) |
1999 | DataVisualization::Categories::Enable(m_options.m_language); |
2000 | |
2001 | result.SetStatus(eReturnStatusSuccessFinishResult); |
2002 | return result.Succeeded(); |
2003 | } |
2004 | }; |
2005 | |
2006 | |
2007 | |
2008 | |
2009 | |
2010 | class CommandObjectTypeCategoryDelete : public CommandObjectParsed { |
2011 | public: |
2012 | CommandObjectTypeCategoryDelete(CommandInterpreter &interpreter) |
2013 | : CommandObjectParsed(interpreter, "type category delete", |
2014 | "Delete a category and all associated formatters.", |
2015 | nullptr) { |
2016 | CommandArgumentEntry type_arg; |
2017 | CommandArgumentData type_style_arg; |
2018 | |
2019 | type_style_arg.arg_type = eArgTypeName; |
2020 | type_style_arg.arg_repetition = eArgRepeatPlus; |
2021 | |
2022 | type_arg.push_back(type_style_arg); |
2023 | |
2024 | m_arguments.push_back(type_arg); |
2025 | } |
2026 | |
2027 | ~CommandObjectTypeCategoryDelete() override = default; |
2028 | |
2029 | protected: |
2030 | bool DoExecute(Args &command, CommandReturnObject &result) override { |
2031 | const size_t argc = command.GetArgumentCount(); |
2032 | |
2033 | if (argc < 1) { |
2034 | result.AppendErrorWithFormat("%s takes 1 or more arg.\n", |
2035 | m_cmd_name.c_str()); |
2036 | result.SetStatus(eReturnStatusFailed); |
2037 | return false; |
2038 | } |
2039 | |
2040 | bool success = true; |
2041 | |
2042 | |
2043 | for (int i = argc - 1; i >= 0; i--) { |
2044 | const char *typeA = command.GetArgumentAtIndex(i); |
2045 | ConstString typeCS(typeA); |
2046 | |
2047 | if (!typeCS) { |
2048 | result.AppendError("empty category name not allowed"); |
2049 | result.SetStatus(eReturnStatusFailed); |
2050 | return false; |
2051 | } |
2052 | if (!DataVisualization::Categories::Delete(typeCS)) |
2053 | success = false; |
2054 | } |
2055 | if (success) { |
2056 | result.SetStatus(eReturnStatusSuccessFinishResult); |
2057 | return result.Succeeded(); |
2058 | } else { |
2059 | result.AppendError("cannot delete one or more categories\n"); |
2060 | result.SetStatus(eReturnStatusFailed); |
2061 | return false; |
2062 | } |
2063 | } |
2064 | }; |
2065 | |
2066 | |
2067 | |
2068 | |
2069 | |
2070 | OptionDefinition g_type_category_disable_options[] = { |
2071 | |
2072 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Enable the category for this language." } |
2073 | |
2074 | }; |
2075 | |
2076 | class CommandObjectTypeCategoryDisable : public CommandObjectParsed { |
2077 | class CommandOptions : public Options { |
2078 | public: |
2079 | CommandOptions() : Options() {} |
2080 | |
2081 | ~CommandOptions() override = default; |
2082 | |
2083 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
2084 | ExecutionContext *execution_context) override { |
2085 | Status error; |
2086 | const int short_option = m_getopt_table[option_idx].val; |
2087 | |
2088 | switch (short_option) { |
2089 | case 'l': |
2090 | if (!option_arg.empty()) { |
2091 | m_language = Language::GetLanguageTypeFromString(option_arg); |
2092 | if (m_language == lldb::eLanguageTypeUnknown) |
2093 | error.SetErrorStringWithFormat("unrecognized language '%s'", |
2094 | option_arg.str().c_str()); |
2095 | } |
2096 | break; |
2097 | default: |
2098 | error.SetErrorStringWithFormat("unrecognized option '%c'", |
2099 | short_option); |
2100 | break; |
2101 | } |
2102 | |
2103 | return error; |
2104 | } |
2105 | |
2106 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
2107 | m_language = lldb::eLanguageTypeUnknown; |
2108 | } |
2109 | |
2110 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
2111 | return llvm::makeArrayRef(g_type_category_disable_options); |
2112 | } |
2113 | |
2114 | |
2115 | |
2116 | lldb::LanguageType m_language; |
2117 | }; |
2118 | |
2119 | CommandOptions m_options; |
2120 | |
2121 | Options *GetOptions() override { return &m_options; } |
2122 | |
2123 | public: |
2124 | CommandObjectTypeCategoryDisable(CommandInterpreter &interpreter) |
2125 | : CommandObjectParsed(interpreter, "type category disable", |
2126 | "Disable a category as a source of formatters.", |
2127 | nullptr), |
2128 | m_options() { |
2129 | CommandArgumentEntry type_arg; |
2130 | CommandArgumentData type_style_arg; |
2131 | |
2132 | type_style_arg.arg_type = eArgTypeName; |
2133 | type_style_arg.arg_repetition = eArgRepeatPlus; |
2134 | |
2135 | type_arg.push_back(type_style_arg); |
2136 | |
2137 | m_arguments.push_back(type_arg); |
2138 | } |
2139 | |
2140 | ~CommandObjectTypeCategoryDisable() override = default; |
2141 | |
2142 | protected: |
2143 | bool DoExecute(Args &command, CommandReturnObject &result) override { |
2144 | const size_t argc = command.GetArgumentCount(); |
2145 | |
2146 | if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) { |
2147 | result.AppendErrorWithFormat("%s takes arguments and/or a language", |
2148 | m_cmd_name.c_str()); |
2149 | result.SetStatus(eReturnStatusFailed); |
2150 | return false; |
2151 | } |
2152 | |
2153 | if (argc == 1 && strcmp(command.GetArgumentAtIndex(0), "*") == 0) { |
2154 | DataVisualization::Categories::DisableStar(); |
2155 | } else if (argc > 0) { |
2156 | |
2157 | for (int i = argc - 1; i >= 0; i--) { |
2158 | const char *typeA = command.GetArgumentAtIndex(i); |
2159 | ConstString typeCS(typeA); |
2160 | |
2161 | if (!typeCS) { |
2162 | result.AppendError("empty category name not allowed"); |
2163 | result.SetStatus(eReturnStatusFailed); |
2164 | return false; |
2165 | } |
2166 | DataVisualization::Categories::Disable(typeCS); |
2167 | } |
2168 | } |
2169 | |
2170 | if (m_options.m_language != lldb::eLanguageTypeUnknown) |
2171 | DataVisualization::Categories::Disable(m_options.m_language); |
2172 | |
2173 | result.SetStatus(eReturnStatusSuccessFinishResult); |
2174 | return result.Succeeded(); |
2175 | } |
2176 | }; |
2177 | |
2178 | |
2179 | |
2180 | |
2181 | |
2182 | class CommandObjectTypeCategoryList : public CommandObjectParsed { |
2183 | public: |
2184 | CommandObjectTypeCategoryList(CommandInterpreter &interpreter) |
2185 | : CommandObjectParsed(interpreter, "type category list", |
2186 | "Provide a list of all existing categories.", |
2187 | nullptr) { |
2188 | CommandArgumentEntry type_arg; |
2189 | CommandArgumentData type_style_arg; |
2190 | |
2191 | type_style_arg.arg_type = eArgTypeName; |
2192 | type_style_arg.arg_repetition = eArgRepeatOptional; |
2193 | |
2194 | type_arg.push_back(type_style_arg); |
2195 | |
2196 | m_arguments.push_back(type_arg); |
2197 | } |
2198 | |
2199 | ~CommandObjectTypeCategoryList() override = default; |
2200 | |
2201 | protected: |
2202 | bool DoExecute(Args &command, CommandReturnObject &result) override { |
2203 | const size_t argc = command.GetArgumentCount(); |
2204 | |
2205 | std::unique_ptr<RegularExpression> regex; |
2206 | |
2207 | if (argc == 1) { |
2208 | regex.reset(new RegularExpression()); |
2209 | const char *arg = command.GetArgumentAtIndex(0); |
2210 | if (!regex->Compile(llvm::StringRef::withNullAsEmpty(arg))) { |
2211 | result.AppendErrorWithFormat( |
2212 | "syntax error in category regular expression '%s'", arg); |
2213 | result.SetStatus(eReturnStatusFailed); |
2214 | return false; |
2215 | } |
2216 | } else if (argc != 0) { |
2217 | result.AppendErrorWithFormat("%s takes 0 or one arg.\n", |
2218 | m_cmd_name.c_str()); |
2219 | result.SetStatus(eReturnStatusFailed); |
2220 | return false; |
2221 | } |
2222 | |
2223 | DataVisualization::Categories::ForEach( |
2224 | [®ex, &result](const lldb::TypeCategoryImplSP &category_sp) -> bool { |
2225 | if (regex) { |
2226 | bool escape = true; |
2227 | if (regex->GetText() == category_sp->GetName()) { |
2228 | escape = false; |
2229 | } else if (regex->Execute(llvm::StringRef::withNullAsEmpty( |
2230 | category_sp->GetName()))) { |
2231 | escape = false; |
2232 | } |
2233 | |
2234 | if (escape) |
2235 | return true; |
2236 | } |
2237 | |
2238 | result.GetOutputStream().Printf( |
2239 | "Category: %s\n", category_sp->GetDescription().c_str()); |
2240 | |
2241 | return true; |
2242 | }); |
2243 | |
2244 | result.SetStatus(eReturnStatusSuccessFinishResult); |
2245 | return result.Succeeded(); |
2246 | } |
2247 | }; |
2248 | |
2249 | |
2250 | |
2251 | |
2252 | |
2253 | class CommandObjectTypeFilterList |
2254 | : public CommandObjectTypeFormatterList<TypeFilterImpl> { |
2255 | public: |
2256 | CommandObjectTypeFilterList(CommandInterpreter &interpreter) |
2257 | : CommandObjectTypeFormatterList(interpreter, "type filter list", |
2258 | "Show a list of current filters.") {} |
2259 | }; |
2260 | |
2261 | #ifndef LLDB_DISABLE_PYTHON |
2262 | |
2263 | |
2264 | |
2265 | |
2266 | |
2267 | class CommandObjectTypeSynthList |
2268 | : public CommandObjectTypeFormatterList<SyntheticChildren> { |
2269 | public: |
2270 | CommandObjectTypeSynthList(CommandInterpreter &interpreter) |
2271 | : CommandObjectTypeFormatterList( |
2272 | interpreter, "type synthetic list", |
2273 | "Show a list of current synthetic providers.") {} |
2274 | }; |
2275 | |
2276 | #endif // LLDB_DISABLE_PYTHON |
2277 | |
2278 | |
2279 | |
2280 | |
2281 | |
2282 | class CommandObjectTypeFilterDelete : public CommandObjectTypeFormatterDelete { |
2283 | public: |
2284 | CommandObjectTypeFilterDelete(CommandInterpreter &interpreter) |
2285 | : CommandObjectTypeFormatterDelete( |
2286 | interpreter, |
2287 | eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter, |
2288 | "type filter delete", "Delete an existing filter for a type.") {} |
2289 | |
2290 | ~CommandObjectTypeFilterDelete() override = default; |
2291 | }; |
2292 | |
2293 | #ifndef LLDB_DISABLE_PYTHON |
2294 | |
2295 | |
2296 | |
2297 | |
2298 | |
2299 | class CommandObjectTypeSynthDelete : public CommandObjectTypeFormatterDelete { |
2300 | public: |
2301 | CommandObjectTypeSynthDelete(CommandInterpreter &interpreter) |
2302 | : CommandObjectTypeFormatterDelete( |
2303 | interpreter, |
2304 | eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth, |
2305 | "type synthetic delete", |
2306 | "Delete an existing synthetic provider for a type.") {} |
2307 | |
2308 | ~CommandObjectTypeSynthDelete() override = default; |
2309 | }; |
2310 | |
2311 | #endif // LLDB_DISABLE_PYTHON |
2312 | |
2313 | |
2314 | |
2315 | |
2316 | |
2317 | class CommandObjectTypeFilterClear : public CommandObjectTypeFormatterClear { |
2318 | public: |
2319 | CommandObjectTypeFilterClear(CommandInterpreter &interpreter) |
2320 | : CommandObjectTypeFormatterClear( |
2321 | interpreter, |
2322 | eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter, |
2323 | "type filter clear", "Delete all existing filter.") {} |
2324 | }; |
2325 | |
2326 | #ifndef LLDB_DISABLE_PYTHON |
2327 | |
2328 | |
2329 | |
2330 | |
2331 | class CommandObjectTypeSynthClear : public CommandObjectTypeFormatterClear { |
2332 | public: |
2333 | CommandObjectTypeSynthClear(CommandInterpreter &interpreter) |
2334 | : CommandObjectTypeFormatterClear( |
2335 | interpreter, |
2336 | eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth, |
2337 | "type synthetic clear", |
2338 | "Delete all existing synthetic providers.") {} |
2339 | }; |
2340 | |
2341 | bool CommandObjectTypeSynthAdd::Execute_HandwritePython( |
2342 | Args &command, CommandReturnObject &result) { |
2343 | SynthAddOptions *options = new SynthAddOptions( |
2344 | m_options.m_skip_pointers, m_options.m_skip_references, |
2345 | m_options.m_cascade, m_options.m_regex, m_options.m_category); |
2346 | |
2347 | for (auto &entry : command.entries()) { |
2348 | if (entry.ref.empty()) { |
2349 | result.AppendError("empty typenames not allowed"); |
2350 | result.SetStatus(eReturnStatusFailed); |
2351 | return false; |
2352 | } |
2353 | |
2354 | options->m_target_types << entry.ref; |
2355 | } |
2356 | |
2357 | m_interpreter.GetPythonCommandsFromIOHandler( |
2358 | " ", |
2359 | *this, |
2360 | true, |
2361 | options); |
2362 | |
2363 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
2364 | return result.Succeeded(); |
2365 | } |
2366 | |
2367 | bool CommandObjectTypeSynthAdd::Execute_PythonClass( |
2368 | Args &command, CommandReturnObject &result) { |
2369 | const size_t argc = command.GetArgumentCount(); |
2370 | |
2371 | if (argc < 1) { |
2372 | result.AppendErrorWithFormat("%s takes one or more args.\n", |
2373 | m_cmd_name.c_str()); |
2374 | result.SetStatus(eReturnStatusFailed); |
2375 | return false; |
2376 | } |
2377 | |
2378 | if (m_options.m_class_name.empty() && !m_options.m_input_python) { |
2379 | result.AppendErrorWithFormat("%s needs either a Python class name or -P to " |
2380 | "directly input Python code.\n", |
2381 | m_cmd_name.c_str()); |
2382 | result.SetStatus(eReturnStatusFailed); |
2383 | return false; |
2384 | } |
2385 | |
2386 | SyntheticChildrenSP entry; |
2387 | |
2388 | ScriptedSyntheticChildren *impl = new ScriptedSyntheticChildren( |
2389 | SyntheticChildren::Flags() |
2390 | .SetCascades(m_options.m_cascade) |
2391 | .SetSkipPointers(m_options.m_skip_pointers) |
2392 | .SetSkipReferences(m_options.m_skip_references), |
2393 | m_options.m_class_name.c_str()); |
2394 | |
2395 | entry.reset(impl); |
2396 | |
2397 | ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); |
2398 | |
2399 | if (interpreter && |
2400 | !interpreter->CheckObjectExists(impl->GetPythonClassName())) |
2401 | result.AppendWarning("The provided class does not exist - please define it " |
2402 | "before attempting to use this synthetic provider"); |
2403 | |
2404 | |
2405 | |
2406 | lldb::TypeCategoryImplSP category; |
2407 | DataVisualization::Categories::GetCategory( |
2408 | ConstString(m_options.m_category.c_str()), category); |
2409 | |
2410 | Status error; |
2411 | |
2412 | for (auto &arg_entry : command.entries()) { |
2413 | if (arg_entry.ref.empty()) { |
2414 | result.AppendError("empty typenames not allowed"); |
2415 | result.SetStatus(eReturnStatusFailed); |
2416 | return false; |
2417 | } |
2418 | |
2419 | ConstString typeCS(arg_entry.ref); |
2420 | if (!AddSynth(typeCS, entry, |
2421 | m_options.m_regex ? eRegexSynth : eRegularSynth, |
2422 | m_options.m_category, &error)) { |
2423 | result.AppendError(error.AsCString()); |
2424 | result.SetStatus(eReturnStatusFailed); |
2425 | return false; |
2426 | } |
2427 | } |
2428 | |
2429 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
2430 | return result.Succeeded(); |
2431 | } |
2432 | |
2433 | CommandObjectTypeSynthAdd::CommandObjectTypeSynthAdd( |
2434 | CommandInterpreter &interpreter) |
2435 | : CommandObjectParsed(interpreter, "type synthetic add", |
2436 | "Add a new synthetic provider for a type.", nullptr), |
2437 | IOHandlerDelegateMultiline("DONE"), m_options() { |
2438 | CommandArgumentEntry type_arg; |
2439 | CommandArgumentData type_style_arg; |
2440 | |
2441 | type_style_arg.arg_type = eArgTypeName; |
2442 | type_style_arg.arg_repetition = eArgRepeatPlus; |
2443 | |
2444 | type_arg.push_back(type_style_arg); |
2445 | |
2446 | m_arguments.push_back(type_arg); |
2447 | } |
2448 | |
2449 | bool CommandObjectTypeSynthAdd::AddSynth(ConstString type_name, |
2450 | SyntheticChildrenSP entry, |
2451 | SynthFormatType type, |
2452 | std::string category_name, |
2453 | Status *error) { |
2454 | lldb::TypeCategoryImplSP category; |
2455 | DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()), |
2456 | category); |
2457 | |
2458 | if (type == eRegularSynth) { |
2459 | if (FixArrayTypeNameWithRegex(type_name)) |
2460 | type = eRegexSynth; |
2461 | } |
2462 | |
2463 | if (category->AnyMatches(type_name, eFormatCategoryItemFilter | |
2464 | eFormatCategoryItemRegexFilter, |
2465 | false)) { |
2466 | if (error) |
2467 | error->SetErrorStringWithFormat("cannot add synthetic for type %s when " |
2468 | "filter is defined in same category!", |
2469 | type_name.AsCString()); |
2470 | return false; |
2471 | } |
2472 | |
2473 | if (type == eRegexSynth) { |
2474 | RegularExpressionSP typeRX(new RegularExpression()); |
2475 | if (!typeRX->Compile(type_name.GetStringRef())) { |
2476 | if (error) |
2477 | error->SetErrorString( |
2478 | "regex format error (maybe this is not really a regex?)"); |
2479 | return false; |
2480 | } |
2481 | |
2482 | category->GetRegexTypeSyntheticsContainer()->Delete(type_name); |
2483 | category->GetRegexTypeSyntheticsContainer()->Add(typeRX, entry); |
2484 | |
2485 | return true; |
2486 | } else { |
2487 | category->GetTypeSyntheticsContainer()->Add(type_name, entry); |
2488 | return true; |
2489 | } |
2490 | } |
2491 | |
2492 | #endif // LLDB_DISABLE_PYTHON |
2493 | |
2494 | static OptionDefinition g_type_filter_add_options[] = { |
2495 | |
2496 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "cascade", 'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, cascade through typedef chains." }, |
2497 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-pointers", 'p', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects." }, |
2498 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "skip-references", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use this format for references-to-type objects." }, |
2499 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "category", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Add this to the given category instead of the default one." }, |
2500 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "child", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpressionPath, "Include this expression path in the synthetic view." }, |
2501 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "regex", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Type names are actually regular expressions." } |
2502 | |
2503 | }; |
2504 | |
2505 | class CommandObjectTypeFilterAdd : public CommandObjectParsed { |
2506 | private: |
2507 | class CommandOptions : public Options { |
2508 | typedef std::vector<std::string> option_vector; |
2509 | |
2510 | public: |
2511 | CommandOptions() : Options() {} |
2512 | |
2513 | ~CommandOptions() override = default; |
2514 | |
2515 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, |
2516 | ExecutionContext *execution_context) override { |
2517 | Status error; |
2518 | const int short_option = m_getopt_table[option_idx].val; |
2519 | bool success; |
2520 | |
2521 | switch (short_option) { |
2522 | case 'C': |
2523 | m_cascade = Args::StringToBoolean(option_arg, true, &success); |
2524 | if (!success) |
2525 | error.SetErrorStringWithFormat("invalid value for cascade: %s", |
2526 | option_arg.str().c_str()); |
2527 | break; |
2528 | case 'c': |
2529 | m_expr_paths.push_back(option_arg); |
2530 | has_child_list = true; |
2531 | break; |
2532 | case 'p': |
2533 | m_skip_pointers = true; |
2534 | break; |
2535 | case 'r': |
2536 | m_skip_references = true; |
2537 | break; |
2538 | case 'w': |
2539 | m_category = std::string(option_arg); |
2540 | break; |
2541 | case 'x': |
2542 | m_regex = true; |
2543 | break; |
2544 | default: |
2545 | error.SetErrorStringWithFormat("unrecognized option '%c'", |
2546 | short_option); |
2547 | break; |
2548 | } |
2549 | |
2550 | return error; |
2551 | } |
2552 | |
2553 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
2554 | m_cascade = true; |
2555 | m_skip_pointers = false; |
2556 | m_skip_references = false; |
2557 | m_category = "default"; |
2558 | m_expr_paths.clear(); |
2559 | has_child_list = false; |
2560 | m_regex = false; |
2561 | } |
2562 | |
2563 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
2564 | return llvm::makeArrayRef(g_type_filter_add_options); |
2565 | } |
2566 | |
2567 | |
2568 | |
2569 | bool m_cascade; |
2570 | bool m_skip_references; |
2571 | bool m_skip_pointers; |
2572 | bool m_input_python; |
2573 | option_vector m_expr_paths; |
2574 | std::string m_category; |
2575 | bool has_child_list; |
2576 | bool m_regex; |
2577 | |
2578 | typedef option_vector::iterator ExpressionPathsIterator; |
2579 | }; |
2580 | |
2581 | CommandOptions m_options; |
2582 | |
2583 | Options *GetOptions() override { return &m_options; } |
2584 | |
2585 | enum FilterFormatType { eRegularFilter, eRegexFilter }; |
2586 | |
2587 | bool AddFilter(ConstString type_name, TypeFilterImplSP entry, |
2588 | FilterFormatType type, std::string category_name, |
2589 | Status *error) { |
2590 | lldb::TypeCategoryImplSP category; |
2591 | DataVisualization::Categories::GetCategory( |
2592 | ConstString(category_name.c_str()), category); |
2593 | |
2594 | if (type == eRegularFilter) { |
2595 | if (FixArrayTypeNameWithRegex(type_name)) |
2596 | type = eRegexFilter; |
2597 | } |
2598 | |
2599 | if (category->AnyMatches(type_name, eFormatCategoryItemSynth | |
2600 | eFormatCategoryItemRegexSynth, |
2601 | false)) { |
2602 | if (error) |
2603 | error->SetErrorStringWithFormat("cannot add filter for type %s when " |
2604 | "synthetic is defined in same " |
2605 | "category!", |
2606 | type_name.AsCString()); |
2607 | return false; |
2608 | } |
2609 | |
2610 | if (type == eRegexFilter) { |
2611 | RegularExpressionSP typeRX(new RegularExpression()); |
2612 | if (!typeRX->Compile(type_name.GetStringRef())) { |
2613 | if (error) |
2614 | error->SetErrorString( |
2615 | "regex format error (maybe this is not really a regex?)"); |
2616 | return false; |
2617 | } |
2618 | |
2619 | category->GetRegexTypeFiltersContainer()->Delete(type_name); |
2620 | category->GetRegexTypeFiltersContainer()->Add(typeRX, entry); |
2621 | |
2622 | return true; |
2623 | } else { |
2624 | category->GetTypeFiltersContainer()->Add(type_name, entry); |
2625 | return true; |
2626 | } |
2627 | } |
2628 | |
2629 | public: |
2630 | CommandObjectTypeFilterAdd(CommandInterpreter &interpreter) |
2631 | : CommandObjectParsed(interpreter, "type filter add", |
2632 | "Add a new filter for a type.", nullptr), |
2633 | m_options() { |
2634 | CommandArgumentEntry type_arg; |
2635 | CommandArgumentData type_style_arg; |
2636 | |
2637 | type_style_arg.arg_type = eArgTypeName; |
2638 | type_style_arg.arg_repetition = eArgRepeatPlus; |
2639 | |
2640 | type_arg.push_back(type_style_arg); |
2641 | |
2642 | m_arguments.push_back(type_arg); |
2643 | |
2644 | SetHelpLong( |
2645 | R"( |
2646 | The following examples of 'type filter add' refer to this code snippet for context: |
2647 | |
2648 | class Foo { |
2649 | int a; |
2650 | int b; |
2651 | int c; |
2652 | int d; |
2653 | int e; |
2654 | int f; |
2655 | int g; |
2656 | int h; |
2657 | int i; |
2658 | } |
2659 | Foo my_foo; |
2660 | |
2661 | Adding a simple filter: |
2662 | |
2663 | (lldb) type filter add --child a --child g Foo |
2664 | (lldb) frame variable my_foo |
2665 | |
2666 | )" |
2667 | "Produces output where only a and g are displayed. Other children of my_foo \ |
2668 | (b, c, d, e, f, h and i) are available by asking for them explicitly:" |
2669 | R"( |
2670 | |
2671 | (lldb) frame variable my_foo.b my_foo.c my_foo.i |
2672 | |
2673 | )" |
2674 | "The formatting option --raw on frame variable bypasses the filter, showing \ |
2675 | all children of my_foo as if no filter was defined:" |
2676 | R"( |
2677 | |
2678 | (lldb) frame variable my_foo --raw)"); |
2679 | } |
2680 | |
2681 | ~CommandObjectTypeFilterAdd() override = default; |
2682 | |
2683 | protected: |
2684 | bool DoExecute(Args &command, CommandReturnObject &result) override { |
2685 | const size_t argc = command.GetArgumentCount(); |
2686 | |
2687 | if (argc < 1) { |
2688 | result.AppendErrorWithFormat("%s takes one or more args.\n", |
2689 | m_cmd_name.c_str()); |
2690 | result.SetStatus(eReturnStatusFailed); |
2691 | return false; |
2692 | } |
2693 | |
2694 | if (m_options.m_expr_paths.empty()) { |
2695 | result.AppendErrorWithFormat("%s needs one or more children.\n", |
2696 | m_cmd_name.c_str()); |
2697 | result.SetStatus(eReturnStatusFailed); |
2698 | return false; |
2699 | } |
2700 | |
2701 | TypeFilterImplSP entry(new TypeFilterImpl( |
2702 | SyntheticChildren::Flags() |
2703 | .SetCascades(m_options.m_cascade) |
2704 | .SetSkipPointers(m_options.m_skip_pointers) |
2705 | .SetSkipReferences(m_options.m_skip_references))); |
2706 | |
2707 | |
2708 | CommandOptions::ExpressionPathsIterator begin, |
2709 | end = m_options.m_expr_paths.end(); |
2710 | |
2711 | for (begin = m_options.m_expr_paths.begin(); begin != end; begin++) |
2712 | entry->AddExpressionPath(*begin); |
2713 | |
2714 | |
2715 | |
2716 | lldb::TypeCategoryImplSP category; |
2717 | DataVisualization::Categories::GetCategory( |
2718 | ConstString(m_options.m_category.c_str()), category); |
2719 | |
2720 | Status error; |
2721 | |
2722 | WarnOnPotentialUnquotedUnsignedType(command, result); |
2723 | |
2724 | for (auto &arg_entry : command.entries()) { |
2725 | if (arg_entry.ref.empty()) { |
2726 | result.AppendError("empty typenames not allowed"); |
2727 | result.SetStatus(eReturnStatusFailed); |
2728 | return false; |
2729 | } |
2730 | |
2731 | ConstString typeCS(arg_entry.ref); |
2732 | if (!AddFilter(typeCS, entry, |
2733 | m_options.m_regex ? eRegexFilter : eRegularFilter, |
2734 | m_options.m_category, &error)) { |
2735 | result.AppendError(error.AsCString()); |
2736 | result.SetStatus(eReturnStatusFailed); |
2737 | return false; |
2738 | } |
2739 | } |
2740 | |
2741 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
2742 | return result.Succeeded(); |
2743 | } |
2744 | }; |
2745 | |
2746 | |
2747 | |
2748 | |
2749 | static OptionDefinition g_type_lookup_options[] = { |
2750 | |
2751 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "show-help", 'h', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display available help for types" }, |
2752 | { LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Which language's types should the search scope be" } |
2753 | |
2754 | }; |
2755 | |
2756 | class CommandObjectTypeLookup : public CommandObjectRaw { |
2757 | protected: |
2758 | |
2759 | |
2760 | |
2761 | |
2762 | lldb::LanguageType GuessLanguage(StackFrame *frame) { |
2763 | lldb::LanguageType lang_type = lldb::eLanguageTypeUnknown; |
2764 | |
2765 | if (!frame) |
2766 | return lang_type; |
2767 | |
2768 | lang_type = frame->GuessLanguage(); |
2769 | if (lang_type != lldb::eLanguageTypeUnknown) |
2770 | return lang_type; |
2771 | |
2772 | Symbol *s = frame->GetSymbolContext(eSymbolContextSymbol).symbol; |
2773 | if (s) |
2774 | lang_type = s->GetMangled().GuessLanguage(); |
2775 | |
2776 | return lang_type; |
2777 | } |
2778 | |
2779 | class CommandOptions : public OptionGroup { |
2780 | public: |
2781 | CommandOptions() |
2782 | : OptionGroup(), m_show_help(false), m_language(eLanguageTypeUnknown) {} |
2783 | |
2784 | ~CommandOptions() override = default; |
2785 | |
2786 | llvm::ArrayRef<OptionDefinition> GetDefinitions() override { |
2787 | return llvm::makeArrayRef(g_type_lookup_options); |
2788 | } |
2789 | |
2790 | Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, |
2791 | ExecutionContext *execution_context) override { |
2792 | Status error; |
2793 | |
2794 | const int short_option = g_type_lookup_options[option_idx].short_option; |
2795 | |
2796 | switch (short_option) { |
2797 | case 'h': |
2798 | m_show_help = true; |
2799 | break; |
2800 | |
2801 | case 'l': |
2802 | m_language = Language::GetLanguageTypeFromString(option_value); |
2803 | break; |
2804 | |
2805 | default: |
2806 | error.SetErrorStringWithFormat("invalid short option character '%c'", |
2807 | short_option); |
2808 | break; |
2809 | } |
2810 | |
2811 | return error; |
2812 | } |
2813 | |
2814 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
2815 | m_show_help = false; |
2816 | m_language = eLanguageTypeUnknown; |
2817 | } |
2818 | |
2819 | |
2820 | |
2821 | bool m_show_help; |
2822 | lldb::LanguageType m_language; |
2823 | }; |
2824 | |
2825 | OptionGroupOptions m_option_group; |
2826 | CommandOptions m_command_options; |
2827 | |
2828 | public: |
2829 | CommandObjectTypeLookup(CommandInterpreter &interpreter) |
2830 | : CommandObjectRaw(interpreter, "type lookup", |
2831 | "Lookup types and declarations in the current target, " |
2832 | "following language-specific naming conventions.", |
2833 | "type lookup <type-specifier>", |
2834 | eCommandRequiresTarget), |
2835 | m_option_group(), m_command_options() { |
2836 | m_option_group.Append(&m_command_options); |
2837 | m_option_group.Finalize(); |
2838 | } |
2839 | |
2840 | ~CommandObjectTypeLookup() override = default; |
2841 | |
2842 | Options *GetOptions() override { return &m_option_group; } |
2843 | |
2844 | llvm::StringRef GetHelpLong() override { |
2845 | if (!m_cmd_help_long.empty()) |
2846 | return m_cmd_help_long; |
2847 | |
2848 | StreamString stream; |
2849 | |
2850 | lldb::LanguageType languages[] = {eLanguageTypeObjC, |
2851 | eLanguageTypeC_plus_plus}; |
2852 | |
2853 | for (const auto lang_type : languages) { |
2854 | if (auto language = Language::FindPlugin(lang_type)) { |
2855 | if (const char *help = language->GetLanguageSpecificTypeLookupHelp()) { |
2856 | stream.Printf("%s\n", help); |
2857 | } |
2858 | } |
2859 | } |
2860 | |
2861 | m_cmd_help_long = stream.GetString(); |
2862 | return m_cmd_help_long; |
2863 | } |
2864 | |
2865 | bool DoExecute(const char *raw_command_line, |
2866 | CommandReturnObject &result) override { |
2867 | if (!raw_command_line || !raw_command_line[0]) { |
2868 | result.SetError( |
2869 | "type lookup cannot be invoked without a type name as argument"); |
2870 | return false; |
2871 | } |
2872 | |
2873 | auto exe_ctx = GetCommandInterpreter().GetExecutionContext(); |
2874 | m_option_group.NotifyOptionParsingStarting(&exe_ctx); |
2875 | |
2876 | const char *name_of_type = nullptr; |
2877 | |
2878 | if (raw_command_line[0] == '-') { |
2879 | |
2880 | const char *end_options = nullptr; |
2881 | const char *s = raw_command_line; |
2882 | while (s && s[0]) { |
2883 | end_options = ::strstr(s, "--"); |
2884 | if (end_options) { |
2885 | end_options += 2; |
2886 | if (::isspace(end_options[0])) { |
2887 | name_of_type = end_options; |
2888 | while (::isspace(*name_of_type)) |
2889 | ++name_of_type; |
2890 | break; |
2891 | } |
2892 | } |
2893 | s = end_options; |
2894 | } |
2895 | |
2896 | if (end_options) { |
2897 | Args args( |
2898 | llvm::StringRef(raw_command_line, end_options - raw_command_line)); |
2899 | if (!ParseOptions(args, result)) |
2900 | return false; |
2901 | |
2902 | Status error(m_option_group.NotifyOptionParsingFinished(&exe_ctx)); |
2903 | if (error.Fail()) { |
2904 | result.AppendError(error.AsCString()); |
2905 | result.SetStatus(eReturnStatusFailed); |
2906 | return false; |
2907 | } |
2908 | } |
2909 | } |
2910 | if (nullptr == name_of_type) |
2911 | name_of_type = raw_command_line; |
2912 | |
2913 | |
2914 | |
2915 | |
2916 | |
2917 | ExecutionContextScope *best_scope = exe_ctx.GetBestExecutionContextScope(); |
2918 | |
2919 | bool any_found = false; |
2920 | |
2921 | std::vector<Language *> languages; |
2922 | |
2923 | bool is_global_search = false; |
2924 | LanguageType guessed_language = lldb::eLanguageTypeUnknown; |
2925 | |
2926 | if ((is_global_search = |
2927 | (m_command_options.m_language == eLanguageTypeUnknown))) { |
2928 | |
2929 | languages.push_back(Language::FindPlugin(eLanguageTypeObjC)); |
2930 | languages.push_back(Language::FindPlugin(eLanguageTypeC_plus_plus)); |
2931 | } else { |
2932 | languages.push_back(Language::FindPlugin(m_command_options.m_language)); |
2933 | } |
2934 | |
2935 | |
2936 | |
2937 | |
2938 | |
2939 | if (StackFrame *frame = m_exe_ctx.GetFramePtr()) { |
2940 | guessed_language = GuessLanguage(frame); |
2941 | if (guessed_language != eLanguageTypeUnknown) { |
2942 | std::sort( |
2943 | languages.begin(), languages.end(), |
2944 | [guessed_language](Language *lang1, Language *lang2) -> bool { |
2945 | if (!lang1 || !lang2) |
2946 | return false; |
2947 | LanguageType lt1 = lang1->GetLanguageType(); |
2948 | LanguageType lt2 = lang2->GetLanguageType(); |
2949 | if (lt1 == guessed_language) |
2950 | return true; |
2951 | if (lt2 == guessed_language) |
2952 | return false; |
2953 | return (lt1 < lt2); |
2954 | }); |
2955 | } |
2956 | } |
2957 | |
2958 | bool is_first_language = true; |
2959 | |
2960 | for (Language *language : languages) { |
2961 | if (!language) |
2962 | continue; |
2963 | |
2964 | if (auto scavenger = language->GetTypeScavenger()) { |
2965 | Language::TypeScavenger::ResultSet search_results; |
2966 | if (scavenger->Find(best_scope, name_of_type, search_results) > 0) { |
2967 | for (const auto &search_result : search_results) { |
2968 | if (search_result && search_result->IsValid()) { |
2969 | any_found = true; |
2970 | search_result->DumpToStream(result.GetOutputStream(), |
2971 | this->m_command_options.m_show_help); |
2972 | } |
2973 | } |
2974 | } |
2975 | } |
2976 | |
2977 | if (any_found && is_global_search) |
2978 | break; |
2979 | else if (is_first_language && is_global_search && |
2980 | guessed_language != lldb::eLanguageTypeUnknown) { |
2981 | is_first_language = false; |
2982 | result.GetOutputStream().Printf( |
2983 | "no type was found in the current language %s matching '%s'; " |
2984 | "performing a global search across all languages\n", |
2985 | Language::GetNameForLanguageType(guessed_language), name_of_type); |
2986 | } |
2987 | } |
2988 | |
2989 | if (!any_found) |
2990 | result.AppendMessageWithFormat("no type was found matching '%s'\n", |
2991 | name_of_type); |
2992 | |
2993 | result.SetStatus(any_found ? lldb::eReturnStatusSuccessFinishResult |
2994 | : lldb::eReturnStatusSuccessFinishNoResult); |
2995 | return true; |
2996 | } |
2997 | }; |
2998 | |
2999 | template <typename FormatterType> |
3000 | class CommandObjectFormatterInfo : public CommandObjectRaw { |
3001 | public: |
3002 | typedef std::function<typename FormatterType::SharedPointer(ValueObject &)> |
3003 | DiscoveryFunction; |
3004 | CommandObjectFormatterInfo(CommandInterpreter &interpreter, |
3005 | const char *formatter_name, |
3006 | DiscoveryFunction discovery_func) |
3007 | : CommandObjectRaw(interpreter, "", "", "", |
3008 | eCommandRequiresFrame), |
3009 | m_formatter_name(formatter_name ? formatter_name : ""), |
3010 | m_discovery_function(discovery_func) { |
3011 | StreamString name; |
3012 | name.Printf("type %s info", formatter_name); |
3013 | SetCommandName(name.GetString()); |
3014 | StreamString help; |
3015 | help.Printf("This command evaluates the provided expression and shows " |
3016 | "which %s is applied to the resulting value (if any).", |
3017 | formatter_name); |
3018 | SetHelp(help.GetString()); |
3019 | StreamString syntax; |
3020 | syntax.Printf("type %s info <expr>", formatter_name); |
3021 | SetSyntax(syntax.GetString()); |
3022 | } |
3023 | |
3024 | ~CommandObjectFormatterInfo() override = default; |
3025 | |
3026 | protected: |
3027 | bool DoExecute(const char *command, CommandReturnObject &result) override { |
3028 | TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget(); |
3029 | Thread *thread = GetDefaultThread(); |
3030 | if (!thread) { |
3031 | result.AppendError("no default thread"); |
3032 | result.SetStatus(lldb::eReturnStatusFailed); |
3033 | return false; |
3034 | } |
3035 | |
3036 | StackFrameSP frame_sp = thread->GetSelectedFrame(); |
3037 | ValueObjectSP result_valobj_sp; |
3038 | EvaluateExpressionOptions options; |
3039 | lldb::ExpressionResults expr_result = target_sp->EvaluateExpression( |
3040 | command, frame_sp.get(), result_valobj_sp, options); |
3041 | if (expr_result == eExpressionCompleted && result_valobj_sp) { |
3042 | result_valobj_sp = |
3043 | result_valobj_sp->GetQualifiedRepresentationIfAvailable( |
3044 | target_sp->GetPreferDynamicValue(), |
3045 | target_sp->GetEnableSyntheticValue()); |
3046 | typename FormatterType::SharedPointer formatter_sp = |
3047 | m_discovery_function(*result_valobj_sp); |
3048 | if (formatter_sp) { |
3049 | std::string description(formatter_sp->GetDescription()); |
3050 | result.AppendMessageWithFormat( |
3051 | "%s applied to (%s) %s is: %s\n", m_formatter_name.c_str(), |
3052 | result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>"), |
3053 | command, description.c_str()); |
3054 | result.SetStatus(lldb::eReturnStatusSuccessFinishResult); |
3055 | } else { |
3056 | result.AppendMessageWithFormat( |
3057 | "no %s applies to (%s) %s\n", m_formatter_name.c_str(), |
3058 | result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>"), |
3059 | command); |
3060 | result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); |
3061 | } |
3062 | return true; |
3063 | } else { |
3064 | result.AppendError("failed to evaluate expression"); |
3065 | result.SetStatus(lldb::eReturnStatusFailed); |
3066 | return false; |
3067 | } |
3068 | } |
3069 | |
3070 | private: |
3071 | std::string m_formatter_name; |
3072 | DiscoveryFunction m_discovery_function; |
3073 | }; |
3074 | |
3075 | class CommandObjectTypeFormat : public CommandObjectMultiword { |
3076 | public: |
3077 | CommandObjectTypeFormat(CommandInterpreter &interpreter) |
3078 | : CommandObjectMultiword( |
3079 | interpreter, "type format", |
3080 | "Commands for customizing value display formats.", |
3081 | "type format [<sub-command-options>] ") { |
3082 | LoadSubCommand( |
3083 | "add", CommandObjectSP(new CommandObjectTypeFormatAdd(interpreter))); |
3084 | LoadSubCommand("clear", CommandObjectSP( |
3085 | new CommandObjectTypeFormatClear(interpreter))); |
3086 | LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeFormatDelete( |
3087 | interpreter))); |
3088 | LoadSubCommand( |
3089 | "list", CommandObjectSP(new CommandObjectTypeFormatList(interpreter))); |
3090 | LoadSubCommand( |
3091 | "info", CommandObjectSP(new CommandObjectFormatterInfo<TypeFormatImpl>( |
3092 | interpreter, "format", |
3093 | [](ValueObject &valobj) -> TypeFormatImpl::SharedPointer { |
3094 | return valobj.GetValueFormat(); |
3095 | }))); |
3096 | } |
3097 | |
3098 | ~CommandObjectTypeFormat() override = default; |
3099 | }; |
3100 | |
3101 | #ifndef LLDB_DISABLE_PYTHON |
3102 | |
3103 | class CommandObjectTypeSynth : public CommandObjectMultiword { |
3104 | public: |
3105 | CommandObjectTypeSynth(CommandInterpreter &interpreter) |
3106 | : CommandObjectMultiword( |
3107 | interpreter, "type synthetic", |
3108 | "Commands for operating on synthetic type representations.", |
3109 | "type synthetic [<sub-command-options>] ") { |
3110 | LoadSubCommand("add", |
3111 | CommandObjectSP(new CommandObjectTypeSynthAdd(interpreter))); |
3112 | LoadSubCommand( |
3113 | "clear", CommandObjectSP(new CommandObjectTypeSynthClear(interpreter))); |
3114 | LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeSynthDelete( |
3115 | interpreter))); |
3116 | LoadSubCommand( |
3117 | "list", CommandObjectSP(new CommandObjectTypeSynthList(interpreter))); |
3118 | LoadSubCommand( |
3119 | "info", |
3120 | CommandObjectSP(new CommandObjectFormatterInfo<SyntheticChildren>( |
3121 | interpreter, "synthetic", |
3122 | [](ValueObject &valobj) -> SyntheticChildren::SharedPointer { |
3123 | return valobj.GetSyntheticChildren(); |
3124 | }))); |
3125 | } |
3126 | |
3127 | ~CommandObjectTypeSynth() override = default; |
3128 | }; |
3129 | |
3130 | #endif // LLDB_DISABLE_PYTHON |
3131 | |
3132 | class CommandObjectTypeFilter : public CommandObjectMultiword { |
3133 | public: |
3134 | CommandObjectTypeFilter(CommandInterpreter &interpreter) |
3135 | : CommandObjectMultiword(interpreter, "type filter", |
3136 | "Commands for operating on type filters.", |
3137 | "type synthetic [<sub-command-options>] ") { |
3138 | LoadSubCommand( |
3139 | "add", CommandObjectSP(new CommandObjectTypeFilterAdd(interpreter))); |
3140 | LoadSubCommand("clear", CommandObjectSP( |
3141 | new CommandObjectTypeFilterClear(interpreter))); |
3142 | LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeFilterDelete( |
3143 | interpreter))); |
3144 | LoadSubCommand( |
3145 | "list", CommandObjectSP(new CommandObjectTypeFilterList(interpreter))); |
3146 | } |
3147 | |
3148 | ~CommandObjectTypeFilter() override = default; |
3149 | }; |
3150 | |
3151 | class CommandObjectTypeCategory : public CommandObjectMultiword { |
3152 | public: |
3153 | CommandObjectTypeCategory(CommandInterpreter &interpreter) |
3154 | : CommandObjectMultiword(interpreter, "type category", |
3155 | "Commands for operating on type categories.", |
3156 | "type category [<sub-command-options>] ") { |
3157 | LoadSubCommand( |
3158 | "define", |
3159 | CommandObjectSP(new CommandObjectTypeCategoryDefine(interpreter))); |
3160 | LoadSubCommand( |
3161 | "enable", |
3162 | CommandObjectSP(new CommandObjectTypeCategoryEnable(interpreter))); |
3163 | LoadSubCommand( |
3164 | "disable", |
3165 | CommandObjectSP(new CommandObjectTypeCategoryDisable(interpreter))); |
3166 | LoadSubCommand( |
3167 | "delete", |
3168 | CommandObjectSP(new CommandObjectTypeCategoryDelete(interpreter))); |
3169 | LoadSubCommand("list", CommandObjectSP( |
3170 | new CommandObjectTypeCategoryList(interpreter))); |
3171 | } |
3172 | |
3173 | ~CommandObjectTypeCategory() override = default; |
3174 | }; |
3175 | |
3176 | class CommandObjectTypeSummary : public CommandObjectMultiword { |
3177 | public: |
3178 | CommandObjectTypeSummary(CommandInterpreter &interpreter) |
3179 | : CommandObjectMultiword( |
3180 | interpreter, "type summary", |
3181 | "Commands for editing variable summary display options.", |
3182 | "type summary [<sub-command-options>] ") { |
3183 | LoadSubCommand( |
3184 | "add", CommandObjectSP(new CommandObjectTypeSummaryAdd(interpreter))); |
3185 | LoadSubCommand("clear", CommandObjectSP(new CommandObjectTypeSummaryClear( |
3186 | interpreter))); |
3187 | LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeSummaryDelete( |
3188 | interpreter))); |
3189 | LoadSubCommand( |
3190 | "list", CommandObjectSP(new CommandObjectTypeSummaryList(interpreter))); |
3191 | LoadSubCommand( |
3192 | "info", CommandObjectSP(new CommandObjectFormatterInfo<TypeSummaryImpl>( |
3193 | interpreter, "summary", |
3194 | [](ValueObject &valobj) -> TypeSummaryImpl::SharedPointer { |
3195 | return valobj.GetSummaryFormat(); |
3196 | }))); |
3197 | } |
3198 | |
3199 | ~CommandObjectTypeSummary() override = default; |
3200 | }; |
3201 | |
3202 | |
3203 | |
3204 | |
3205 | |
3206 | CommandObjectType::CommandObjectType(CommandInterpreter &interpreter) |
3207 | : CommandObjectMultiword(interpreter, "type", |
3208 | "Commands for operating on the type system.", |
3209 | "type [<sub-command-options>]") { |
3210 | LoadSubCommand("category", |
3211 | CommandObjectSP(new CommandObjectTypeCategory(interpreter))); |
3212 | LoadSubCommand("filter", |
3213 | CommandObjectSP(new CommandObjectTypeFilter(interpreter))); |
3214 | LoadSubCommand("format", |
3215 | CommandObjectSP(new CommandObjectTypeFormat(interpreter))); |
3216 | LoadSubCommand("summary", |
3217 | CommandObjectSP(new CommandObjectTypeSummary(interpreter))); |
3218 | #ifndef LLDB_DISABLE_PYTHON |
3219 | LoadSubCommand("synthetic", |
3220 | CommandObjectSP(new CommandObjectTypeSynth(interpreter))); |
3221 | #endif // LLDB_DISABLE_PYTHON |
3222 | LoadSubCommand("lookup", |
3223 | CommandObjectSP(new CommandObjectTypeLookup(interpreter))); |
3224 | } |
3225 | |
3226 | CommandObjectType::~CommandObjectType() = default; |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | #ifndef _SHARED_PTR_BASE_H1 |
50 | #define _SHARED_PTR_BASE_H1 1 |
51 | |
52 | #if __cpp_rtti199711 |
53 | # include <typeinfo> |
54 | #endif |
55 | #include <bits/allocated_ptr.h> |
56 | #include <bits/refwrap.h> |
57 | #include <bits/stl_function.h> |
58 | #include <ext/aligned_buffer.h> |
59 | |
60 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
61 | { |
62 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
63 | |
64 | #if _GLIBCXX_USE_DEPRECATED1 |
65 | template<typename> class auto_ptr; |
66 | #endif |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | class bad_weak_ptr : public std::exception |
73 | { |
74 | public: |
75 | virtual char const* what() const noexcept; |
76 | |
77 | virtual ~bad_weak_ptr() noexcept; |
78 | }; |
79 | |
80 | |
81 | inline void |
82 | __throw_bad_weak_ptr() |
83 | { _GLIBCXX_THROW_OR_ABORT(bad_weak_ptr())(__builtin_abort()); } |
84 | |
85 | using __gnu_cxx::_Lock_policy; |
86 | using __gnu_cxx::__default_lock_policy; |
87 | using __gnu_cxx::_S_single; |
88 | using __gnu_cxx::_S_mutex; |
89 | using __gnu_cxx::_S_atomic; |
90 | |
91 | |
92 | template<_Lock_policy _Lp> |
93 | class _Mutex_base |
94 | { |
95 | protected: |
96 | |
97 | enum { _S_need_barriers = 0 }; |
98 | }; |
99 | |
100 | template<> |
101 | class _Mutex_base<_S_mutex> |
102 | : public __gnu_cxx::__mutex |
103 | { |
104 | protected: |
105 | |
106 | |
107 | |
108 | enum { _S_need_barriers = 1 }; |
109 | }; |
110 | |
111 | template<_Lock_policy _Lp = __default_lock_policy> |
112 | class _Sp_counted_base |
113 | : public _Mutex_base<_Lp> |
114 | { |
115 | public: |
116 | _Sp_counted_base() noexcept |
117 | : _M_use_count(1), _M_weak_count(1) { } |
118 | |
119 | virtual |
120 | ~_Sp_counted_base() noexcept |
121 | { } |
122 | |
123 | |
124 | |
125 | virtual void |
126 | _M_dispose() noexcept = 0; |
127 | |
128 | |
129 | virtual void |
130 | _M_destroy() noexcept |
131 | { delete this; } |
| |
132 | |
133 | virtual void* |
134 | _M_get_deleter(const std::type_info&) noexcept = 0; |
135 | |
136 | void |
137 | _M_add_ref_copy() |
138 | { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); } |
139 | |
140 | void |
141 | _M_add_ref_lock(); |
142 | |
143 | bool |
144 | _M_add_ref_lock_nothrow(); |
145 | |
146 | void |
147 | _M_release() noexcept |
148 | { |
149 | |
150 | _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count); |
151 | if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1) |
| |
| 61 | | Calling '__exchange_and_add_dispatch' | |
|
152 | { |
153 | _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count); |
154 | _M_dispose(); |
155 | |
156 | |
157 | |
158 | |
159 | if (_Mutex_base<_Lp>::_S_need_barriers) |
| |
160 | { |
161 | __atomic_thread_fence (__ATOMIC_ACQ_REL4); |
162 | } |
163 | |
164 | |
165 | _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count); |
166 | if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, |
| |
167 | -1) == 1) |
168 | { |
169 | _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count); |
170 | _M_destroy(); |
| 34 | | Calling '_Sp_counted_base::_M_destroy' | |
|
| 36 | | Returning; memory was released | |
|
171 | } |
172 | } |
173 | } |
174 | |
175 | void |
176 | _M_weak_add_ref() noexcept |
177 | { __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); } |
178 | |
179 | void |
180 | _M_weak_release() noexcept |
181 | { |
182 | |
183 | _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count); |
184 | if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1) |
185 | { |
186 | _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count); |
187 | if (_Mutex_base<_Lp>::_S_need_barriers) |
188 | { |
189 | |
190 | |
191 | __atomic_thread_fence (__ATOMIC_ACQ_REL4); |
192 | } |
193 | _M_destroy(); |
194 | } |
195 | } |
196 | |
197 | long |
198 | _M_get_use_count() const noexcept |
199 | { |
200 | |
201 | |
202 | return __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED0); |
203 | } |
204 | |
205 | private: |
206 | _Sp_counted_base(_Sp_counted_base const&) = delete; |
207 | _Sp_counted_base& operator=(_Sp_counted_base const&) = delete; |
208 | |
209 | _Atomic_word _M_use_count; |
210 | _Atomic_word _M_weak_count; |
211 | }; |
212 | |
213 | template<> |
214 | inline void |
215 | _Sp_counted_base<_S_single>:: |
216 | _M_add_ref_lock() |
217 | { |
218 | if (_M_use_count == 0) |
219 | __throw_bad_weak_ptr(); |
220 | ++_M_use_count; |
221 | } |
222 | |
223 | template<> |
224 | inline void |
225 | _Sp_counted_base<_S_mutex>:: |
226 | _M_add_ref_lock() |
227 | { |
228 | __gnu_cxx::__scoped_lock sentry(*this); |
229 | if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0) |
230 | { |
231 | _M_use_count = 0; |
232 | __throw_bad_weak_ptr(); |
233 | } |
234 | } |
235 | |
236 | template<> |
237 | inline void |
238 | _Sp_counted_base<_S_atomic>:: |
239 | _M_add_ref_lock() |
240 | { |
241 | |
242 | _Atomic_word __count = _M_get_use_count(); |
243 | do |
244 | { |
245 | if (__count == 0) |
246 | __throw_bad_weak_ptr(); |
247 | |
248 | |
249 | } |
250 | while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1, |
251 | true, __ATOMIC_ACQ_REL4, |
252 | __ATOMIC_RELAXED0)); |
253 | } |
254 | |
255 | template<> |
256 | inline bool |
257 | _Sp_counted_base<_S_single>:: |
258 | _M_add_ref_lock_nothrow() |
259 | { |
260 | if (_M_use_count == 0) |
261 | return false; |
262 | ++_M_use_count; |
263 | return true; |
264 | } |
265 | |
266 | template<> |
267 | inline bool |
268 | _Sp_counted_base<_S_mutex>:: |
269 | _M_add_ref_lock_nothrow() |
270 | { |
271 | __gnu_cxx::__scoped_lock sentry(*this); |
272 | if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0) |
273 | { |
274 | _M_use_count = 0; |
275 | return false; |
276 | } |
277 | return true; |
278 | } |
279 | |
280 | template<> |
281 | inline bool |
282 | _Sp_counted_base<_S_atomic>:: |
283 | _M_add_ref_lock_nothrow() |
284 | { |
285 | |
286 | _Atomic_word __count = _M_get_use_count(); |
287 | do |
288 | { |
289 | if (__count == 0) |
290 | return false; |
291 | |
292 | |
293 | } |
294 | while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1, |
295 | true, __ATOMIC_ACQ_REL4, |
296 | __ATOMIC_RELAXED0)); |
297 | return true; |
298 | } |
299 | |
300 | template<> |
301 | inline void |
302 | _Sp_counted_base<_S_single>::_M_add_ref_copy() |
303 | { ++_M_use_count; } |
304 | |
305 | template<> |
306 | inline void |
307 | _Sp_counted_base<_S_single>::_M_release() noexcept |
308 | { |
309 | if (--_M_use_count == 0) |
310 | { |
311 | _M_dispose(); |
312 | if (--_M_weak_count == 0) |
313 | _M_destroy(); |
314 | } |
315 | } |
316 | |
317 | template<> |
318 | inline void |
319 | _Sp_counted_base<_S_single>::_M_weak_add_ref() noexcept |
320 | { ++_M_weak_count; } |
321 | |
322 | template<> |
323 | inline void |
324 | _Sp_counted_base<_S_single>::_M_weak_release() noexcept |
325 | { |
326 | if (--_M_weak_count == 0) |
327 | _M_destroy(); |
328 | } |
329 | |
330 | template<> |
331 | inline long |
332 | _Sp_counted_base<_S_single>::_M_get_use_count() const noexcept |
333 | { return _M_use_count; } |
334 | |
335 | |
336 | |
337 | template<typename _Tp, _Lock_policy _Lp = __default_lock_policy> |
338 | class __shared_ptr; |
339 | |
340 | template<typename _Tp, _Lock_policy _Lp = __default_lock_policy> |
341 | class __weak_ptr; |
342 | |
343 | template<typename _Tp, _Lock_policy _Lp = __default_lock_policy> |
344 | class __enable_shared_from_this; |
345 | |
346 | template<typename _Tp> |
347 | class shared_ptr; |
348 | |
349 | template<typename _Tp> |
350 | class weak_ptr; |
351 | |
352 | template<typename _Tp> |
353 | struct owner_less; |
354 | |
355 | template<typename _Tp> |
356 | class enable_shared_from_this; |
357 | |
358 | template<_Lock_policy _Lp = __default_lock_policy> |
359 | class __weak_count; |
360 | |
361 | template<_Lock_policy _Lp = __default_lock_policy> |
362 | class __shared_count; |
363 | |
364 | |
365 | |
366 | template<typename _Ptr, _Lock_policy _Lp> |
367 | class _Sp_counted_ptr final : public _Sp_counted_base<_Lp> |
368 | { |
369 | public: |
370 | explicit |
371 | _Sp_counted_ptr(_Ptr __p) noexcept |
372 | : _M_ptr(__p) { } |
373 | |
374 | virtual void |
375 | _M_dispose() noexcept |
376 | { delete _M_ptr; } |
377 | |
378 | virtual void |
379 | _M_destroy() noexcept |
380 | { delete this; } |
381 | |
382 | virtual void* |
383 | _M_get_deleter(const std::type_info&) noexcept |
384 | { return nullptr; } |
385 | |
386 | _Sp_counted_ptr(const _Sp_counted_ptr&) = delete; |
387 | _Sp_counted_ptr& operator=(const _Sp_counted_ptr&) = delete; |
388 | |
389 | private: |
390 | _Ptr _M_ptr; |
391 | }; |
392 | |
393 | template<> |
394 | inline void |
395 | _Sp_counted_ptr<nullptr_t, _S_single>::_M_dispose() noexcept { } |
396 | |
397 | template<> |
398 | inline void |
399 | _Sp_counted_ptr<nullptr_t, _S_mutex>::_M_dispose() noexcept { } |
400 | |
401 | template<> |
402 | inline void |
403 | _Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept { } |
404 | |
405 | template<int _Nm, typename _Tp, |
406 | bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)> |
407 | struct _Sp_ebo_helper; |
408 | |
409 | |
410 | template<int _Nm, typename _Tp> |
411 | struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp |
412 | { |
413 | explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) { } |
414 | explicit _Sp_ebo_helper(_Tp&& __tp) : _Tp(std::move(__tp)) { } |
415 | |
416 | static _Tp& |
417 | _S_get(_Sp_ebo_helper& __eboh) { return static_cast<_Tp&>(__eboh); } |
418 | }; |
419 | |
420 | |
421 | template<int _Nm, typename _Tp> |
422 | struct _Sp_ebo_helper<_Nm, _Tp, false> |
423 | { |
424 | explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) { } |
425 | explicit _Sp_ebo_helper(_Tp&& __tp) : _M_tp(std::move(__tp)) { } |
426 | |
427 | static _Tp& |
428 | _S_get(_Sp_ebo_helper& __eboh) |
429 | { return __eboh._M_tp; } |
430 | |
431 | private: |
432 | _Tp _M_tp; |
433 | }; |
434 | |
435 | |
436 | template<typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp> |
437 | class _Sp_counted_deleter final : public _Sp_counted_base<_Lp> |
438 | { |
439 | class _Impl : _Sp_ebo_helper<0, _Deleter>, _Sp_ebo_helper<1, _Alloc> |
440 | { |
441 | typedef _Sp_ebo_helper<0, _Deleter> _Del_base; |
442 | typedef _Sp_ebo_helper<1, _Alloc> _Alloc_base; |
443 | |
444 | public: |
445 | _Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept |
446 | : _M_ptr(__p), _Del_base(std::move(__d)), _Alloc_base(__a) |
447 | { } |
448 | |
449 | _Deleter& _M_del() noexcept { return _Del_base::_S_get(*this); } |
450 | _Alloc& _M_alloc() noexcept { return _Alloc_base::_S_get(*this); } |
451 | |
452 | _Ptr _M_ptr; |
453 | }; |
454 | |
455 | public: |
456 | using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_deleter>; |
457 | |
458 | |
459 | _Sp_counted_deleter(_Ptr __p, _Deleter __d) noexcept |
460 | : _M_impl(__p, std::move(__d), _Alloc()) { } |
461 | |
462 | |
463 | _Sp_counted_deleter(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept |
464 | : _M_impl(__p, std::move(__d), __a) { } |
465 | |
466 | ~_Sp_counted_deleter() noexcept { } |
467 | |
468 | virtual void |
469 | _M_dispose() noexcept |
470 | { _M_impl._M_del()(_M_impl._M_ptr); } |
471 | |
472 | virtual void |
473 | _M_destroy() noexcept |
474 | { |
475 | __allocator_type __a(_M_impl._M_alloc()); |
476 | __allocated_ptr<__allocator_type> __guard_ptr{ __a, this }; |
477 | this->~_Sp_counted_deleter(); |
478 | } |
479 | |
480 | virtual void* |
481 | _M_get_deleter(const std::type_info& __ti) noexcept |
482 | { |
483 | #if __cpp_rtti199711 |
484 | |
485 | |
486 | return __ti == typeid(_Deleter) |
487 | ? std::__addressof(_M_impl._M_del()) |
488 | : nullptr; |
489 | #else |
490 | return nullptr; |
491 | #endif |
492 | } |
493 | |
494 | private: |
495 | _Impl _M_impl; |
496 | }; |
497 | |
498 | |
499 | |
500 | struct _Sp_make_shared_tag { }; |
501 | |
502 | template<typename _Tp, typename _Alloc, _Lock_policy _Lp> |
503 | class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp> |
504 | { |
505 | class _Impl : _Sp_ebo_helper<0, _Alloc> |
506 | { |
507 | typedef _Sp_ebo_helper<0, _Alloc> _A_base; |
508 | |
509 | public: |
510 | explicit _Impl(_Alloc __a) noexcept : _A_base(__a) { } |
511 | |
512 | _Alloc& _M_alloc() noexcept { return _A_base::_S_get(*this); } |
513 | |
514 | __gnu_cxx::__aligned_buffer<_Tp> _M_storage; |
515 | }; |
516 | |
517 | public: |
518 | using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_ptr_inplace>; |
519 | |
520 | template<typename... _Args> |
521 | _Sp_counted_ptr_inplace(_Alloc __a, _Args&&... __args) |
522 | : _M_impl(__a) |
523 | { |
524 | |
525 | |
526 | allocator_traits<_Alloc>::construct(__a, _M_ptr(), |
527 | std::forward<_Args>(__args)...); |
528 | } |
529 | |
530 | ~_Sp_counted_ptr_inplace() noexcept { } |
531 | |
532 | virtual void |
533 | _M_dispose() noexcept |
534 | { |
535 | allocator_traits<_Alloc>::destroy(_M_impl._M_alloc(), _M_ptr()); |
536 | } |
537 | |
538 | |
539 | virtual void |
540 | _M_destroy() noexcept |
541 | { |
542 | __allocator_type __a(_M_impl._M_alloc()); |
543 | __allocated_ptr<__allocator_type> __guard_ptr{ __a, this }; |
544 | this->~_Sp_counted_ptr_inplace(); |
545 | } |
546 | |
547 | |
548 | virtual void* |
549 | _M_get_deleter(const std::type_info& __ti) noexcept |
550 | { |
551 | #if __cpp_rtti199711 |
552 | if (__ti == typeid(_Sp_make_shared_tag)) |
553 | return const_cast<typename remove_cv<_Tp>::type*>(_M_ptr()); |
554 | #endif |
555 | return nullptr; |
556 | } |
557 | |
558 | private: |
559 | _Tp* _M_ptr() noexcept { return _M_impl._M_storage._M_ptr(); } |
560 | |
561 | _Impl _M_impl; |
562 | }; |
563 | |
564 | |
565 | struct __sp_array_delete |
566 | { |
567 | template<typename _Yp> |
568 | void operator()(_Yp* __p) const { delete[] __p; } |
569 | }; |
570 | |
571 | template<_Lock_policy _Lp> |
572 | class __shared_count |
573 | { |
574 | public: |
575 | constexpr __shared_count() noexcept : _M_pi(0) |
576 | { } |
577 | |
578 | template<typename _Ptr> |
579 | explicit |
580 | __shared_count(_Ptr __p) : _M_pi(0) |
581 | { |
582 | __tryif (true) |
583 | { |
584 | _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p); |
585 | } |
586 | __catch(...)if (false) |
587 | { |
588 | delete __p; |
589 | __throw_exception_again; |
590 | } |
591 | } |
592 | |
593 | template<typename _Ptr> |
594 | __shared_count(_Ptr __p, false_type) |
595 | : __shared_count(__p) |
596 | { } |
597 | |
598 | template<typename _Ptr> |
599 | __shared_count(_Ptr __p, true_type) |
600 | : __shared_count(__p, __sp_array_delete{}, allocator<void>()) |
601 | { } |
602 | |
603 | template<typename _Ptr, typename _Deleter> |
604 | __shared_count(_Ptr __p, _Deleter __d) |
605 | : __shared_count(__p, std::move(__d), allocator<void>()) |
606 | { } |
607 | |
608 | template<typename _Ptr, typename _Deleter, typename _Alloc> |
609 | __shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0) |
610 | { |
611 | typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type; |
612 | __tryif (true) |
613 | { |
614 | typename _Sp_cd_type::__allocator_type __a2(__a); |
615 | auto __guard = std::__allocate_guarded(__a2); |
616 | _Sp_cd_type* __mem = __guard.get(); |
617 | ::new (__mem) _Sp_cd_type(__p, std::move(__d), std::move(__a)); |
618 | _M_pi = __mem; |
619 | __guard = nullptr; |
620 | } |
621 | __catch(...)if (false) |
622 | { |
623 | __d(__p); |
624 | __throw_exception_again; |
625 | } |
626 | } |
627 | |
628 | template<typename _Tp, typename _Alloc, typename... _Args> |
629 | __shared_count(_Sp_make_shared_tag, _Tp*, const _Alloc& __a, |
630 | _Args&&... __args) |
631 | : _M_pi(0) |
632 | { |
633 | typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type; |
634 | typename _Sp_cp_type::__allocator_type __a2(__a); |
635 | auto __guard = std::__allocate_guarded(__a2); |
636 | _Sp_cp_type* __mem = __guard.get(); |
637 | ::new (__mem) _Sp_cp_type(std::move(__a), |
638 | std::forward<_Args>(__args)...); |
639 | _M_pi = __mem; |
640 | __guard = nullptr; |
641 | } |
642 | |
643 | #if _GLIBCXX_USE_DEPRECATED1 |
644 | |
645 | template<typename _Tp> |
646 | explicit |
647 | __shared_count(std::auto_ptr<_Tp>&& __r); |
648 | #endif |
649 | |
650 | |
651 | template<typename _Tp, typename _Del> |
652 | explicit |
653 | __shared_count(std::unique_ptr<_Tp, _Del>&& __r) : _M_pi(0) |
654 | { |
655 | |
656 | |
657 | if (__r.get() == nullptr) |
658 | return; |
659 | |
660 | using _Ptr = typename unique_ptr<_Tp, _Del>::pointer; |
661 | using _Del2 = typename conditional<is_reference<_Del>::value, |
662 | reference_wrapper<typename remove_reference<_Del>::type>, |
663 | _Del>::type; |
664 | using _Sp_cd_type |
665 | = _Sp_counted_deleter<_Ptr, _Del2, allocator<void>, _Lp>; |
666 | using _Alloc = allocator<_Sp_cd_type>; |
667 | using _Alloc_traits = allocator_traits<_Alloc>; |
668 | _Alloc __a; |
669 | _Sp_cd_type* __mem = _Alloc_traits::allocate(__a, 1); |
670 | _Alloc_traits::construct(__a, __mem, __r.release(), |
671 | __r.get_deleter()); |
672 | _M_pi = __mem; |
673 | } |
674 | |
675 | |
676 | explicit __shared_count(const __weak_count<_Lp>& __r); |
677 | |
678 | |
679 | explicit __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t); |
680 | |
681 | ~__shared_count() noexcept |
682 | { |
683 | if (_M_pi != nullptr) |
684 | _M_pi->_M_release(); |
685 | } |
686 | |
687 | __shared_count(const __shared_count& __r) noexcept |
688 | : _M_pi(__r._M_pi) |
689 | { |
690 | if (_M_pi != 0) |
691 | _M_pi->_M_add_ref_copy(); |
692 | } |
693 | |
694 | __shared_count& |
695 | operator=(const __shared_count& __r) noexcept |
696 | { |
697 | _Sp_counted_base<_Lp>* __tmp = __r._M_pi; |
698 | if (__tmp != _M_pi) |
| |
| |
699 | { |
700 | if (__tmp != 0) |
| 27 | | Assuming '__tmp' is equal to null | |
|
| |
| |
701 | __tmp->_M_add_ref_copy(); |
702 | if (_M_pi != 0) |
| |
| |
703 | _M_pi->_M_release(); |
| 30 | | Calling '_Sp_counted_base::_M_release' | |
|
| 37 | | Returning; memory was released | |
|
| 60 | | Calling '_Sp_counted_base::_M_release' | |
|
704 | _M_pi = __tmp; |
705 | } |
706 | return *this; |
707 | } |
708 | |
709 | void |
710 | _M_swap(__shared_count& __r) noexcept |
711 | { |
712 | _Sp_counted_base<_Lp>* __tmp = __r._M_pi; |
713 | __r._M_pi = _M_pi; |
714 | _M_pi = __tmp; |
715 | } |
716 | |
717 | long |
718 | _M_get_use_count() const noexcept |
719 | { return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0; } |
720 | |
721 | bool |
722 | _M_unique() const noexcept |
723 | { return this->_M_get_use_count() == 1; } |
724 | |
725 | void* |
726 | _M_get_deleter(const std::type_info& __ti) const noexcept |
727 | { return _M_pi ? _M_pi->_M_get_deleter(__ti) : nullptr; } |
728 | |
729 | bool |
730 | _M_less(const __shared_count& __rhs) const noexcept |
731 | { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } |
732 | |
733 | bool |
734 | _M_less(const __weak_count<_Lp>& __rhs) const noexcept |
735 | { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } |
736 | |
737 | |
738 | friend inline bool |
739 | operator==(const __shared_count& __a, const __shared_count& __b) noexcept |
740 | { return __a._M_pi == __b._M_pi; } |
741 | |
742 | private: |
743 | friend class __weak_count<_Lp>; |
744 | |
745 | _Sp_counted_base<_Lp>* _M_pi; |
746 | }; |
747 | |
748 | |
749 | template<_Lock_policy _Lp> |
750 | class __weak_count |
751 | { |
752 | public: |
753 | constexpr __weak_count() noexcept : _M_pi(nullptr) |
754 | { } |
755 | |
756 | __weak_count(const __shared_count<_Lp>& __r) noexcept |
757 | : _M_pi(__r._M_pi) |
758 | { |
759 | if (_M_pi != nullptr) |
760 | _M_pi->_M_weak_add_ref(); |
761 | } |
762 | |
763 | __weak_count(const __weak_count& __r) noexcept |
764 | : _M_pi(__r._M_pi) |
765 | { |
766 | if (_M_pi != nullptr) |
767 | _M_pi->_M_weak_add_ref(); |
768 | } |
769 | |
770 | __weak_count(__weak_count&& __r) noexcept |
771 | : _M_pi(__r._M_pi) |
772 | { __r._M_pi = nullptr; } |
773 | |
774 | ~__weak_count() noexcept |
775 | { |
776 | if (_M_pi != nullptr) |
777 | _M_pi->_M_weak_release(); |
778 | } |
779 | |
780 | __weak_count& |
781 | operator=(const __shared_count<_Lp>& __r) noexcept |
782 | { |
783 | _Sp_counted_base<_Lp>* __tmp = __r._M_pi; |
784 | if (__tmp != nullptr) |
785 | __tmp->_M_weak_add_ref(); |
786 | if (_M_pi != nullptr) |
787 | _M_pi->_M_weak_release(); |
788 | _M_pi = __tmp; |
789 | return *this; |
790 | } |
791 | |
792 | __weak_count& |
793 | operator=(const __weak_count& __r) noexcept |
794 | { |
795 | _Sp_counted_base<_Lp>* __tmp = __r._M_pi; |
796 | if (__tmp != nullptr) |
797 | __tmp->_M_weak_add_ref(); |
798 | if (_M_pi != nullptr) |
799 | _M_pi->_M_weak_release(); |
800 | _M_pi = __tmp; |
801 | return *this; |
802 | } |
803 | |
804 | __weak_count& |
805 | operator=(__weak_count&& __r) noexcept |
806 | { |
807 | if (_M_pi != nullptr) |
808 | _M_pi->_M_weak_release(); |
809 | _M_pi = __r._M_pi; |
810 | __r._M_pi = nullptr; |
811 | return *this; |
812 | } |
813 | |
814 | void |
815 | _M_swap(__weak_count& __r) noexcept |
816 | { |
817 | _Sp_counted_base<_Lp>* __tmp = __r._M_pi; |
818 | __r._M_pi = _M_pi; |
819 | _M_pi = __tmp; |
820 | } |
821 | |
822 | long |
823 | _M_get_use_count() const noexcept |
824 | { return _M_pi != nullptr ? _M_pi->_M_get_use_count() : 0; } |
825 | |
826 | bool |
827 | _M_less(const __weak_count& __rhs) const noexcept |
828 | { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } |
829 | |
830 | bool |
831 | _M_less(const __shared_count<_Lp>& __rhs) const noexcept |
832 | { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); } |
833 | |
834 | |
835 | friend inline bool |
836 | operator==(const __weak_count& __a, const __weak_count& __b) noexcept |
837 | { return __a._M_pi == __b._M_pi; } |
838 | |
839 | private: |
840 | friend class __shared_count<_Lp>; |
841 | |
842 | _Sp_counted_base<_Lp>* _M_pi; |
843 | }; |
844 | |
845 | |
846 | template<_Lock_policy _Lp> |
847 | inline |
848 | __shared_count<_Lp>::__shared_count(const __weak_count<_Lp>& __r) |
849 | : _M_pi(__r._M_pi) |
850 | { |
851 | if (_M_pi != nullptr) |
852 | _M_pi->_M_add_ref_lock(); |
853 | else |
854 | __throw_bad_weak_ptr(); |
855 | } |
856 | |
857 | |
858 | template<_Lock_policy _Lp> |
859 | inline |
860 | __shared_count<_Lp>:: |
861 | __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t) |
862 | : _M_pi(__r._M_pi) |
863 | { |
864 | if (_M_pi != nullptr) |
865 | if (!_M_pi->_M_add_ref_lock_nothrow()) |
866 | _M_pi = nullptr; |
867 | } |
868 | |
869 | #define __cpp_lib_shared_ptr_arrays201603 201603 |
870 | |
871 | |
872 | |
873 | |
874 | |
875 | template<typename _Yp_ptr, typename _Tp_ptr> |
876 | struct __sp_compatible_with |
877 | : false_type |
878 | { }; |
879 | |
880 | template<typename _Yp, typename _Tp> |
881 | struct __sp_compatible_with<_Yp*, _Tp*> |
882 | : is_convertible<_Yp*, _Tp*>::type |
883 | { }; |
884 | |
885 | template<typename _Up, size_t _Nm> |
886 | struct __sp_compatible_with<_Up(*)[_Nm], _Up(*)[]> |
887 | : true_type |
888 | { }; |
889 | |
890 | template<typename _Up, size_t _Nm> |
891 | struct __sp_compatible_with<_Up(*)[_Nm], const _Up(*)[]> |
892 | : true_type |
893 | { }; |
894 | |
895 | template<typename _Up, size_t _Nm> |
896 | struct __sp_compatible_with<_Up(*)[_Nm], volatile _Up(*)[]> |
897 | : true_type |
898 | { }; |
899 | |
900 | template<typename _Up, size_t _Nm> |
901 | struct __sp_compatible_with<_Up(*)[_Nm], const volatile _Up(*)[]> |
902 | : true_type |
903 | { }; |
904 | |
905 | |
906 | template<typename _Up, size_t _Nm, typename _Yp, typename = void> |
907 | struct __sp_is_constructible_arrN |
908 | : false_type |
909 | { }; |
910 | |
911 | template<typename _Up, size_t _Nm, typename _Yp> |
912 | struct __sp_is_constructible_arrN<_Up, _Nm, _Yp, __void_t<_Yp[_Nm]>> |
913 | : is_convertible<_Yp(*)[_Nm], _Up(*)[_Nm]>::type |
914 | { }; |
915 | |
916 | |
917 | template<typename _Up, typename _Yp, typename = void> |
918 | struct __sp_is_constructible_arr |
919 | : false_type |
920 | { }; |
921 | |
922 | template<typename _Up, typename _Yp> |
923 | struct __sp_is_constructible_arr<_Up, _Yp, __void_t<_Yp[]>> |
924 | : is_convertible<_Yp(*)[], _Up(*)[]>::type |
925 | { }; |
926 | |
927 | |
928 | template<typename _Tp, typename _Yp> |
929 | struct __sp_is_constructible; |
930 | |
931 | |
932 | template<typename _Up, size_t _Nm, typename _Yp> |
933 | struct __sp_is_constructible<_Up[_Nm], _Yp> |
934 | : __sp_is_constructible_arrN<_Up, _Nm, _Yp>::type |
935 | { }; |
936 | |
937 | |
938 | template<typename _Up, typename _Yp> |
939 | struct __sp_is_constructible<_Up[], _Yp> |
940 | : __sp_is_constructible_arr<_Up, _Yp>::type |
941 | { }; |
942 | |
943 | |
944 | template<typename _Tp, typename _Yp> |
945 | struct __sp_is_constructible |
946 | : is_convertible<_Yp*, _Tp*>::type |
947 | { }; |
948 | |
949 | |
950 | |
951 | template<typename _Tp, _Lock_policy _Lp, |
952 | bool = is_array<_Tp>::value, bool = is_void<_Tp>::value> |
953 | class __shared_ptr_access |
954 | { |
955 | public: |
956 | using element_type = _Tp; |
957 | |
958 | element_type& |
959 | operator*() const noexcept |
960 | { |
961 | __glibcxx_assert(_M_get() != nullptr); |
962 | return *_M_get(); |
963 | } |
964 | |
965 | element_type* |
966 | operator->() const noexcept |
967 | { |
968 | _GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr); |
969 | return _M_get(); |
970 | } |
971 | |
972 | private: |
973 | element_type* |
974 | _M_get() const noexcept |
975 | { return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); } |
976 | }; |
977 | |
978 | |
979 | template<typename _Tp, _Lock_policy _Lp> |
980 | class __shared_ptr_access<_Tp, _Lp, false, true> |
981 | { |
982 | public: |
983 | using element_type = _Tp; |
984 | |
985 | element_type* |
986 | operator->() const noexcept |
987 | { |
988 | auto __ptr = static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); |
989 | _GLIBCXX_DEBUG_PEDASSERT(__ptr != nullptr); |
990 | return __ptr; |
991 | } |
992 | }; |
993 | |
994 | |
995 | template<typename _Tp, _Lock_policy _Lp> |
996 | class __shared_ptr_access<_Tp, _Lp, true, false> |
997 | { |
998 | public: |
999 | using element_type = typename remove_extent<_Tp>::type; |
1000 | |
1001 | #if __cplusplus201103L <= 201402L |
1002 | [[__deprecated__("shared_ptr<T[]>::operator* is absent from C++17")]] |
1003 | element_type& |
1004 | operator*() const noexcept |
1005 | { |
1006 | __glibcxx_assert(_M_get() != nullptr); |
1007 | return *_M_get(); |
1008 | } |
1009 | |
1010 | [[__deprecated__("shared_ptr<T[]>::operator-> is absent from C++17")]] |
1011 | element_type* |
1012 | operator->() const noexcept |
1013 | { |
1014 | _GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr); |
1015 | return _M_get(); |
1016 | } |
1017 | #endif |
1018 | |
1019 | element_type& |
1020 | operator[](ptrdiff_t __i) const |
1021 | { |
1022 | __glibcxx_assert(_M_get() != nullptr); |
1023 | __glibcxx_assert(!extent<_Tp>::value || __i < extent<_Tp>::value); |
1024 | return _M_get()[__i]; |
1025 | } |
1026 | |
1027 | private: |
1028 | element_type* |
1029 | _M_get() const noexcept |
1030 | { return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); } |
1031 | }; |
1032 | |
1033 | template<typename _Tp, _Lock_policy _Lp> |
1034 | class __shared_ptr |
1035 | : public __shared_ptr_access<_Tp, _Lp> |
1036 | { |
1037 | public: |
1038 | using element_type = typename remove_extent<_Tp>::type; |
1039 | |
1040 | private: |
1041 | |
1042 | template<typename _Yp> |
1043 | using _SafeConv |
1044 | = typename enable_if<__sp_is_constructible<_Tp, _Yp>::value>::type; |
1045 | |
1046 | |
1047 | template<typename _Yp, typename _Res = void> |
1048 | using _Compatible = typename |
1049 | enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type; |
1050 | |
1051 | |
1052 | template<typename _Yp> |
1053 | using _Assignable = _Compatible<_Yp, __shared_ptr&>; |
1054 | |
1055 | |
1056 | template<typename _Yp, typename _Del, typename _Res = void, |
1057 | typename _Ptr = typename unique_ptr<_Yp, _Del>::pointer> |
1058 | using _UniqCompatible = typename enable_if<__and_< |
1059 | __sp_compatible_with<_Yp*, _Tp*>, is_convertible<_Ptr, element_type*> |
1060 | >::value, _Res>::type; |
1061 | |
1062 | |
1063 | template<typename _Yp, typename _Del> |
1064 | using _UniqAssignable = _UniqCompatible<_Yp, _Del, __shared_ptr&>; |
1065 | |
1066 | public: |
1067 | |
1068 | #if __cplusplus201103L > 201402L |
1069 | using weak_type = __weak_ptr<_Tp, _Lp>; |
1070 | #endif |
1071 | |
1072 | constexpr __shared_ptr() noexcept |
1073 | : _M_ptr(0), _M_refcount() |
1074 | { } |
1075 | |
1076 | template<typename _Yp, typename = _SafeConv<_Yp>> |
1077 | explicit |
1078 | __shared_ptr(_Yp* __p) |
1079 | : _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type()) |
1080 | { |
1081 | static_assert( !is_void<_Yp>::value, "incomplete type" ); |
1082 | static_assert( sizeof(_Yp) > 0, "incomplete type" ); |
1083 | _M_enable_shared_from_this_with(__p); |
1084 | } |
1085 | |
1086 | template<typename _Yp, typename _Deleter, typename = _SafeConv<_Yp>> |
1087 | __shared_ptr(_Yp* __p, _Deleter __d) |
1088 | : _M_ptr(__p), _M_refcount(__p, std::move(__d)) |
1089 | { |
1090 | static_assert(__is_invocable<_Deleter&, _Yp*&>::value, |
1091 | "deleter expression d(p) is well-formed"); |
1092 | _M_enable_shared_from_this_with(__p); |
1093 | } |
1094 | |
1095 | template<typename _Yp, typename _Deleter, typename _Alloc, |
1096 | typename = _SafeConv<_Yp>> |
1097 | __shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a) |
1098 | : _M_ptr(__p), _M_refcount(__p, std::move(__d), std::move(__a)) |
1099 | { |
1100 | static_assert(__is_invocable<_Deleter&, _Yp*&>::value, |
1101 | "deleter expression d(p) is well-formed"); |
1102 | _M_enable_shared_from_this_with(__p); |
1103 | } |
1104 | |
1105 | template<typename _Deleter> |
1106 | __shared_ptr(nullptr_t __p, _Deleter __d) |
1107 | : _M_ptr(0), _M_refcount(__p, std::move(__d)) |
1108 | { } |
1109 | |
1110 | template<typename _Deleter, typename _Alloc> |
1111 | __shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a) |
1112 | : _M_ptr(0), _M_refcount(__p, std::move(__d), std::move(__a)) |
1113 | { } |
1114 | |
1115 | template<typename _Yp> |
1116 | __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r, |
1117 | element_type* __p) noexcept |
1118 | : _M_ptr(__p), _M_refcount(__r._M_refcount) |
1119 | { } |
1120 | |
1121 | __shared_ptr(const __shared_ptr&) noexcept = default; |
1122 | __shared_ptr& operator=(const __shared_ptr&) noexcept = default; |
| 25 | | Calling copy assignment operator for '__shared_count' | |
|
| 38 | | Returning; memory was released | |
|
| 56 | | Calling copy assignment operator for '__shared_count' | |
|
1123 | ~__shared_ptr() = default; |
1124 | |
1125 | template<typename _Yp, typename = _Compatible<_Yp>> |
1126 | __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept |
1127 | : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) |
1128 | { } |
1129 | |
1130 | __shared_ptr(__shared_ptr&& __r) noexcept |
1131 | : _M_ptr(__r._M_ptr), _M_refcount() |
1132 | { |
1133 | _M_refcount._M_swap(__r._M_refcount); |
1134 | __r._M_ptr = 0; |
1135 | } |
1136 | |
1137 | template<typename _Yp, typename = _Compatible<_Yp>> |
1138 | __shared_ptr(__shared_ptr<_Yp, _Lp>&& __r) noexcept |
1139 | : _M_ptr(__r._M_ptr), _M_refcount() |
1140 | { |
1141 | _M_refcount._M_swap(__r._M_refcount); |
1142 | __r._M_ptr = 0; |
1143 | } |
1144 | |
1145 | template<typename _Yp, typename = _Compatible<_Yp>> |
1146 | explicit __shared_ptr(const __weak_ptr<_Yp, _Lp>& __r) |
1147 | : _M_refcount(__r._M_refcount) |
1148 | { |
1149 | |
1150 | |
1151 | _M_ptr = __r._M_ptr; |
1152 | } |
1153 | |
1154 | |
1155 | template<typename _Yp, typename _Del, |
1156 | typename = _UniqCompatible<_Yp, _Del>> |
1157 | __shared_ptr(unique_ptr<_Yp, _Del>&& __r) |
1158 | : _M_ptr(__r.get()), _M_refcount() |
1159 | { |
1160 | auto __raw = _S_raw_ptr(__r.get()); |
1161 | _M_refcount = __shared_count<_Lp>(std::move(__r)); |
1162 | _M_enable_shared_from_this_with(__raw); |
1163 | } |
1164 | |
1165 | #if __cplusplus201103L <= 201402L && _GLIBCXX_USE_DEPRECATED1 |
1166 | protected: |
1167 | |
1168 | template<typename _Tp1, typename _Del, |
1169 | typename enable_if<__and_< |
1170 | __not_<is_array<_Tp>>, is_array<_Tp1>, |
1171 | is_convertible<typename unique_ptr<_Tp1, _Del>::pointer, _Tp*> |
1172 | >::value, bool>::type = true> |
1173 | __shared_ptr(unique_ptr<_Tp1, _Del>&& __r, __sp_array_delete) |
1174 | : _M_ptr(__r.get()), _M_refcount() |
1175 | { |
1176 | auto __raw = _S_raw_ptr(__r.get()); |
1177 | _M_refcount = __shared_count<_Lp>(std::move(__r)); |
1178 | _M_enable_shared_from_this_with(__raw); |
1179 | } |
1180 | public: |
1181 | #endif |
1182 | |
1183 | #if _GLIBCXX_USE_DEPRECATED1 |
1184 | |
1185 | template<typename _Yp, typename = _Compatible<_Yp>> |
1186 | __shared_ptr(auto_ptr<_Yp>&& __r); |
1187 | #endif |
1188 | |
1189 | constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { } |
1190 | |
1191 | template<typename _Yp> |
1192 | _Assignable<_Yp> |
1193 | operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept |
1194 | { |
1195 | _M_ptr = __r._M_ptr; |
1196 | _M_refcount = __r._M_refcount; |
1197 | return *this; |
1198 | } |
1199 | |
1200 | #if _GLIBCXX_USE_DEPRECATED1 |
1201 | template<typename _Yp> |
1202 | _Assignable<_Yp> |
1203 | operator=(auto_ptr<_Yp>&& __r) |
1204 | { |
1205 | __shared_ptr(std::move(__r)).swap(*this); |
1206 | return *this; |
1207 | } |
1208 | #endif |
1209 | |
1210 | __shared_ptr& |
1211 | operator=(__shared_ptr&& __r) noexcept |
1212 | { |
1213 | __shared_ptr(std::move(__r)).swap(*this); |
1214 | return *this; |
1215 | } |
1216 | |
1217 | template<class _Yp> |
1218 | _Assignable<_Yp> |
1219 | operator=(__shared_ptr<_Yp, _Lp>&& __r) noexcept |
1220 | { |
1221 | __shared_ptr(std::move(__r)).swap(*this); |
1222 | return *this; |
1223 | } |
1224 | |
1225 | template<typename _Yp, typename _Del> |
1226 | _UniqAssignable<_Yp, _Del> |
1227 | operator=(unique_ptr<_Yp, _Del>&& __r) |
1228 | { |
1229 | __shared_ptr(std::move(__r)).swap(*this); |
1230 | return *this; |
1231 | } |
1232 | |
1233 | void |
1234 | reset() noexcept |
1235 | { __shared_ptr().swap(*this); } |
1236 | |
1237 | template<typename _Yp> |
1238 | _SafeConv<_Yp> |
1239 | reset(_Yp* __p) |
1240 | { |
1241 | |
1242 | __glibcxx_assert(__p == 0 || __p != _M_ptr); |
1243 | __shared_ptr(__p).swap(*this); |
1244 | } |
1245 | |
1246 | template<typename _Yp, typename _Deleter> |
1247 | _SafeConv<_Yp> |
1248 | reset(_Yp* __p, _Deleter __d) |
1249 | { __shared_ptr(__p, std::move(__d)).swap(*this); } |
1250 | |
1251 | template<typename _Yp, typename _Deleter, typename _Alloc> |
1252 | _SafeConv<_Yp> |
1253 | reset(_Yp* __p, _Deleter __d, _Alloc __a) |
1254 | { __shared_ptr(__p, std::move(__d), std::move(__a)).swap(*this); } |
1255 | |
1256 | element_type* |
1257 | get() const noexcept |
1258 | { return _M_ptr; } |
1259 | |
1260 | explicit operator bool() const |
1261 | { return _M_ptr == 0 ? false : true; } |
1262 | |
1263 | bool |
1264 | unique() const noexcept |
1265 | { return _M_refcount._M_unique(); } |
1266 | |
1267 | long |
1268 | use_count() const noexcept |
1269 | { return _M_refcount._M_get_use_count(); } |
1270 | |
1271 | void |
1272 | swap(__shared_ptr<_Tp, _Lp>& __other) noexcept |
1273 | { |
1274 | std::swap(_M_ptr, __other._M_ptr); |
1275 | _M_refcount._M_swap(__other._M_refcount); |
1276 | } |
1277 | |
1278 | template<typename _Tp1> |
1279 | bool |
1280 | owner_before(__shared_ptr<_Tp1, _Lp> const& __rhs) const noexcept |
1281 | { return _M_refcount._M_less(__rhs._M_refcount); } |
1282 | |
1283 | template<typename _Tp1> |
1284 | bool |
1285 | owner_before(__weak_ptr<_Tp1, _Lp> const& __rhs) const noexcept |
1286 | { return _M_refcount._M_less(__rhs._M_refcount); } |
1287 | |
1288 | #if __cpp_rtti199711 |
1289 | protected: |
1290 | |
1291 | template<typename _Alloc, typename... _Args> |
1292 | __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a, |
1293 | _Args&&... __args) |
1294 | : _M_ptr(), _M_refcount(__tag, (_Tp*)0, __a, |
1295 | std::forward<_Args>(__args)...) |
1296 | { |
1297 | |
1298 | |
1299 | void* __p = _M_refcount._M_get_deleter(typeid(__tag)); |
1300 | _M_ptr = static_cast<_Tp*>(__p); |
1301 | _M_enable_shared_from_this_with(_M_ptr); |
1302 | } |
1303 | #else |
1304 | template<typename _Alloc> |
1305 | struct _Deleter |
1306 | { |
1307 | void operator()(typename _Alloc::value_type* __ptr) |
1308 | { |
1309 | __allocated_ptr<_Alloc> __guard{ _M_alloc, __ptr }; |
1310 | allocator_traits<_Alloc>::destroy(_M_alloc, __guard.get()); |
1311 | } |
1312 | _Alloc _M_alloc; |
1313 | }; |
1314 | |
1315 | template<typename _Alloc, typename... _Args> |
1316 | __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a, |
1317 | _Args&&... __args) |
1318 | : _M_ptr(), _M_refcount() |
1319 | { |
1320 | typedef typename allocator_traits<_Alloc>::template |
1321 | rebind_traits<typename std::remove_cv<_Tp>::type> __traits; |
1322 | _Deleter<typename __traits::allocator_type> __del = { __a }; |
1323 | auto __guard = std::__allocate_guarded(__del._M_alloc); |
1324 | auto __ptr = __guard.get(); |
1325 | |
1326 | |
1327 | __traits::construct(__del._M_alloc, __ptr, |
1328 | std::forward<_Args>(__args)...); |
1329 | __guard = nullptr; |
1330 | __shared_count<_Lp> __count(__ptr, __del, __del._M_alloc); |
1331 | _M_refcount._M_swap(__count); |
1332 | _M_ptr = __ptr; |
1333 | _M_enable_shared_from_this_with(_M_ptr); |
1334 | } |
1335 | #endif |
1336 | |
1337 | template<typename _Tp1, _Lock_policy _Lp1, typename _Alloc, |
1338 | typename... _Args> |
1339 | friend __shared_ptr<_Tp1, _Lp1> |
1340 | __allocate_shared(const _Alloc& __a, _Args&&... __args); |
1341 | |
1342 | |
1343 | |
1344 | __shared_ptr(const __weak_ptr<_Tp, _Lp>& __r, std::nothrow_t) |
1345 | : _M_refcount(__r._M_refcount, std::nothrow) |
1346 | { |
1347 | _M_ptr = _M_refcount._M_get_use_count() ? __r._M_ptr : nullptr; |
1348 | } |
1349 | |
1350 | friend class __weak_ptr<_Tp, _Lp>; |
1351 | |
1352 | private: |
1353 | |
1354 | template<typename _Yp> |
1355 | using __esft_base_t = decltype(__enable_shared_from_this_base( |
1356 | std::declval<const __shared_count<_Lp>&>(), |
1357 | std::declval<_Yp*>())); |
1358 | |
1359 | |
1360 | template<typename _Yp, typename = void> |
1361 | struct __has_esft_base |
1362 | : false_type { }; |
1363 | |
1364 | template<typename _Yp> |
1365 | struct __has_esft_base<_Yp, __void_t<__esft_base_t<_Yp>>> |
1366 | : __not_<is_array<_Tp>> { }; |
1367 | |
1368 | template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type> |
1369 | typename enable_if<__has_esft_base<_Yp2>::value>::type |
1370 | _M_enable_shared_from_this_with(_Yp* __p) noexcept |
1371 | { |
1372 | if (auto __base = __enable_shared_from_this_base(_M_refcount, __p)) |
1373 | __base->_M_weak_assign(const_cast<_Yp2*>(__p), _M_refcount); |
1374 | } |
1375 | |
1376 | template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type> |
1377 | typename enable_if<!__has_esft_base<_Yp2>::value>::type |
1378 | _M_enable_shared_from_this_with(_Yp*) noexcept |
1379 | { } |
1380 | |
1381 | void* |
1382 | _M_get_deleter(const std::type_info& __ti) const noexcept |
1383 | { return _M_refcount._M_get_deleter(__ti); } |
1384 | |
1385 | template<typename _Tp1> |
1386 | static _Tp1* |
1387 | _S_raw_ptr(_Tp1* __ptr) |
1388 | { return __ptr; } |
1389 | |
1390 | template<typename _Tp1> |
1391 | static auto |
1392 | _S_raw_ptr(_Tp1 __ptr) -> decltype(std::__addressof(*__ptr)) |
1393 | { return std::__addressof(*__ptr); } |
1394 | |
1395 | template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr; |
1396 | template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr; |
1397 | |
1398 | template<typename _Del, typename _Tp1, _Lock_policy _Lp1> |
1399 | friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&) noexcept; |
1400 | |
1401 | element_type* _M_ptr; |
1402 | __shared_count<_Lp> _M_refcount; |
1403 | }; |
1404 | |
1405 | |
1406 | |
1407 | template<typename _Tp1, typename _Tp2, _Lock_policy _Lp> |
1408 | inline bool |
1409 | operator==(const __shared_ptr<_Tp1, _Lp>& __a, |
1410 | const __shared_ptr<_Tp2, _Lp>& __b) noexcept |
1411 | { return __a.get() == __b.get(); } |
1412 | |
1413 | template<typename _Tp, _Lock_policy _Lp> |
1414 | inline bool |
1415 | operator==(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept |
1416 | { return !__a; } |
1417 | |
1418 | template<typename _Tp, _Lock_policy _Lp> |
1419 | inline bool |
1420 | operator==(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept |
1421 | { return !__a; } |
1422 | |
1423 | template<typename _Tp1, typename _Tp2, _Lock_policy _Lp> |
1424 | inline bool |
1425 | operator!=(const __shared_ptr<_Tp1, _Lp>& __a, |
1426 | const __shared_ptr<_Tp2, _Lp>& __b) noexcept |
1427 | { return __a.get() != __b.get(); } |
1428 | |
1429 | template<typename _Tp, _Lock_policy _Lp> |
1430 | inline bool |
1431 | operator!=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept |
1432 | { return (bool)__a; } |
1433 | |
1434 | template<typename _Tp, _Lock_policy _Lp> |
1435 | inline bool |
1436 | operator!=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept |
1437 | { return (bool)__a; } |
1438 | |
1439 | template<typename _Tp, typename _Up, _Lock_policy _Lp> |
1440 | inline bool |
1441 | operator<(const __shared_ptr<_Tp, _Lp>& __a, |
1442 | const __shared_ptr<_Up, _Lp>& __b) noexcept |
1443 | { |
1444 | using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type; |
1445 | using _Up_elt = typename __shared_ptr<_Up, _Lp>::element_type; |
1446 | using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type; |
1447 | return less<_Vp>()(__a.get(), __b.get()); |
1448 | } |
1449 | |
1450 | template<typename _Tp, _Lock_policy _Lp> |
1451 | inline bool |
1452 | operator<(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept |
1453 | { |
1454 | using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type; |
1455 | return less<_Tp_elt*>()(__a.get(), nullptr); |
1456 | } |
1457 | |
1458 | template<typename _Tp, _Lock_policy _Lp> |
1459 | inline bool |
1460 | operator<(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept |
1461 | { |
1462 | using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type; |
1463 | return less<_Tp_elt*>()(nullptr, __a.get()); |
1464 | } |
1465 | |
1466 | template<typename _Tp1, typename _Tp2, _Lock_policy _Lp> |
1467 | inline bool |
1468 | operator<=(const __shared_ptr<_Tp1, _Lp>& __a, |
1469 | const __shared_ptr<_Tp2, _Lp>& __b) noexcept |
1470 | { return !(__b < __a); } |
1471 | |
1472 | template<typename _Tp, _Lock_policy _Lp> |
1473 | inline bool |
1474 | operator<=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept |
1475 | { return !(nullptr < __a); } |
1476 | |
1477 | template<typename _Tp, _Lock_policy _Lp> |
1478 | inline bool |
1479 | operator<=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept |
1480 | { return !(__a < nullptr); } |
1481 | |
1482 | template<typename _Tp1, typename _Tp2, _Lock_policy _Lp> |
1483 | inline bool |
1484 | operator>(const __shared_ptr<_Tp1, _Lp>& __a, |
1485 | const __shared_ptr<_Tp2, _Lp>& __b) noexcept |
1486 | { return (__b < __a); } |
1487 | |
1488 | template<typename _Tp, _Lock_policy _Lp> |
1489 | inline bool |
1490 | operator>(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept |
1491 | { return nullptr < __a; } |
1492 | |
1493 | template<typename _Tp, _Lock_policy _Lp> |
1494 | inline bool |
1495 | operator>(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept |
1496 | { return __a < nullptr; } |
1497 | |
1498 | template<typename _Tp1, typename _Tp2, _Lock_policy _Lp> |
1499 | inline bool |
1500 | operator>=(const __shared_ptr<_Tp1, _Lp>& __a, |
1501 | const __shared_ptr<_Tp2, _Lp>& __b) noexcept |
1502 | { return !(__a < __b); } |
1503 | |
1504 | template<typename _Tp, _Lock_policy _Lp> |
1505 | inline bool |
1506 | operator>=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept |
1507 | { return !(__a < nullptr); } |
1508 | |
1509 | template<typename _Tp, _Lock_policy _Lp> |
1510 | inline bool |
1511 | operator>=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept |
1512 | { return !(nullptr < __a); } |
1513 | |
1514 | template<typename _Sp> |
1515 | struct _Sp_less : public binary_function<_Sp, _Sp, bool> |
1516 | { |
1517 | bool |
1518 | operator()(const _Sp& __lhs, const _Sp& __rhs) const noexcept |
1519 | { |
1520 | typedef typename _Sp::element_type element_type; |
1521 | return std::less<element_type*>()(__lhs.get(), __rhs.get()); |
1522 | } |
1523 | }; |
1524 | |
1525 | template<typename _Tp, _Lock_policy _Lp> |
1526 | struct less<__shared_ptr<_Tp, _Lp>> |
1527 | : public _Sp_less<__shared_ptr<_Tp, _Lp>> |
1528 | { }; |
1529 | |
1530 | |
1531 | template<typename _Tp, _Lock_policy _Lp> |
1532 | inline void |
1533 | swap(__shared_ptr<_Tp, _Lp>& __a, __shared_ptr<_Tp, _Lp>& __b) noexcept |
1534 | { __a.swap(__b); } |
1535 | |
1536 | |
1537 | |
1538 | |
1539 | |
1540 | |
1541 | |
1542 | |
1543 | template<typename _Tp, typename _Tp1, _Lock_policy _Lp> |
1544 | inline __shared_ptr<_Tp, _Lp> |
1545 | static_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept |
1546 | { |
1547 | using _Sp = __shared_ptr<_Tp, _Lp>; |
1548 | return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get())); |
1549 | } |
1550 | |
1551 | |
1552 | |
1553 | |
1554 | |
1555 | |
1556 | template<typename _Tp, typename _Tp1, _Lock_policy _Lp> |
1557 | inline __shared_ptr<_Tp, _Lp> |
1558 | const_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept |
1559 | { |
1560 | using _Sp = __shared_ptr<_Tp, _Lp>; |
1561 | return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get())); |
1562 | } |
1563 | |
1564 | |
1565 | |
1566 | |
1567 | |
1568 | |
1569 | template<typename _Tp, typename _Tp1, _Lock_policy _Lp> |
1570 | inline __shared_ptr<_Tp, _Lp> |
1571 | dynamic_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept |
1572 | { |
1573 | using _Sp = __shared_ptr<_Tp, _Lp>; |
1574 | if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get())) |
1575 | return _Sp(__r, __p); |
1576 | return _Sp(); |
1577 | } |
1578 | |
1579 | #if __cplusplus201103L > 201402L |
1580 | template<typename _Tp, typename _Tp1, _Lock_policy _Lp> |
1581 | inline __shared_ptr<_Tp, _Lp> |
1582 | reinterpret_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept |
1583 | { |
1584 | using _Sp = __shared_ptr<_Tp, _Lp>; |
1585 | return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get())); |
1586 | } |
1587 | #endif |
1588 | |
1589 | template<typename _Tp, _Lock_policy _Lp> |
1590 | class __weak_ptr |
1591 | { |
1592 | template<typename _Yp, typename _Res = void> |
1593 | using _Compatible = typename |
1594 | enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type; |
1595 | |
1596 | |
1597 | template<typename _Yp> |
1598 | using _Assignable = _Compatible<_Yp, __weak_ptr&>; |
1599 | |
1600 | public: |
1601 | using element_type = typename remove_extent<_Tp>::type; |
1602 | |
1603 | constexpr __weak_ptr() noexcept |
1604 | : _M_ptr(nullptr), _M_refcount() |
1605 | { } |
1606 | |
1607 | __weak_ptr(const __weak_ptr&) noexcept = default; |
1608 | |
1609 | ~__weak_ptr() = default; |
1610 | |
1611 | |
1612 | |
1613 | |
1614 | |
1615 | |
1616 | |
1617 | |
1618 | |
1619 | |
1620 | |
1621 | |
1622 | |
1623 | |
1624 | |
1625 | template<typename _Yp, typename = _Compatible<_Yp>> |
1626 | __weak_ptr(const __weak_ptr<_Yp, _Lp>& __r) noexcept |
1627 | : _M_refcount(__r._M_refcount) |
1628 | { _M_ptr = __r.lock().get(); } |
1629 | |
1630 | template<typename _Yp, typename = _Compatible<_Yp>> |
1631 | __weak_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept |
1632 | : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) |
1633 | { } |
1634 | |
1635 | __weak_ptr(__weak_ptr&& __r) noexcept |
1636 | : _M_ptr(__r._M_ptr), _M_refcount(std::move(__r._M_refcount)) |
1637 | { __r._M_ptr = nullptr; } |
1638 | |
1639 | template<typename _Yp, typename = _Compatible<_Yp>> |
1640 | __weak_ptr(__weak_ptr<_Yp, _Lp>&& __r) noexcept |
1641 | : _M_ptr(__r.lock().get()), _M_refcount(std::move(__r._M_refcount)) |
1642 | { __r._M_ptr = nullptr; } |
1643 | |
1644 | __weak_ptr& |
1645 | operator=(const __weak_ptr& __r) noexcept = default; |
1646 | |
1647 | template<typename _Yp> |
1648 | _Assignable<_Yp> |
1649 | operator=(const __weak_ptr<_Yp, _Lp>& __r) noexcept |
1650 | { |
1651 | _M_ptr = __r.lock().get(); |
1652 | _M_refcount = __r._M_refcount; |
1653 | return *this; |
1654 | } |
1655 | |
1656 | template<typename _Yp> |
1657 | _Assignable<_Yp> |
1658 | operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept |
1659 | { |
1660 | _M_ptr = __r._M_ptr; |
1661 | _M_refcount = __r._M_refcount; |
1662 | return *this; |
1663 | } |
1664 | |
1665 | __weak_ptr& |
1666 | operator=(__weak_ptr&& __r) noexcept |
1667 | { |
1668 | _M_ptr = __r._M_ptr; |
1669 | _M_refcount = std::move(__r._M_refcount); |
1670 | __r._M_ptr = nullptr; |
1671 | return *this; |
1672 | } |
1673 | |
1674 | template<typename _Yp> |
1675 | _Assignable<_Yp> |
1676 | operator=(__weak_ptr<_Yp, _Lp>&& __r) noexcept |
1677 | { |
1678 | _M_ptr = __r.lock().get(); |
1679 | _M_refcount = std::move(__r._M_refcount); |
1680 | __r._M_ptr = nullptr; |
1681 | return *this; |
1682 | } |
1683 | |
1684 | __shared_ptr<_Tp, _Lp> |
1685 | lock() const noexcept |
1686 | { return __shared_ptr<element_type, _Lp>(*this, std::nothrow); } |
1687 | |
1688 | long |
1689 | use_count() const noexcept |
1690 | { return _M_refcount._M_get_use_count(); } |
1691 | |
1692 | bool |
1693 | expired() const noexcept |
1694 | { return _M_refcount._M_get_use_count() == 0; } |
1695 | |
1696 | template<typename _Tp1> |
1697 | bool |
1698 | owner_before(const __shared_ptr<_Tp1, _Lp>& __rhs) const noexcept |
1699 | { return _M_refcount._M_less(__rhs._M_refcount); } |
1700 | |
1701 | template<typename _Tp1> |
1702 | bool |
1703 | owner_before(const __weak_ptr<_Tp1, _Lp>& __rhs) const noexcept |
1704 | { return _M_refcount._M_less(__rhs._M_refcount); } |
1705 | |
1706 | void |
1707 | reset() noexcept |
1708 | { __weak_ptr().swap(*this); } |
1709 | |
1710 | void |
1711 | swap(__weak_ptr& __s) noexcept |
1712 | { |
1713 | std::swap(_M_ptr, __s._M_ptr); |
1714 | _M_refcount._M_swap(__s._M_refcount); |
1715 | } |
1716 | |
1717 | private: |
1718 | |
1719 | void |
1720 | _M_assign(_Tp* __ptr, const __shared_count<_Lp>& __refcount) noexcept |
1721 | { |
1722 | if (use_count() == 0) |
1723 | { |
1724 | _M_ptr = __ptr; |
1725 | _M_refcount = __refcount; |
1726 | } |
1727 | } |
1728 | |
1729 | template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr; |
1730 | template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr; |
1731 | friend class __enable_shared_from_this<_Tp, _Lp>; |
1732 | friend class enable_shared_from_this<_Tp>; |
1733 | |
1734 | element_type* _M_ptr; |
1735 | __weak_count<_Lp> _M_refcount; |
1736 | }; |
1737 | |
1738 | |
1739 | template<typename _Tp, _Lock_policy _Lp> |
1740 | inline void |
1741 | swap(__weak_ptr<_Tp, _Lp>& __a, __weak_ptr<_Tp, _Lp>& __b) noexcept |
1742 | { __a.swap(__b); } |
1743 | |
1744 | template<typename _Tp, typename _Tp1> |
1745 | struct _Sp_owner_less : public binary_function<_Tp, _Tp, bool> |
1746 | { |
1747 | bool |
1748 | operator()(const _Tp& __lhs, const _Tp& __rhs) const noexcept |
1749 | { return __lhs.owner_before(__rhs); } |
1750 | |
1751 | bool |
1752 | operator()(const _Tp& __lhs, const _Tp1& __rhs) const noexcept |
1753 | { return __lhs.owner_before(__rhs); } |
1754 | |
1755 | bool |
1756 | operator()(const _Tp1& __lhs, const _Tp& __rhs) const noexcept |
1757 | { return __lhs.owner_before(__rhs); } |
1758 | }; |
1759 | |
1760 | template<> |
1761 | struct _Sp_owner_less<void, void> |
1762 | { |
1763 | template<typename _Tp, typename _Up> |
1764 | auto |
1765 | operator()(const _Tp& __lhs, const _Up& __rhs) const noexcept |
1766 | -> decltype(__lhs.owner_before(__rhs)) |
1767 | { return __lhs.owner_before(__rhs); } |
1768 | |
1769 | using is_transparent = void; |
1770 | }; |
1771 | |
1772 | template<typename _Tp, _Lock_policy _Lp> |
1773 | struct owner_less<__shared_ptr<_Tp, _Lp>> |
1774 | : public _Sp_owner_less<__shared_ptr<_Tp, _Lp>, __weak_ptr<_Tp, _Lp>> |
1775 | { }; |
1776 | |
1777 | template<typename _Tp, _Lock_policy _Lp> |
1778 | struct owner_less<__weak_ptr<_Tp, _Lp>> |
1779 | : public _Sp_owner_less<__weak_ptr<_Tp, _Lp>, __shared_ptr<_Tp, _Lp>> |
1780 | { }; |
1781 | |
1782 | |
1783 | template<typename _Tp, _Lock_policy _Lp> |
1784 | class __enable_shared_from_this |
1785 | { |
1786 | protected: |
1787 | constexpr __enable_shared_from_this() noexcept { } |
1788 | |
1789 | __enable_shared_from_this(const __enable_shared_from_this&) noexcept { } |
1790 | |
1791 | __enable_shared_from_this& |
1792 | operator=(const __enable_shared_from_this&) noexcept |
1793 | { return *this; } |
1794 | |
1795 | ~__enable_shared_from_this() { } |
1796 | |
1797 | public: |
1798 | __shared_ptr<_Tp, _Lp> |
1799 | shared_from_this() |
1800 | { return __shared_ptr<_Tp, _Lp>(this->_M_weak_this); } |
1801 | |
1802 | __shared_ptr<const _Tp, _Lp> |
1803 | shared_from_this() const |
1804 | { return __shared_ptr<const _Tp, _Lp>(this->_M_weak_this); } |
1805 | |
1806 | #if __cplusplus201103L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11 |
1807 | __weak_ptr<_Tp, _Lp> |
1808 | weak_from_this() noexcept |
1809 | { return this->_M_weak_this; } |
1810 | |
1811 | __weak_ptr<const _Tp, _Lp> |
1812 | weak_from_this() const noexcept |
1813 | { return this->_M_weak_this; } |
1814 | #endif |
1815 | |
1816 | private: |
1817 | template<typename _Tp1> |
1818 | void |
1819 | _M_weak_assign(_Tp1* __p, const __shared_count<_Lp>& __n) const noexcept |
1820 | { _M_weak_this._M_assign(__p, __n); } |
1821 | |
1822 | friend const __enable_shared_from_this* |
1823 | __enable_shared_from_this_base(const __shared_count<_Lp>&, |
1824 | const __enable_shared_from_this* __p) |
1825 | { return __p; } |
1826 | |
1827 | template<typename, _Lock_policy> |
1828 | friend class __shared_ptr; |
1829 | |
1830 | mutable __weak_ptr<_Tp, _Lp> _M_weak_this; |
1831 | }; |
1832 | |
1833 | template<typename _Tp, _Lock_policy _Lp, typename _Alloc, typename... _Args> |
1834 | inline __shared_ptr<_Tp, _Lp> |
1835 | __allocate_shared(const _Alloc& __a, _Args&&... __args) |
1836 | { |
1837 | return __shared_ptr<_Tp, _Lp>(_Sp_make_shared_tag(), __a, |
1838 | std::forward<_Args>(__args)...); |
1839 | } |
1840 | |
1841 | template<typename _Tp, _Lock_policy _Lp, typename... _Args> |
1842 | inline __shared_ptr<_Tp, _Lp> |
1843 | __make_shared(_Args&&... __args) |
1844 | { |
1845 | typedef typename std::remove_const<_Tp>::type _Tp_nc; |
1846 | return std::__allocate_shared<_Tp, _Lp>(std::allocator<_Tp_nc>(), |
1847 | std::forward<_Args>(__args)...); |
1848 | } |
1849 | |
1850 | |
1851 | template<typename _Tp, _Lock_policy _Lp> |
1852 | struct hash<__shared_ptr<_Tp, _Lp>> |
1853 | : public __hash_base<size_t, __shared_ptr<_Tp, _Lp>> |
1854 | { |
1855 | size_t |
1856 | operator()(const __shared_ptr<_Tp, _Lp>& __s) const noexcept |
1857 | { |
1858 | return hash<typename __shared_ptr<_Tp, _Lp>::element_type*>()( |
1859 | __s.get()); |
1860 | } |
1861 | }; |
1862 | |
1863 | _GLIBCXX_END_NAMESPACE_VERSION |
1864 | } |
1865 | |
1866 | #endif // _SHARED_PTR_BASE_H |