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