[DAG] Fix typo in VSELECT SimplifyDemandedVectorElts handling. NFC.
[llvm-project.git] / lldb / source / Commands / CommandObjectType.cpp
blobf76420f3cc6837ff8376c449dc0b5b3cfbe76be7
1 //===-- CommandObjectType.cpp ---------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "CommandObjectType.h"
11 #include "lldb/Core/Debugger.h"
12 #include "lldb/Core/IOHandler.h"
13 #include "lldb/DataFormatters/DataVisualization.h"
14 #include "lldb/DataFormatters/FormatClasses.h"
15 #include "lldb/Host/Config.h"
16 #include "lldb/Host/OptionParser.h"
17 #include "lldb/Interpreter/CommandInterpreter.h"
18 #include "lldb/Interpreter/CommandObject.h"
19 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
20 #include "lldb/Interpreter/CommandReturnObject.h"
21 #include "lldb/Interpreter/OptionArgParser.h"
22 #include "lldb/Interpreter/OptionGroupFormat.h"
23 #include "lldb/Interpreter/OptionValueBoolean.h"
24 #include "lldb/Interpreter/OptionValueLanguage.h"
25 #include "lldb/Interpreter/OptionValueString.h"
26 #include "lldb/Interpreter/Options.h"
27 #include "lldb/Symbol/Symbol.h"
28 #include "lldb/Target/Language.h"
29 #include "lldb/Target/StackFrame.h"
30 #include "lldb/Target/Target.h"
31 #include "lldb/Target/Thread.h"
32 #include "lldb/Utility/ConstString.h"
33 #include "lldb/Utility/RegularExpression.h"
34 #include "lldb/Utility/StringList.h"
36 #include "llvm/ADT/STLExtras.h"
38 #include <algorithm>
39 #include <functional>
40 #include <memory>
42 using namespace lldb;
43 using namespace lldb_private;
45 class ScriptAddOptions {
46 public:
47 TypeSummaryImpl::Flags m_flags;
48 StringList m_target_types;
49 FormatterMatchType m_match_type;
50 ConstString m_name;
51 std::string m_category;
53 ScriptAddOptions(const TypeSummaryImpl::Flags &flags,
54 FormatterMatchType match_type, ConstString name,
55 std::string catg)
56 : m_flags(flags), m_match_type(match_type), m_name(name),
57 m_category(catg) {}
59 typedef std::shared_ptr<ScriptAddOptions> SharedPointer;
62 class SynthAddOptions {
63 public:
64 bool m_skip_pointers;
65 bool m_skip_references;
66 bool m_cascade;
67 FormatterMatchType m_match_type;
68 StringList m_target_types;
69 std::string m_category;
71 SynthAddOptions(bool sptr, bool sref, bool casc,
72 FormatterMatchType match_type, std::string catg)
73 : m_skip_pointers(sptr), m_skip_references(sref), m_cascade(casc),
74 m_match_type(match_type), m_category(catg) {}
76 typedef std::shared_ptr<SynthAddOptions> SharedPointer;
79 static bool WarnOnPotentialUnquotedUnsignedType(Args &command,
80 CommandReturnObject &result) {
81 if (command.empty())
82 return false;
84 for (auto entry : llvm::enumerate(command.entries().drop_back())) {
85 if (entry.value().ref() != "unsigned")
86 continue;
87 auto next = command.entries()[entry.index() + 1].ref();
88 if (next == "int" || next == "short" || next == "char" || next == "long") {
89 result.AppendWarningWithFormat(
90 "unsigned %s being treated as two types. if you meant the combined "
91 "type "
92 "name use quotes, as in \"unsigned %s\"\n",
93 next.str().c_str(), next.str().c_str());
94 return true;
97 return false;
100 const char *FormatCategoryToString(FormatCategoryItem item, bool long_name) {
101 switch (item) {
102 case eFormatCategoryItemSummary:
103 return "summary";
104 case eFormatCategoryItemFilter:
105 return "filter";
106 case eFormatCategoryItemSynth:
107 if (long_name)
108 return "synthetic child provider";
109 return "synthetic";
110 case eFormatCategoryItemFormat:
111 return "format";
113 llvm_unreachable("Fully covered switch above!");
116 #define LLDB_OPTIONS_type_summary_add
117 #include "CommandOptions.inc"
119 class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
120 public IOHandlerDelegateMultiline {
121 private:
122 class CommandOptions : public Options {
123 public:
124 CommandOptions(CommandInterpreter &interpreter) {}
126 ~CommandOptions() override = default;
128 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
129 ExecutionContext *execution_context) override;
131 void OptionParsingStarting(ExecutionContext *execution_context) override;
133 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
134 return llvm::ArrayRef(g_type_summary_add_options);
137 // Instance variables to hold the values for command options.
139 TypeSummaryImpl::Flags m_flags;
140 FormatterMatchType m_match_type = eFormatterMatchExact;
141 std::string m_format_string;
142 ConstString m_name;
143 std::string m_python_script;
144 std::string m_python_function;
145 bool m_is_add_script = false;
146 std::string m_category;
149 CommandOptions m_options;
151 Options *GetOptions() override { return &m_options; }
153 bool Execute_ScriptSummary(Args &command, CommandReturnObject &result);
155 bool Execute_StringSummary(Args &command, CommandReturnObject &result);
157 public:
158 CommandObjectTypeSummaryAdd(CommandInterpreter &interpreter);
160 ~CommandObjectTypeSummaryAdd() override = default;
162 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
163 static const char *g_summary_addreader_instructions =
164 "Enter your Python command(s). Type 'DONE' to end.\n"
165 "def function (valobj,internal_dict):\n"
166 " \"\"\"valobj: an SBValue which you want to provide a summary "
167 "for\n"
168 " internal_dict: an LLDB support object not to be used\"\"\"\n";
170 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
171 if (output_sp && interactive) {
172 output_sp->PutCString(g_summary_addreader_instructions);
173 output_sp->Flush();
177 void IOHandlerInputComplete(IOHandler &io_handler,
178 std::string &data) override {
179 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
181 #if LLDB_ENABLE_PYTHON
182 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
183 if (interpreter) {
184 StringList lines;
185 lines.SplitIntoLines(data);
186 if (lines.GetSize() > 0) {
187 ScriptAddOptions *options_ptr =
188 ((ScriptAddOptions *)io_handler.GetUserData());
189 if (options_ptr) {
190 ScriptAddOptions::SharedPointer options(
191 options_ptr); // this will ensure that we get rid of the pointer
192 // when going out of scope
194 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
195 if (interpreter) {
196 std::string funct_name_str;
197 if (interpreter->GenerateTypeScriptFunction(lines,
198 funct_name_str)) {
199 if (funct_name_str.empty()) {
200 error_sp->Printf("unable to obtain a valid function name from "
201 "the script interpreter.\n");
202 error_sp->Flush();
203 } else {
204 // now I have a valid function name, let's add this as script
205 // for every type in the list
207 TypeSummaryImplSP script_format;
208 script_format = std::make_shared<ScriptSummaryFormat>(
209 options->m_flags, funct_name_str.c_str(),
210 lines.CopyList(" ").c_str());
212 Status error;
214 for (const std::string &type_name : options->m_target_types) {
215 AddSummary(ConstString(type_name), script_format,
216 options->m_match_type, options->m_category,
217 &error);
218 if (error.Fail()) {
219 error_sp->Printf("error: %s", error.AsCString());
220 error_sp->Flush();
224 if (options->m_name) {
225 CommandObjectTypeSummaryAdd::AddNamedSummary(
226 options->m_name, script_format, &error);
227 if (error.Fail()) {
228 CommandObjectTypeSummaryAdd::AddNamedSummary(
229 options->m_name, script_format, &error);
230 if (error.Fail()) {
231 error_sp->Printf("error: %s", error.AsCString());
232 error_sp->Flush();
234 } else {
235 error_sp->Printf("error: %s", error.AsCString());
236 error_sp->Flush();
238 } else {
239 if (error.AsCString()) {
240 error_sp->Printf("error: %s", error.AsCString());
241 error_sp->Flush();
245 } else {
246 error_sp->Printf("error: unable to generate a function.\n");
247 error_sp->Flush();
249 } else {
250 error_sp->Printf("error: no script interpreter.\n");
251 error_sp->Flush();
253 } else {
254 error_sp->Printf("error: internal synchronization information "
255 "missing or invalid.\n");
256 error_sp->Flush();
258 } else {
259 error_sp->Printf("error: empty function, didn't add python command.\n");
260 error_sp->Flush();
262 } else {
263 error_sp->Printf(
264 "error: script interpreter missing, didn't add python command.\n");
265 error_sp->Flush();
267 #endif
268 io_handler.SetIsDone(true);
271 bool AddSummary(ConstString type_name, lldb::TypeSummaryImplSP entry,
272 FormatterMatchType match_type, std::string category,
273 Status *error = nullptr);
275 bool AddNamedSummary(ConstString summary_name, lldb::TypeSummaryImplSP entry,
276 Status *error = nullptr);
278 protected:
279 void DoExecute(Args &command, CommandReturnObject &result) override;
282 static const char *g_synth_addreader_instructions =
283 "Enter your Python command(s). Type 'DONE' to end.\n"
284 "You must define a Python class with these methods:\n"
285 " def __init__(self, valobj, internal_dict):\n"
286 " def num_children(self):\n"
287 " def get_child_at_index(self, index):\n"
288 " def get_child_index(self, name):\n"
289 " def update(self):\n"
290 " '''Optional'''\n"
291 "class synthProvider:\n";
293 #define LLDB_OPTIONS_type_synth_add
294 #include "CommandOptions.inc"
296 class CommandObjectTypeSynthAdd : public CommandObjectParsed,
297 public IOHandlerDelegateMultiline {
298 private:
299 class CommandOptions : public Options {
300 public:
301 CommandOptions() = default;
303 ~CommandOptions() override = default;
305 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
306 ExecutionContext *execution_context) override {
307 Status error;
308 const int short_option = m_getopt_table[option_idx].val;
309 bool success;
311 switch (short_option) {
312 case 'C':
313 m_cascade = OptionArgParser::ToBoolean(option_arg, true, &success);
314 if (!success)
315 error.SetErrorStringWithFormat("invalid value for cascade: %s",
316 option_arg.str().c_str());
317 break;
318 case 'P':
319 handwrite_python = true;
320 break;
321 case 'l':
322 m_class_name = std::string(option_arg);
323 is_class_based = true;
324 break;
325 case 'p':
326 m_skip_pointers = true;
327 break;
328 case 'r':
329 m_skip_references = true;
330 break;
331 case 'w':
332 m_category = std::string(option_arg);
333 break;
334 case 'x':
335 if (m_match_type == eFormatterMatchCallback)
336 error.SetErrorString(
337 "can't use --regex and --recognizer-function at the same time");
338 else
339 m_match_type = eFormatterMatchRegex;
340 break;
341 case '\x01':
342 if (m_match_type == eFormatterMatchRegex)
343 error.SetErrorString(
344 "can't use --regex and --recognizer-function at the same time");
345 else
346 m_match_type = eFormatterMatchCallback;
347 break;
348 default:
349 llvm_unreachable("Unimplemented option");
352 return error;
355 void OptionParsingStarting(ExecutionContext *execution_context) override {
356 m_cascade = true;
357 m_class_name = "";
358 m_skip_pointers = false;
359 m_skip_references = false;
360 m_category = "default";
361 is_class_based = false;
362 handwrite_python = false;
363 m_match_type = eFormatterMatchExact;
366 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
367 return llvm::ArrayRef(g_type_synth_add_options);
370 // Instance variables to hold the values for command options.
372 bool m_cascade;
373 bool m_skip_references;
374 bool m_skip_pointers;
375 std::string m_class_name;
376 bool m_input_python;
377 std::string m_category;
378 bool is_class_based;
379 bool handwrite_python;
380 FormatterMatchType m_match_type;
383 CommandOptions m_options;
385 Options *GetOptions() override { return &m_options; }
387 bool Execute_HandwritePython(Args &command, CommandReturnObject &result);
389 bool Execute_PythonClass(Args &command, CommandReturnObject &result);
391 protected:
392 void DoExecute(Args &command, CommandReturnObject &result) override {
393 WarnOnPotentialUnquotedUnsignedType(command, result);
395 if (m_options.handwrite_python)
396 Execute_HandwritePython(command, result);
397 else if (m_options.is_class_based)
398 Execute_PythonClass(command, result);
399 else {
400 result.AppendError("must either provide a children list, a Python class "
401 "name, or use -P and type a Python class "
402 "line-by-line");
406 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
407 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
408 if (output_sp && interactive) {
409 output_sp->PutCString(g_synth_addreader_instructions);
410 output_sp->Flush();
414 void IOHandlerInputComplete(IOHandler &io_handler,
415 std::string &data) override {
416 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
418 #if LLDB_ENABLE_PYTHON
419 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
420 if (interpreter) {
421 StringList lines;
422 lines.SplitIntoLines(data);
423 if (lines.GetSize() > 0) {
424 SynthAddOptions *options_ptr =
425 ((SynthAddOptions *)io_handler.GetUserData());
426 if (options_ptr) {
427 SynthAddOptions::SharedPointer options(
428 options_ptr); // this will ensure that we get rid of the pointer
429 // when going out of scope
431 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
432 if (interpreter) {
433 std::string class_name_str;
434 if (interpreter->GenerateTypeSynthClass(lines, class_name_str)) {
435 if (class_name_str.empty()) {
436 error_sp->Printf(
437 "error: unable to obtain a proper name for the class.\n");
438 error_sp->Flush();
439 } else {
440 // everything should be fine now, let's add the synth provider
441 // class
443 SyntheticChildrenSP synth_provider;
444 synth_provider = std::make_shared<ScriptedSyntheticChildren>(
445 SyntheticChildren::Flags()
446 .SetCascades(options->m_cascade)
447 .SetSkipPointers(options->m_skip_pointers)
448 .SetSkipReferences(options->m_skip_references),
449 class_name_str.c_str());
451 lldb::TypeCategoryImplSP category;
452 DataVisualization::Categories::GetCategory(
453 ConstString(options->m_category.c_str()), category);
455 Status error;
457 for (const std::string &type_name : options->m_target_types) {
458 if (!type_name.empty()) {
459 if (AddSynth(ConstString(type_name), synth_provider,
460 options->m_match_type, options->m_category,
461 &error)) {
462 error_sp->Printf("error: %s\n", error.AsCString());
463 error_sp->Flush();
464 break;
466 } else {
467 error_sp->Printf("error: invalid type name.\n");
468 error_sp->Flush();
469 break;
473 } else {
474 error_sp->Printf("error: unable to generate a class.\n");
475 error_sp->Flush();
477 } else {
478 error_sp->Printf("error: no script interpreter.\n");
479 error_sp->Flush();
481 } else {
482 error_sp->Printf("error: internal synchronization data missing.\n");
483 error_sp->Flush();
485 } else {
486 error_sp->Printf("error: empty function, didn't add python command.\n");
487 error_sp->Flush();
489 } else {
490 error_sp->Printf(
491 "error: script interpreter missing, didn't add python command.\n");
492 error_sp->Flush();
495 #endif
496 io_handler.SetIsDone(true);
499 public:
500 CommandObjectTypeSynthAdd(CommandInterpreter &interpreter);
502 ~CommandObjectTypeSynthAdd() override = default;
504 bool AddSynth(ConstString type_name, lldb::SyntheticChildrenSP entry,
505 FormatterMatchType match_type, std::string category_name,
506 Status *error);
509 // CommandObjectTypeFormatAdd
511 #define LLDB_OPTIONS_type_format_add
512 #include "CommandOptions.inc"
514 class CommandObjectTypeFormatAdd : public CommandObjectParsed {
515 private:
516 class CommandOptions : public OptionGroup {
517 public:
518 CommandOptions() = default;
520 ~CommandOptions() override = default;
522 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
523 return llvm::ArrayRef(g_type_format_add_options);
526 void OptionParsingStarting(ExecutionContext *execution_context) override {
527 m_cascade = true;
528 m_skip_pointers = false;
529 m_skip_references = false;
530 m_regex = false;
531 m_category.assign("default");
532 m_custom_type_name.clear();
535 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
536 ExecutionContext *execution_context) override {
537 Status error;
538 const int short_option =
539 g_type_format_add_options[option_idx].short_option;
540 bool success;
542 switch (short_option) {
543 case 'C':
544 m_cascade = OptionArgParser::ToBoolean(option_value, true, &success);
545 if (!success)
546 error.SetErrorStringWithFormat("invalid value for cascade: %s",
547 option_value.str().c_str());
548 break;
549 case 'p':
550 m_skip_pointers = true;
551 break;
552 case 'w':
553 m_category.assign(std::string(option_value));
554 break;
555 case 'r':
556 m_skip_references = true;
557 break;
558 case 'x':
559 m_regex = true;
560 break;
561 case 't':
562 m_custom_type_name.assign(std::string(option_value));
563 break;
564 default:
565 llvm_unreachable("Unimplemented option");
568 return error;
571 // Instance variables to hold the values for command options.
573 bool m_cascade;
574 bool m_skip_references;
575 bool m_skip_pointers;
576 bool m_regex;
577 std::string m_category;
578 std::string m_custom_type_name;
581 OptionGroupOptions m_option_group;
582 OptionGroupFormat m_format_options;
583 CommandOptions m_command_options;
585 Options *GetOptions() override { return &m_option_group; }
587 public:
588 CommandObjectTypeFormatAdd(CommandInterpreter &interpreter)
589 : CommandObjectParsed(interpreter, "type format add",
590 "Add a new formatting style for a type.", nullptr),
591 m_format_options(eFormatInvalid) {
592 CommandArgumentEntry type_arg;
593 CommandArgumentData type_style_arg;
595 type_style_arg.arg_type = eArgTypeName;
596 type_style_arg.arg_repetition = eArgRepeatPlus;
598 type_arg.push_back(type_style_arg);
600 m_arguments.push_back(type_arg);
602 SetHelpLong(
604 The following examples of 'type format add' refer to this code snippet for context:
606 typedef int Aint;
607 typedef float Afloat;
608 typedef Aint Bint;
609 typedef Afloat Bfloat;
611 Aint ix = 5;
612 Bint iy = 5;
614 Afloat fx = 3.14;
615 BFloat fy = 3.14;
617 Adding default formatting:
619 (lldb) type format add -f hex AInt
620 (lldb) frame variable iy
623 " Produces hexadecimal display of iy, because no formatter is available for Bint and \
624 the one for Aint is used instead."
627 To prevent this use the cascade option '-C no' to prevent evaluation of typedef chains:
630 (lldb) type format add -f hex -C no AInt
632 Similar reasoning applies to this:
634 (lldb) type format add -f hex -C no float -p
637 " All float values and float references are now formatted as hexadecimal, but not \
638 pointers to floats. Nor will it change the default display for Afloat and Bfloat objects.");
640 // Add the "--format" to all options groups
641 m_option_group.Append(&m_format_options,
642 OptionGroupFormat::OPTION_GROUP_FORMAT,
643 LLDB_OPT_SET_1);
644 m_option_group.Append(&m_command_options);
645 m_option_group.Finalize();
648 ~CommandObjectTypeFormatAdd() override = default;
650 protected:
651 void DoExecute(Args &command, CommandReturnObject &result) override {
652 const size_t argc = command.GetArgumentCount();
654 if (argc < 1) {
655 result.AppendErrorWithFormat("%s takes one or more args.\n",
656 m_cmd_name.c_str());
657 return;
660 const Format format = m_format_options.GetFormat();
661 if (format == eFormatInvalid &&
662 m_command_options.m_custom_type_name.empty()) {
663 result.AppendErrorWithFormat("%s needs a valid format.\n",
664 m_cmd_name.c_str());
665 return;
668 TypeFormatImplSP entry;
670 if (m_command_options.m_custom_type_name.empty())
671 entry = std::make_shared<TypeFormatImpl_Format>(
672 format, TypeFormatImpl::Flags()
673 .SetCascades(m_command_options.m_cascade)
674 .SetSkipPointers(m_command_options.m_skip_pointers)
675 .SetSkipReferences(m_command_options.m_skip_references));
676 else
677 entry = std::make_shared<TypeFormatImpl_EnumType>(
678 ConstString(m_command_options.m_custom_type_name.c_str()),
679 TypeFormatImpl::Flags()
680 .SetCascades(m_command_options.m_cascade)
681 .SetSkipPointers(m_command_options.m_skip_pointers)
682 .SetSkipReferences(m_command_options.m_skip_references));
684 // now I have a valid format, let's add it to every type
686 TypeCategoryImplSP category_sp;
687 DataVisualization::Categories::GetCategory(
688 ConstString(m_command_options.m_category), category_sp);
689 if (!category_sp)
690 return;
692 WarnOnPotentialUnquotedUnsignedType(command, result);
694 for (auto &arg_entry : command.entries()) {
695 if (arg_entry.ref().empty()) {
696 result.AppendError("empty typenames not allowed");
697 return;
700 FormatterMatchType match_type = eFormatterMatchExact;
701 if (m_command_options.m_regex) {
702 match_type = eFormatterMatchRegex;
703 RegularExpression typeRX(arg_entry.ref());
704 if (!typeRX.IsValid()) {
705 result.AppendError(
706 "regex format error (maybe this is not really a regex?)");
707 return;
710 category_sp->AddTypeFormat(arg_entry.ref(), match_type, entry);
713 result.SetStatus(eReturnStatusSuccessFinishNoResult);
717 #define LLDB_OPTIONS_type_formatter_delete
718 #include "CommandOptions.inc"
720 class CommandObjectTypeFormatterDelete : public CommandObjectParsed {
721 protected:
722 class CommandOptions : public Options {
723 public:
724 CommandOptions() = default;
726 ~CommandOptions() override = default;
728 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
729 ExecutionContext *execution_context) override {
730 Status error;
731 const int short_option = m_getopt_table[option_idx].val;
733 switch (short_option) {
734 case 'a':
735 m_delete_all = true;
736 break;
737 case 'w':
738 m_category = std::string(option_arg);
739 break;
740 case 'l':
741 m_language = Language::GetLanguageTypeFromString(option_arg);
742 break;
743 default:
744 llvm_unreachable("Unimplemented option");
747 return error;
750 void OptionParsingStarting(ExecutionContext *execution_context) override {
751 m_delete_all = false;
752 m_category = "default";
753 m_language = lldb::eLanguageTypeUnknown;
756 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
757 return llvm::ArrayRef(g_type_formatter_delete_options);
760 // Instance variables to hold the values for command options.
762 bool m_delete_all;
763 std::string m_category;
764 lldb::LanguageType m_language;
767 CommandOptions m_options;
768 FormatCategoryItem m_formatter_kind;
770 Options *GetOptions() override { return &m_options; }
772 static constexpr const char *g_short_help_template =
773 "Delete an existing %s for a type.";
775 static constexpr const char *g_long_help_template =
776 "Delete an existing %s for a type. Unless you specify a "
777 "specific category or all categories, only the "
778 "'default' category is searched. The names must be exactly as "
779 "shown in the 'type %s list' output";
781 public:
782 CommandObjectTypeFormatterDelete(CommandInterpreter &interpreter,
783 FormatCategoryItem formatter_kind)
784 : CommandObjectParsed(interpreter,
785 FormatCategoryToString(formatter_kind, false)),
786 m_formatter_kind(formatter_kind) {
787 CommandArgumentEntry type_arg;
788 CommandArgumentData type_style_arg;
790 type_style_arg.arg_type = eArgTypeName;
791 type_style_arg.arg_repetition = eArgRepeatPlain;
793 type_arg.push_back(type_style_arg);
795 m_arguments.push_back(type_arg);
797 const char *kind = FormatCategoryToString(formatter_kind, true);
798 const char *short_kind = FormatCategoryToString(formatter_kind, false);
800 StreamString s;
801 s.Printf(g_short_help_template, kind);
802 SetHelp(s.GetData());
803 s.Clear();
804 s.Printf(g_long_help_template, kind, short_kind);
805 SetHelpLong(s.GetData());
806 s.Clear();
807 s.Printf("type %s delete", short_kind);
808 SetCommandName(s.GetData());
811 ~CommandObjectTypeFormatterDelete() override = default;
813 void
814 HandleArgumentCompletion(CompletionRequest &request,
815 OptionElementVector &opt_element_vector) override {
816 if (request.GetCursorIndex())
817 return;
819 DataVisualization::Categories::ForEach(
820 [this, &request](const lldb::TypeCategoryImplSP &category_sp) {
821 category_sp->AutoComplete(request, m_formatter_kind);
822 return true;
826 protected:
827 virtual bool FormatterSpecificDeletion(ConstString typeCS) { return false; }
829 void DoExecute(Args &command, CommandReturnObject &result) override {
830 const size_t argc = command.GetArgumentCount();
832 if (argc != 1) {
833 result.AppendErrorWithFormat("%s takes 1 arg.\n", m_cmd_name.c_str());
834 return;
837 const char *typeA = command.GetArgumentAtIndex(0);
838 ConstString typeCS(typeA);
840 if (!typeCS) {
841 result.AppendError("empty typenames not allowed");
842 return;
845 if (m_options.m_delete_all) {
846 DataVisualization::Categories::ForEach(
847 [this, typeCS](const lldb::TypeCategoryImplSP &category_sp) -> bool {
848 category_sp->Delete(typeCS, m_formatter_kind);
849 return true;
851 result.SetStatus(eReturnStatusSuccessFinishNoResult);
852 return;
855 bool delete_category = false;
856 bool extra_deletion = false;
858 if (m_options.m_language != lldb::eLanguageTypeUnknown) {
859 lldb::TypeCategoryImplSP category;
860 DataVisualization::Categories::GetCategory(m_options.m_language,
861 category);
862 if (category)
863 delete_category = category->Delete(typeCS, m_formatter_kind);
864 extra_deletion = FormatterSpecificDeletion(typeCS);
865 } else {
866 lldb::TypeCategoryImplSP category;
867 DataVisualization::Categories::GetCategory(
868 ConstString(m_options.m_category.c_str()), category);
869 if (category)
870 delete_category = category->Delete(typeCS, m_formatter_kind);
871 extra_deletion = FormatterSpecificDeletion(typeCS);
874 if (delete_category || extra_deletion) {
875 result.SetStatus(eReturnStatusSuccessFinishNoResult);
876 } else {
877 result.AppendErrorWithFormat("no custom formatter for %s.\n", typeA);
882 #define LLDB_OPTIONS_type_formatter_clear
883 #include "CommandOptions.inc"
885 class CommandObjectTypeFormatterClear : public CommandObjectParsed {
886 private:
887 class CommandOptions : public Options {
888 public:
889 CommandOptions() = default;
891 ~CommandOptions() override = default;
893 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
894 ExecutionContext *execution_context) override {
895 Status error;
896 const int short_option = m_getopt_table[option_idx].val;
898 switch (short_option) {
899 case 'a':
900 m_delete_all = true;
901 break;
902 default:
903 llvm_unreachable("Unimplemented option");
906 return error;
909 void OptionParsingStarting(ExecutionContext *execution_context) override {
910 m_delete_all = false;
913 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
914 return llvm::ArrayRef(g_type_formatter_clear_options);
917 // Instance variables to hold the values for command options.
918 bool m_delete_all;
921 CommandOptions m_options;
922 FormatCategoryItem m_formatter_kind;
924 Options *GetOptions() override { return &m_options; }
926 public:
927 CommandObjectTypeFormatterClear(CommandInterpreter &interpreter,
928 FormatCategoryItem formatter_kind,
929 const char *name, const char *help)
930 : CommandObjectParsed(interpreter, name, help, nullptr),
931 m_formatter_kind(formatter_kind) {
932 CommandArgumentData category_arg{eArgTypeName, eArgRepeatOptional};
933 m_arguments.push_back({category_arg});
936 ~CommandObjectTypeFormatterClear() override = default;
938 protected:
939 virtual void FormatterSpecificDeletion() {}
941 void DoExecute(Args &command, CommandReturnObject &result) override {
942 if (m_options.m_delete_all) {
943 DataVisualization::Categories::ForEach(
944 [this](const TypeCategoryImplSP &category_sp) -> bool {
945 category_sp->Clear(m_formatter_kind);
946 return true;
948 } else {
949 lldb::TypeCategoryImplSP category;
950 if (command.GetArgumentCount() > 0) {
951 const char *cat_name = command.GetArgumentAtIndex(0);
952 ConstString cat_nameCS(cat_name);
953 DataVisualization::Categories::GetCategory(cat_nameCS, category);
954 } else {
955 DataVisualization::Categories::GetCategory(ConstString(nullptr),
956 category);
958 category->Clear(m_formatter_kind);
961 FormatterSpecificDeletion();
963 result.SetStatus(eReturnStatusSuccessFinishResult);
967 // CommandObjectTypeFormatDelete
969 class CommandObjectTypeFormatDelete : public CommandObjectTypeFormatterDelete {
970 public:
971 CommandObjectTypeFormatDelete(CommandInterpreter &interpreter)
972 : CommandObjectTypeFormatterDelete(
973 interpreter, eFormatCategoryItemFormat) {}
975 ~CommandObjectTypeFormatDelete() override = default;
978 // CommandObjectTypeFormatClear
980 class CommandObjectTypeFormatClear : public CommandObjectTypeFormatterClear {
981 public:
982 CommandObjectTypeFormatClear(CommandInterpreter &interpreter)
983 : CommandObjectTypeFormatterClear(interpreter, eFormatCategoryItemFormat,
984 "type format clear",
985 "Delete all existing format styles.") {}
988 #define LLDB_OPTIONS_type_formatter_list
989 #include "CommandOptions.inc"
991 template <typename FormatterType>
992 class CommandObjectTypeFormatterList : public CommandObjectParsed {
993 typedef typename FormatterType::SharedPointer FormatterSharedPointer;
995 class CommandOptions : public Options {
996 public:
997 CommandOptions()
998 : Options(), m_category_regex("", ""),
999 m_category_language(lldb::eLanguageTypeUnknown,
1000 lldb::eLanguageTypeUnknown) {}
1002 ~CommandOptions() override = default;
1004 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1005 ExecutionContext *execution_context) override {
1006 Status error;
1007 const int short_option = m_getopt_table[option_idx].val;
1008 switch (short_option) {
1009 case 'w':
1010 m_category_regex.SetCurrentValue(option_arg);
1011 m_category_regex.SetOptionWasSet();
1012 break;
1013 case 'l':
1014 error = m_category_language.SetValueFromString(option_arg);
1015 if (error.Success())
1016 m_category_language.SetOptionWasSet();
1017 break;
1018 default:
1019 llvm_unreachable("Unimplemented option");
1022 return error;
1025 void OptionParsingStarting(ExecutionContext *execution_context) override {
1026 m_category_regex.Clear();
1027 m_category_language.Clear();
1030 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1031 return llvm::ArrayRef(g_type_formatter_list_options);
1034 // Instance variables to hold the values for command options.
1036 OptionValueString m_category_regex;
1037 OptionValueLanguage m_category_language;
1040 CommandOptions m_options;
1042 Options *GetOptions() override { return &m_options; }
1044 public:
1045 CommandObjectTypeFormatterList(CommandInterpreter &interpreter,
1046 const char *name, const char *help)
1047 : CommandObjectParsed(interpreter, name, help, nullptr), m_options() {
1048 CommandArgumentEntry type_arg;
1049 CommandArgumentData type_style_arg;
1051 type_style_arg.arg_type = eArgTypeName;
1052 type_style_arg.arg_repetition = eArgRepeatOptional;
1054 type_arg.push_back(type_style_arg);
1056 m_arguments.push_back(type_arg);
1059 ~CommandObjectTypeFormatterList() override = default;
1061 protected:
1062 virtual bool FormatterSpecificList(CommandReturnObject &result) {
1063 return false;
1066 static bool ShouldListItem(llvm::StringRef s, RegularExpression *regex) {
1067 // If we have a regex, it can match two kinds of results:
1068 // - An item created with that same regex string (exact string match), so
1069 // the user can list it using the same string it used at creation time.
1070 // - Items that match the regex.
1071 // No regex means list everything.
1072 return regex == nullptr || s == regex->GetText() || regex->Execute(s);
1075 void DoExecute(Args &command, CommandReturnObject &result) override {
1076 const size_t argc = command.GetArgumentCount();
1078 std::unique_ptr<RegularExpression> category_regex;
1079 std::unique_ptr<RegularExpression> formatter_regex;
1081 if (m_options.m_category_regex.OptionWasSet()) {
1082 category_regex = std::make_unique<RegularExpression>(
1083 m_options.m_category_regex.GetCurrentValueAsRef());
1084 if (!category_regex->IsValid()) {
1085 result.AppendErrorWithFormat(
1086 "syntax error in category regular expression '%s'",
1087 m_options.m_category_regex.GetCurrentValueAsRef().str().c_str());
1088 return;
1092 if (argc == 1) {
1093 const char *arg = command.GetArgumentAtIndex(0);
1094 formatter_regex = std::make_unique<RegularExpression>(arg);
1095 if (!formatter_regex->IsValid()) {
1096 result.AppendErrorWithFormat("syntax error in regular expression '%s'",
1097 arg);
1098 return;
1102 bool any_printed = false;
1104 auto category_closure =
1105 [&result, &formatter_regex,
1106 &any_printed](const lldb::TypeCategoryImplSP &category) -> void {
1107 result.GetOutputStream().Printf(
1108 "-----------------------\nCategory: %s%s\n-----------------------\n",
1109 category->GetName(), category->IsEnabled() ? "" : " (disabled)");
1111 TypeCategoryImpl::ForEachCallback<FormatterType> print_formatter =
1112 [&result, &formatter_regex,
1113 &any_printed](const TypeMatcher &type_matcher,
1114 const FormatterSharedPointer &format_sp) -> bool {
1115 if (ShouldListItem(type_matcher.GetMatchString().GetStringRef(),
1116 formatter_regex.get())) {
1117 any_printed = true;
1118 result.GetOutputStream().Printf(
1119 "%s: %s\n", type_matcher.GetMatchString().GetCString(),
1120 format_sp->GetDescription().c_str());
1122 return true;
1124 category->ForEach(print_formatter);
1127 if (m_options.m_category_language.OptionWasSet()) {
1128 lldb::TypeCategoryImplSP category_sp;
1129 DataVisualization::Categories::GetCategory(
1130 m_options.m_category_language.GetCurrentValue(), category_sp);
1131 if (category_sp)
1132 category_closure(category_sp);
1133 } else {
1134 DataVisualization::Categories::ForEach(
1135 [&category_regex, &category_closure](
1136 const lldb::TypeCategoryImplSP &category) -> bool {
1137 if (ShouldListItem(category->GetName(), category_regex.get())) {
1138 category_closure(category);
1140 return true;
1143 any_printed = FormatterSpecificList(result) | any_printed;
1146 if (any_printed)
1147 result.SetStatus(eReturnStatusSuccessFinishResult);
1148 else {
1149 result.GetOutputStream().PutCString("no matching results found.\n");
1150 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1155 // CommandObjectTypeFormatList
1157 class CommandObjectTypeFormatList
1158 : public CommandObjectTypeFormatterList<TypeFormatImpl> {
1159 public:
1160 CommandObjectTypeFormatList(CommandInterpreter &interpreter)
1161 : CommandObjectTypeFormatterList(interpreter, "type format list",
1162 "Show a list of current formats.") {}
1165 Status CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue(
1166 uint32_t option_idx, llvm::StringRef option_arg,
1167 ExecutionContext *execution_context) {
1168 Status error;
1169 const int short_option = m_getopt_table[option_idx].val;
1170 bool success;
1172 switch (short_option) {
1173 case 'C':
1174 m_flags.SetCascades(OptionArgParser::ToBoolean(option_arg, true, &success));
1175 if (!success)
1176 error.SetErrorStringWithFormat("invalid value for cascade: %s",
1177 option_arg.str().c_str());
1178 break;
1179 case 'e':
1180 m_flags.SetDontShowChildren(false);
1181 break;
1182 case 'h':
1183 m_flags.SetHideEmptyAggregates(true);
1184 break;
1185 case 'v':
1186 m_flags.SetDontShowValue(true);
1187 break;
1188 case 'c':
1189 m_flags.SetShowMembersOneLiner(true);
1190 break;
1191 case 's':
1192 m_format_string = std::string(option_arg);
1193 break;
1194 case 'p':
1195 m_flags.SetSkipPointers(true);
1196 break;
1197 case 'r':
1198 m_flags.SetSkipReferences(true);
1199 break;
1200 case 'x':
1201 if (m_match_type == eFormatterMatchCallback)
1202 error.SetErrorString(
1203 "can't use --regex and --recognizer-function at the same time");
1204 else
1205 m_match_type = eFormatterMatchRegex;
1206 break;
1207 case '\x01':
1208 if (m_match_type == eFormatterMatchRegex)
1209 error.SetErrorString(
1210 "can't use --regex and --recognizer-function at the same time");
1211 else
1212 m_match_type = eFormatterMatchCallback;
1213 break;
1214 case 'n':
1215 m_name.SetString(option_arg);
1216 break;
1217 case 'o':
1218 m_python_script = std::string(option_arg);
1219 m_is_add_script = true;
1220 break;
1221 case 'F':
1222 m_python_function = std::string(option_arg);
1223 m_is_add_script = true;
1224 break;
1225 case 'P':
1226 m_is_add_script = true;
1227 break;
1228 case 'w':
1229 m_category = std::string(option_arg);
1230 break;
1231 case 'O':
1232 m_flags.SetHideItemNames(true);
1233 break;
1234 default:
1235 llvm_unreachable("Unimplemented option");
1238 return error;
1241 void CommandObjectTypeSummaryAdd::CommandOptions::OptionParsingStarting(
1242 ExecutionContext *execution_context) {
1243 m_flags.Clear().SetCascades().SetDontShowChildren().SetDontShowValue(false);
1244 m_flags.SetShowMembersOneLiner(false)
1245 .SetSkipPointers(false)
1246 .SetSkipReferences(false)
1247 .SetHideItemNames(false);
1249 m_match_type = eFormatterMatchExact;
1250 m_name.Clear();
1251 m_python_script = "";
1252 m_python_function = "";
1253 m_format_string = "";
1254 m_is_add_script = false;
1255 m_category = "default";
1258 #if LLDB_ENABLE_PYTHON
1260 bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary(
1261 Args &command, CommandReturnObject &result) {
1262 const size_t argc = command.GetArgumentCount();
1264 if (argc < 1 && !m_options.m_name) {
1265 result.AppendErrorWithFormat("%s takes one or more args.\n",
1266 m_cmd_name.c_str());
1267 return false;
1270 TypeSummaryImplSP script_format;
1272 if (!m_options.m_python_function
1273 .empty()) // we have a Python function ready to use
1275 const char *funct_name = m_options.m_python_function.c_str();
1276 if (!funct_name || !funct_name[0]) {
1277 result.AppendError("function name empty.\n");
1278 return false;
1281 std::string code =
1282 (" " + m_options.m_python_function + "(valobj,internal_dict)");
1284 script_format = std::make_shared<ScriptSummaryFormat>(
1285 m_options.m_flags, funct_name, code.c_str());
1287 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1289 if (interpreter && !interpreter->CheckObjectExists(funct_name))
1290 result.AppendWarningWithFormat(
1291 "The provided function \"%s\" does not exist - "
1292 "please define it before attempting to use this summary.\n",
1293 funct_name);
1294 } else if (!m_options.m_python_script
1295 .empty()) // we have a quick 1-line script, just use it
1297 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1298 if (!interpreter) {
1299 result.AppendError("script interpreter missing - unable to generate "
1300 "function wrapper.\n");
1301 return false;
1303 StringList funct_sl;
1304 funct_sl << m_options.m_python_script.c_str();
1305 std::string funct_name_str;
1306 if (!interpreter->GenerateTypeScriptFunction(funct_sl, funct_name_str)) {
1307 result.AppendError("unable to generate function wrapper.\n");
1308 return false;
1310 if (funct_name_str.empty()) {
1311 result.AppendError(
1312 "script interpreter failed to generate a valid function name.\n");
1313 return false;
1316 std::string code = " " + m_options.m_python_script;
1318 script_format = std::make_shared<ScriptSummaryFormat>(
1319 m_options.m_flags, funct_name_str.c_str(), code.c_str());
1320 } else {
1321 // Use an IOHandler to grab Python code from the user
1322 auto options = std::make_unique<ScriptAddOptions>(
1323 m_options.m_flags, m_options.m_match_type, m_options.m_name,
1324 m_options.m_category);
1326 for (auto &entry : command.entries()) {
1327 if (entry.ref().empty()) {
1328 result.AppendError("empty typenames not allowed");
1329 return false;
1332 options->m_target_types << std::string(entry.ref());
1335 m_interpreter.GetPythonCommandsFromIOHandler(
1336 " ", // Prompt
1337 *this, // IOHandlerDelegate
1338 options.release()); // Baton for the "io_handler" that will be passed
1339 // back into our IOHandlerDelegate functions
1340 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1342 return result.Succeeded();
1345 // if I am here, script_format must point to something good, so I can add
1346 // that as a script summary to all interested parties
1348 Status error;
1350 for (auto &entry : command.entries()) {
1351 AddSummary(ConstString(entry.ref()), script_format, m_options.m_match_type,
1352 m_options.m_category, &error);
1353 if (error.Fail()) {
1354 result.AppendError(error.AsCString());
1355 return false;
1359 if (m_options.m_name) {
1360 AddNamedSummary(m_options.m_name, script_format, &error);
1361 if (error.Fail()) {
1362 result.AppendError(error.AsCString());
1363 result.AppendError("added to types, but not given a name");
1364 return false;
1368 return result.Succeeded();
1371 #endif
1373 bool CommandObjectTypeSummaryAdd::Execute_StringSummary(
1374 Args &command, CommandReturnObject &result) {
1375 const size_t argc = command.GetArgumentCount();
1377 if (argc < 1 && !m_options.m_name) {
1378 result.AppendErrorWithFormat("%s takes one or more args.\n",
1379 m_cmd_name.c_str());
1380 return false;
1383 if (!m_options.m_flags.GetShowMembersOneLiner() &&
1384 m_options.m_format_string.empty()) {
1385 result.AppendError("empty summary strings not allowed");
1386 return false;
1389 const char *format_cstr = (m_options.m_flags.GetShowMembersOneLiner()
1390 ? ""
1391 : m_options.m_format_string.c_str());
1393 // ${var%S} is an endless recursion, prevent it
1394 if (strcmp(format_cstr, "${var%S}") == 0) {
1395 result.AppendError("recursive summary not allowed");
1396 return false;
1399 std::unique_ptr<StringSummaryFormat> string_format(
1400 new StringSummaryFormat(m_options.m_flags, format_cstr));
1401 if (!string_format) {
1402 result.AppendError("summary creation failed");
1403 return false;
1405 if (string_format->m_error.Fail()) {
1406 result.AppendErrorWithFormat("syntax error: %s",
1407 string_format->m_error.AsCString("<unknown>"));
1408 return false;
1410 lldb::TypeSummaryImplSP entry(string_format.release());
1412 // now I have a valid format, let's add it to every type
1413 Status error;
1414 for (auto &arg_entry : command.entries()) {
1415 if (arg_entry.ref().empty()) {
1416 result.AppendError("empty typenames not allowed");
1417 return false;
1419 ConstString typeCS(arg_entry.ref());
1421 AddSummary(typeCS, entry, m_options.m_match_type, m_options.m_category,
1422 &error);
1424 if (error.Fail()) {
1425 result.AppendError(error.AsCString());
1426 return false;
1430 if (m_options.m_name) {
1431 AddNamedSummary(m_options.m_name, entry, &error);
1432 if (error.Fail()) {
1433 result.AppendError(error.AsCString());
1434 result.AppendError("added to types, but not given a name");
1435 return false;
1439 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1440 return result.Succeeded();
1443 CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd(
1444 CommandInterpreter &interpreter)
1445 : CommandObjectParsed(interpreter, "type summary add",
1446 "Add a new summary style for a type.", nullptr),
1447 IOHandlerDelegateMultiline("DONE"), m_options(interpreter) {
1448 CommandArgumentEntry type_arg;
1449 CommandArgumentData type_style_arg;
1451 type_style_arg.arg_type = eArgTypeName;
1452 type_style_arg.arg_repetition = eArgRepeatPlus;
1454 type_arg.push_back(type_style_arg);
1456 m_arguments.push_back(type_arg);
1458 SetHelpLong(
1460 The following examples of 'type summary add' refer to this code snippet for context:
1462 struct JustADemo
1464 int* ptr;
1465 float value;
1466 JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {}
1468 JustADemo demo_instance(42, 3.14);
1470 typedef JustADemo NewDemo;
1471 NewDemo new_demo_instance(42, 3.14);
1473 (lldb) type summary add --summary-string "the answer is ${*var.ptr}" JustADemo
1475 Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42"
1477 (lldb) type summary add --summary-string "the answer is ${*var.ptr}, and the question is ${var.value}" JustADemo
1479 Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42 and the question is 3.14"
1482 "Alternatively, you could define formatting for all pointers to integers and \
1483 rely on that when formatting JustADemo to obtain the same result:"
1486 (lldb) type summary add --summary-string "${var%V} -> ${*var}" "int *"
1487 (lldb) type summary add --summary-string "the answer is ${var.ptr}, and the question is ${var.value}" JustADemo
1490 "Type summaries are automatically applied to derived typedefs, so the examples \
1491 above apply to both JustADemo and NewDemo. The cascade option can be used to \
1492 suppress this behavior:"
1495 (lldb) type summary add --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo -C no
1497 The summary will now be used for values of JustADemo but not NewDemo.
1500 "By default summaries are shown for pointers and references to values of the \
1501 specified type. To suppress formatting for pointers use the -p option, or apply \
1502 the corresponding -r option to suppress formatting for references:"
1505 (lldb) type summary add -p -r --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo
1508 "One-line summaries including all fields in a type can be inferred without supplying an \
1509 explicit summary string by passing the -c option:"
1512 (lldb) type summary add -c JustADemo
1513 (lldb) frame variable demo_instance
1514 (ptr=<address>, value=3.14)
1517 "Type summaries normally suppress the nested display of individual fields. To \
1518 supply a summary to supplement the default structure add the -e option:"
1521 (lldb) type summary add -e --summary-string "*ptr = ${*var.ptr}" JustADemo
1524 "Now when displaying JustADemo values the int* is displayed, followed by the \
1525 standard LLDB sequence of children, one per line:"
1528 *ptr = 42 {
1529 ptr = <address>
1530 value = 3.14
1534 "You can also add summaries written in Python. These scripts use lldb public API to \
1535 gather information from your variables and produce a meaningful summary. To start a \
1536 multi-line script use the -P option. The function declaration will be displayed along with \
1537 a comment describing the two arguments. End your script with the word 'DONE' on a line by \
1538 itself:"
1541 (lldb) type summary add JustADemo -P
1542 def function (valobj,internal_dict):
1543 """valobj: an SBValue which you want to provide a summary for
1544 internal_dict: an LLDB support object not to be used"""
1545 value = valobj.GetChildMemberWithName('value');
1546 return 'My value is ' + value.GetValue();
1547 DONE
1549 Alternatively, the -o option can be used when providing a simple one-line Python script:
1551 (lldb) type summary add JustADemo -o "value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();")");
1554 void CommandObjectTypeSummaryAdd::DoExecute(Args &command,
1555 CommandReturnObject &result) {
1556 WarnOnPotentialUnquotedUnsignedType(command, result);
1558 if (m_options.m_is_add_script) {
1559 #if LLDB_ENABLE_PYTHON
1560 Execute_ScriptSummary(command, result);
1561 #else
1562 result.AppendError("python is disabled");
1563 #endif
1564 return;
1567 Execute_StringSummary(command, result);
1570 static bool FixArrayTypeNameWithRegex(ConstString &type_name) {
1571 llvm::StringRef type_name_ref(type_name.GetStringRef());
1573 if (type_name_ref.ends_with("[]")) {
1574 std::string type_name_str(type_name.GetCString());
1575 type_name_str.resize(type_name_str.length() - 2);
1576 if (type_name_str.back() != ' ')
1577 type_name_str.append(" ?\\[[0-9]+\\]");
1578 else
1579 type_name_str.append("\\[[0-9]+\\]");
1580 type_name.SetCString(type_name_str.c_str());
1581 return true;
1583 return false;
1586 bool CommandObjectTypeSummaryAdd::AddNamedSummary(ConstString summary_name,
1587 TypeSummaryImplSP entry,
1588 Status *error) {
1589 // system named summaries do not exist (yet?)
1590 DataVisualization::NamedSummaryFormats::Add(summary_name, entry);
1591 return true;
1594 bool CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name,
1595 TypeSummaryImplSP entry,
1596 FormatterMatchType match_type,
1597 std::string category_name,
1598 Status *error) {
1599 lldb::TypeCategoryImplSP category;
1600 DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()),
1601 category);
1603 if (match_type == eFormatterMatchExact) {
1604 if (FixArrayTypeNameWithRegex(type_name))
1605 match_type = eFormatterMatchRegex;
1608 if (match_type == eFormatterMatchRegex) {
1609 match_type = eFormatterMatchRegex;
1610 RegularExpression typeRX(type_name.GetStringRef());
1611 if (!typeRX.IsValid()) {
1612 if (error)
1613 error->SetErrorString(
1614 "regex format error (maybe this is not really a regex?)");
1615 return false;
1619 if (match_type == eFormatterMatchCallback) {
1620 const char *function_name = type_name.AsCString();
1621 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1622 if (interpreter && !interpreter->CheckObjectExists(function_name)) {
1623 error->SetErrorStringWithFormat(
1624 "The provided recognizer function \"%s\" does not exist - "
1625 "please define it before attempting to use this summary.\n",
1626 function_name);
1627 return false;
1630 category->AddTypeSummary(type_name.GetStringRef(), match_type, entry);
1631 return true;
1634 // CommandObjectTypeSummaryDelete
1636 class CommandObjectTypeSummaryDelete : public CommandObjectTypeFormatterDelete {
1637 public:
1638 CommandObjectTypeSummaryDelete(CommandInterpreter &interpreter)
1639 : CommandObjectTypeFormatterDelete(
1640 interpreter, eFormatCategoryItemSummary) {}
1642 ~CommandObjectTypeSummaryDelete() override = default;
1644 protected:
1645 bool FormatterSpecificDeletion(ConstString typeCS) override {
1646 if (m_options.m_language != lldb::eLanguageTypeUnknown)
1647 return false;
1648 return DataVisualization::NamedSummaryFormats::Delete(typeCS);
1652 class CommandObjectTypeSummaryClear : public CommandObjectTypeFormatterClear {
1653 public:
1654 CommandObjectTypeSummaryClear(CommandInterpreter &interpreter)
1655 : CommandObjectTypeFormatterClear(interpreter, eFormatCategoryItemSummary,
1656 "type summary clear",
1657 "Delete all existing summaries.") {}
1659 protected:
1660 void FormatterSpecificDeletion() override {
1661 DataVisualization::NamedSummaryFormats::Clear();
1665 // CommandObjectTypeSummaryList
1667 class CommandObjectTypeSummaryList
1668 : public CommandObjectTypeFormatterList<TypeSummaryImpl> {
1669 public:
1670 CommandObjectTypeSummaryList(CommandInterpreter &interpreter)
1671 : CommandObjectTypeFormatterList(interpreter, "type summary list",
1672 "Show a list of current summaries.") {}
1674 protected:
1675 bool FormatterSpecificList(CommandReturnObject &result) override {
1676 if (DataVisualization::NamedSummaryFormats::GetCount() > 0) {
1677 result.GetOutputStream().Printf("Named summaries:\n");
1678 DataVisualization::NamedSummaryFormats::ForEach(
1679 [&result](const TypeMatcher &type_matcher,
1680 const TypeSummaryImplSP &summary_sp) -> bool {
1681 result.GetOutputStream().Printf(
1682 "%s: %s\n", type_matcher.GetMatchString().GetCString(),
1683 summary_sp->GetDescription().c_str());
1684 return true;
1686 return true;
1688 return false;
1692 // CommandObjectTypeCategoryDefine
1693 #define LLDB_OPTIONS_type_category_define
1694 #include "CommandOptions.inc"
1696 class CommandObjectTypeCategoryDefine : public CommandObjectParsed {
1697 class CommandOptions : public Options {
1698 public:
1699 CommandOptions()
1700 : m_define_enabled(false, false),
1701 m_cate_language(eLanguageTypeUnknown, eLanguageTypeUnknown) {}
1703 ~CommandOptions() override = default;
1705 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1706 ExecutionContext *execution_context) override {
1707 Status error;
1708 const int short_option = m_getopt_table[option_idx].val;
1710 switch (short_option) {
1711 case 'e':
1712 m_define_enabled.SetValueFromString(llvm::StringRef("true"));
1713 break;
1714 case 'l':
1715 error = m_cate_language.SetValueFromString(option_arg);
1716 break;
1717 default:
1718 llvm_unreachable("Unimplemented option");
1721 return error;
1724 void OptionParsingStarting(ExecutionContext *execution_context) override {
1725 m_define_enabled.Clear();
1726 m_cate_language.Clear();
1729 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1730 return llvm::ArrayRef(g_type_category_define_options);
1733 // Instance variables to hold the values for command options.
1735 OptionValueBoolean m_define_enabled;
1736 OptionValueLanguage m_cate_language;
1739 CommandOptions m_options;
1741 Options *GetOptions() override { return &m_options; }
1743 public:
1744 CommandObjectTypeCategoryDefine(CommandInterpreter &interpreter)
1745 : CommandObjectParsed(interpreter, "type category define",
1746 "Define a new category as a source of formatters.",
1747 nullptr) {
1748 CommandArgumentEntry type_arg;
1749 CommandArgumentData type_style_arg;
1751 type_style_arg.arg_type = eArgTypeName;
1752 type_style_arg.arg_repetition = eArgRepeatPlus;
1754 type_arg.push_back(type_style_arg);
1756 m_arguments.push_back(type_arg);
1759 ~CommandObjectTypeCategoryDefine() override = default;
1761 void
1762 HandleArgumentCompletion(CompletionRequest &request,
1763 OptionElementVector &opt_element_vector) override {
1764 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1765 GetCommandInterpreter(), lldb::eTypeCategoryNameCompletion, request,
1766 nullptr);
1769 protected:
1770 void DoExecute(Args &command, CommandReturnObject &result) override {
1771 const size_t argc = command.GetArgumentCount();
1773 if (argc < 1) {
1774 result.AppendErrorWithFormat("%s takes 1 or more args.\n",
1775 m_cmd_name.c_str());
1776 return;
1779 for (auto &entry : command.entries()) {
1780 TypeCategoryImplSP category_sp;
1781 if (DataVisualization::Categories::GetCategory(ConstString(entry.ref()),
1782 category_sp) &&
1783 category_sp) {
1784 category_sp->AddLanguage(m_options.m_cate_language.GetCurrentValue());
1785 if (m_options.m_define_enabled.GetCurrentValue())
1786 DataVisualization::Categories::Enable(category_sp,
1787 TypeCategoryMap::Default);
1791 result.SetStatus(eReturnStatusSuccessFinishResult);
1795 // CommandObjectTypeCategoryEnable
1796 #define LLDB_OPTIONS_type_category_enable
1797 #include "CommandOptions.inc"
1799 class CommandObjectTypeCategoryEnable : public CommandObjectParsed {
1800 class CommandOptions : public Options {
1801 public:
1802 CommandOptions() = default;
1804 ~CommandOptions() override = default;
1806 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1807 ExecutionContext *execution_context) override {
1808 Status error;
1809 const int short_option = m_getopt_table[option_idx].val;
1811 switch (short_option) {
1812 case 'l':
1813 if (!option_arg.empty()) {
1814 m_language = Language::GetLanguageTypeFromString(option_arg);
1815 if (m_language == lldb::eLanguageTypeUnknown)
1816 error.SetErrorStringWithFormat("unrecognized language '%s'",
1817 option_arg.str().c_str());
1819 break;
1820 default:
1821 llvm_unreachable("Unimplemented option");
1824 return error;
1827 void OptionParsingStarting(ExecutionContext *execution_context) override {
1828 m_language = lldb::eLanguageTypeUnknown;
1831 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1832 return llvm::ArrayRef(g_type_category_enable_options);
1835 // Instance variables to hold the values for command options.
1837 lldb::LanguageType m_language;
1840 CommandOptions m_options;
1842 Options *GetOptions() override { return &m_options; }
1844 public:
1845 CommandObjectTypeCategoryEnable(CommandInterpreter &interpreter)
1846 : CommandObjectParsed(interpreter, "type category enable",
1847 "Enable a category as a source of formatters.",
1848 nullptr) {
1849 CommandArgumentEntry type_arg;
1850 CommandArgumentData type_style_arg;
1852 type_style_arg.arg_type = eArgTypeName;
1853 type_style_arg.arg_repetition = eArgRepeatPlus;
1855 type_arg.push_back(type_style_arg);
1857 m_arguments.push_back(type_arg);
1860 ~CommandObjectTypeCategoryEnable() override = default;
1862 void
1863 HandleArgumentCompletion(CompletionRequest &request,
1864 OptionElementVector &opt_element_vector) override {
1865 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1866 GetCommandInterpreter(), lldb::eTypeCategoryNameCompletion, request,
1867 nullptr);
1870 protected:
1871 void DoExecute(Args &command, CommandReturnObject &result) override {
1872 const size_t argc = command.GetArgumentCount();
1874 if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) {
1875 result.AppendErrorWithFormat("%s takes arguments and/or a language",
1876 m_cmd_name.c_str());
1877 return;
1880 if (argc == 1 && strcmp(command.GetArgumentAtIndex(0), "*") == 0) {
1881 DataVisualization::Categories::EnableStar();
1882 } else if (argc > 0) {
1883 for (int i = argc - 1; i >= 0; i--) {
1884 const char *typeA = command.GetArgumentAtIndex(i);
1885 ConstString typeCS(typeA);
1887 if (!typeCS) {
1888 result.AppendError("empty category name not allowed");
1889 return;
1891 DataVisualization::Categories::Enable(typeCS);
1892 lldb::TypeCategoryImplSP cate;
1893 if (DataVisualization::Categories::GetCategory(typeCS, cate) && cate) {
1894 if (cate->GetCount() == 0) {
1895 result.AppendWarning("empty category enabled (typo?)");
1901 if (m_options.m_language != lldb::eLanguageTypeUnknown)
1902 DataVisualization::Categories::Enable(m_options.m_language);
1904 result.SetStatus(eReturnStatusSuccessFinishResult);
1908 // CommandObjectTypeCategoryDelete
1910 class CommandObjectTypeCategoryDelete : public CommandObjectParsed {
1911 public:
1912 CommandObjectTypeCategoryDelete(CommandInterpreter &interpreter)
1913 : CommandObjectParsed(interpreter, "type category delete",
1914 "Delete a category and all associated formatters.",
1915 nullptr) {
1916 CommandArgumentEntry type_arg;
1917 CommandArgumentData type_style_arg;
1919 type_style_arg.arg_type = eArgTypeName;
1920 type_style_arg.arg_repetition = eArgRepeatPlus;
1922 type_arg.push_back(type_style_arg);
1924 m_arguments.push_back(type_arg);
1927 ~CommandObjectTypeCategoryDelete() override = default;
1929 void
1930 HandleArgumentCompletion(CompletionRequest &request,
1931 OptionElementVector &opt_element_vector) override {
1932 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1933 GetCommandInterpreter(), lldb::eTypeCategoryNameCompletion, request,
1934 nullptr);
1937 protected:
1938 void DoExecute(Args &command, CommandReturnObject &result) override {
1939 const size_t argc = command.GetArgumentCount();
1941 if (argc < 1) {
1942 result.AppendErrorWithFormat("%s takes 1 or more arg.\n",
1943 m_cmd_name.c_str());
1944 return;
1947 bool success = true;
1949 // the order is not relevant here
1950 for (int i = argc - 1; i >= 0; i--) {
1951 const char *typeA = command.GetArgumentAtIndex(i);
1952 ConstString typeCS(typeA);
1954 if (!typeCS) {
1955 result.AppendError("empty category name not allowed");
1956 return;
1958 if (!DataVisualization::Categories::Delete(typeCS))
1959 success = false; // keep deleting even if we hit an error
1961 if (success) {
1962 result.SetStatus(eReturnStatusSuccessFinishResult);
1963 } else {
1964 result.AppendError("cannot delete one or more categories\n");
1969 // CommandObjectTypeCategoryDisable
1970 #define LLDB_OPTIONS_type_category_disable
1971 #include "CommandOptions.inc"
1973 class CommandObjectTypeCategoryDisable : public CommandObjectParsed {
1974 class CommandOptions : public Options {
1975 public:
1976 CommandOptions() = default;
1978 ~CommandOptions() override = default;
1980 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1981 ExecutionContext *execution_context) override {
1982 Status error;
1983 const int short_option = m_getopt_table[option_idx].val;
1985 switch (short_option) {
1986 case 'l':
1987 if (!option_arg.empty()) {
1988 m_language = Language::GetLanguageTypeFromString(option_arg);
1989 if (m_language == lldb::eLanguageTypeUnknown)
1990 error.SetErrorStringWithFormat("unrecognized language '%s'",
1991 option_arg.str().c_str());
1993 break;
1994 default:
1995 llvm_unreachable("Unimplemented option");
1998 return error;
2001 void OptionParsingStarting(ExecutionContext *execution_context) override {
2002 m_language = lldb::eLanguageTypeUnknown;
2005 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2006 return llvm::ArrayRef(g_type_category_disable_options);
2009 // Instance variables to hold the values for command options.
2011 lldb::LanguageType m_language;
2014 CommandOptions m_options;
2016 Options *GetOptions() override { return &m_options; }
2018 public:
2019 CommandObjectTypeCategoryDisable(CommandInterpreter &interpreter)
2020 : CommandObjectParsed(interpreter, "type category disable",
2021 "Disable a category as a source of formatters.",
2022 nullptr) {
2023 CommandArgumentEntry type_arg;
2024 CommandArgumentData type_style_arg;
2026 type_style_arg.arg_type = eArgTypeName;
2027 type_style_arg.arg_repetition = eArgRepeatPlus;
2029 type_arg.push_back(type_style_arg);
2031 m_arguments.push_back(type_arg);
2034 ~CommandObjectTypeCategoryDisable() override = default;
2036 void
2037 HandleArgumentCompletion(CompletionRequest &request,
2038 OptionElementVector &opt_element_vector) override {
2039 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
2040 GetCommandInterpreter(), lldb::eTypeCategoryNameCompletion, request,
2041 nullptr);
2044 protected:
2045 void DoExecute(Args &command, CommandReturnObject &result) override {
2046 const size_t argc = command.GetArgumentCount();
2048 if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) {
2049 result.AppendErrorWithFormat("%s takes arguments and/or a language",
2050 m_cmd_name.c_str());
2051 return;
2054 if (argc == 1 && strcmp(command.GetArgumentAtIndex(0), "*") == 0) {
2055 DataVisualization::Categories::DisableStar();
2056 } else if (argc > 0) {
2057 // the order is not relevant here
2058 for (int i = argc - 1; i >= 0; i--) {
2059 const char *typeA = command.GetArgumentAtIndex(i);
2060 ConstString typeCS(typeA);
2062 if (!typeCS) {
2063 result.AppendError("empty category name not allowed");
2064 return;
2066 DataVisualization::Categories::Disable(typeCS);
2070 if (m_options.m_language != lldb::eLanguageTypeUnknown)
2071 DataVisualization::Categories::Disable(m_options.m_language);
2073 result.SetStatus(eReturnStatusSuccessFinishResult);
2077 // CommandObjectTypeCategoryList
2079 class CommandObjectTypeCategoryList : public CommandObjectParsed {
2080 public:
2081 CommandObjectTypeCategoryList(CommandInterpreter &interpreter)
2082 : CommandObjectParsed(interpreter, "type category list",
2083 "Provide a list of all existing categories.",
2084 nullptr) {
2085 CommandArgumentEntry type_arg;
2086 CommandArgumentData type_style_arg;
2088 type_style_arg.arg_type = eArgTypeName;
2089 type_style_arg.arg_repetition = eArgRepeatOptional;
2091 type_arg.push_back(type_style_arg);
2093 m_arguments.push_back(type_arg);
2096 ~CommandObjectTypeCategoryList() override = default;
2098 void
2099 HandleArgumentCompletion(CompletionRequest &request,
2100 OptionElementVector &opt_element_vector) override {
2101 if (request.GetCursorIndex())
2102 return;
2103 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
2104 GetCommandInterpreter(), lldb::eTypeCategoryNameCompletion, request,
2105 nullptr);
2108 protected:
2109 void DoExecute(Args &command, CommandReturnObject &result) override {
2110 const size_t argc = command.GetArgumentCount();
2112 std::unique_ptr<RegularExpression> regex;
2114 if (argc == 1) {
2115 const char *arg = command.GetArgumentAtIndex(0);
2116 regex = std::make_unique<RegularExpression>(arg);
2117 if (!regex->IsValid()) {
2118 result.AppendErrorWithFormat(
2119 "syntax error in category regular expression '%s'", arg);
2120 return;
2122 } else if (argc != 0) {
2123 result.AppendErrorWithFormat("%s takes 0 or one arg.\n",
2124 m_cmd_name.c_str());
2125 return;
2128 DataVisualization::Categories::ForEach(
2129 [&regex, &result](const lldb::TypeCategoryImplSP &category_sp) -> bool {
2130 if (regex) {
2131 bool escape = true;
2132 if (regex->GetText() == category_sp->GetName()) {
2133 escape = false;
2134 } else if (regex->Execute(category_sp->GetName())) {
2135 escape = false;
2138 if (escape)
2139 return true;
2142 result.GetOutputStream().Printf(
2143 "Category: %s\n", category_sp->GetDescription().c_str());
2145 return true;
2148 result.SetStatus(eReturnStatusSuccessFinishResult);
2152 // CommandObjectTypeFilterList
2154 class CommandObjectTypeFilterList
2155 : public CommandObjectTypeFormatterList<TypeFilterImpl> {
2156 public:
2157 CommandObjectTypeFilterList(CommandInterpreter &interpreter)
2158 : CommandObjectTypeFormatterList(interpreter, "type filter list",
2159 "Show a list of current filters.") {}
2162 // CommandObjectTypeSynthList
2164 class CommandObjectTypeSynthList
2165 : public CommandObjectTypeFormatterList<SyntheticChildren> {
2166 public:
2167 CommandObjectTypeSynthList(CommandInterpreter &interpreter)
2168 : CommandObjectTypeFormatterList(
2169 interpreter, "type synthetic list",
2170 "Show a list of current synthetic providers.") {}
2173 // CommandObjectTypeFilterDelete
2175 class CommandObjectTypeFilterDelete : public CommandObjectTypeFormatterDelete {
2176 public:
2177 CommandObjectTypeFilterDelete(CommandInterpreter &interpreter)
2178 : CommandObjectTypeFormatterDelete(
2179 interpreter, eFormatCategoryItemFilter) {}
2181 ~CommandObjectTypeFilterDelete() override = default;
2184 // CommandObjectTypeSynthDelete
2186 class CommandObjectTypeSynthDelete : public CommandObjectTypeFormatterDelete {
2187 public:
2188 CommandObjectTypeSynthDelete(CommandInterpreter &interpreter)
2189 : CommandObjectTypeFormatterDelete(
2190 interpreter, eFormatCategoryItemSynth) {}
2192 ~CommandObjectTypeSynthDelete() override = default;
2196 // CommandObjectTypeFilterClear
2198 class CommandObjectTypeFilterClear : public CommandObjectTypeFormatterClear {
2199 public:
2200 CommandObjectTypeFilterClear(CommandInterpreter &interpreter)
2201 : CommandObjectTypeFormatterClear(interpreter, eFormatCategoryItemFilter,
2202 "type filter clear",
2203 "Delete all existing filter.") {}
2206 // CommandObjectTypeSynthClear
2208 class CommandObjectTypeSynthClear : public CommandObjectTypeFormatterClear {
2209 public:
2210 CommandObjectTypeSynthClear(CommandInterpreter &interpreter)
2211 : CommandObjectTypeFormatterClear(
2212 interpreter, eFormatCategoryItemSynth, "type synthetic clear",
2213 "Delete all existing synthetic providers.") {}
2216 bool CommandObjectTypeSynthAdd::Execute_HandwritePython(
2217 Args &command, CommandReturnObject &result) {
2218 auto options = std::make_unique<SynthAddOptions>(
2219 m_options.m_skip_pointers, m_options.m_skip_references,
2220 m_options.m_cascade, m_options.m_match_type, m_options.m_category);
2222 for (auto &entry : command.entries()) {
2223 if (entry.ref().empty()) {
2224 result.AppendError("empty typenames not allowed");
2225 return false;
2228 options->m_target_types << std::string(entry.ref());
2231 m_interpreter.GetPythonCommandsFromIOHandler(
2232 " ", // Prompt
2233 *this, // IOHandlerDelegate
2234 options.release()); // Baton for the "io_handler" that will be passed back
2235 // into our IOHandlerDelegate functions
2236 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2237 return result.Succeeded();
2240 bool CommandObjectTypeSynthAdd::Execute_PythonClass(
2241 Args &command, CommandReturnObject &result) {
2242 const size_t argc = command.GetArgumentCount();
2244 if (argc < 1) {
2245 result.AppendErrorWithFormat("%s takes one or more args.\n",
2246 m_cmd_name.c_str());
2247 return false;
2250 if (m_options.m_class_name.empty() && !m_options.m_input_python) {
2251 result.AppendErrorWithFormat("%s needs either a Python class name or -P to "
2252 "directly input Python code.\n",
2253 m_cmd_name.c_str());
2254 return false;
2257 SyntheticChildrenSP entry;
2259 ScriptedSyntheticChildren *impl = new ScriptedSyntheticChildren(
2260 SyntheticChildren::Flags()
2261 .SetCascades(m_options.m_cascade)
2262 .SetSkipPointers(m_options.m_skip_pointers)
2263 .SetSkipReferences(m_options.m_skip_references),
2264 m_options.m_class_name.c_str());
2266 entry.reset(impl);
2268 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
2270 if (interpreter &&
2271 !interpreter->CheckObjectExists(impl->GetPythonClassName()))
2272 result.AppendWarning("The provided class does not exist - please define it "
2273 "before attempting to use this synthetic provider");
2275 // now I have a valid provider, let's add it to every type
2277 lldb::TypeCategoryImplSP category;
2278 DataVisualization::Categories::GetCategory(
2279 ConstString(m_options.m_category.c_str()), category);
2281 Status error;
2283 for (auto &arg_entry : command.entries()) {
2284 if (arg_entry.ref().empty()) {
2285 result.AppendError("empty typenames not allowed");
2286 return false;
2289 ConstString typeCS(arg_entry.ref());
2290 if (!AddSynth(typeCS, entry, m_options.m_match_type, m_options.m_category,
2291 &error)) {
2292 result.AppendError(error.AsCString());
2293 return false;
2297 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2298 return result.Succeeded();
2301 CommandObjectTypeSynthAdd::CommandObjectTypeSynthAdd(
2302 CommandInterpreter &interpreter)
2303 : CommandObjectParsed(interpreter, "type synthetic add",
2304 "Add a new synthetic provider for a type.", nullptr),
2305 IOHandlerDelegateMultiline("DONE"), m_options() {
2306 CommandArgumentEntry type_arg;
2307 CommandArgumentData type_style_arg;
2309 type_style_arg.arg_type = eArgTypeName;
2310 type_style_arg.arg_repetition = eArgRepeatPlus;
2312 type_arg.push_back(type_style_arg);
2314 m_arguments.push_back(type_arg);
2317 bool CommandObjectTypeSynthAdd::AddSynth(ConstString type_name,
2318 SyntheticChildrenSP entry,
2319 FormatterMatchType match_type,
2320 std::string category_name,
2321 Status *error) {
2322 lldb::TypeCategoryImplSP category;
2323 DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()),
2324 category);
2326 if (match_type == eFormatterMatchExact) {
2327 if (FixArrayTypeNameWithRegex(type_name))
2328 match_type = eFormatterMatchRegex;
2331 // Only check for conflicting filters in the same category if `type_name` is
2332 // an actual type name. Matching a regex string against registered regexes
2333 // doesn't work.
2334 if (match_type == eFormatterMatchExact) {
2335 // It's not generally possible to get a type object here. For example, this
2336 // command can be run before loading any binaries. Do just a best-effort
2337 // name-based lookup here to try to prevent conflicts.
2338 FormattersMatchCandidate candidate_type(type_name, nullptr, TypeImpl(),
2339 FormattersMatchCandidate::Flags());
2340 if (category->AnyMatches(candidate_type, eFormatCategoryItemFilter,
2341 false)) {
2342 if (error)
2343 error->SetErrorStringWithFormat("cannot add synthetic for type %s when "
2344 "filter is defined in same category!",
2345 type_name.AsCString());
2346 return false;
2350 if (match_type == eFormatterMatchRegex) {
2351 RegularExpression typeRX(type_name.GetStringRef());
2352 if (!typeRX.IsValid()) {
2353 if (error)
2354 error->SetErrorString(
2355 "regex format error (maybe this is not really a regex?)");
2356 return false;
2360 if (match_type == eFormatterMatchCallback) {
2361 const char *function_name = type_name.AsCString();
2362 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
2363 if (interpreter && !interpreter->CheckObjectExists(function_name)) {
2364 error->SetErrorStringWithFormat(
2365 "The provided recognizer function \"%s\" does not exist - "
2366 "please define it before attempting to use this summary.\n",
2367 function_name);
2368 return false;
2372 category->AddTypeSynthetic(type_name.GetStringRef(), match_type, entry);
2373 return true;
2376 #define LLDB_OPTIONS_type_filter_add
2377 #include "CommandOptions.inc"
2379 class CommandObjectTypeFilterAdd : public CommandObjectParsed {
2380 private:
2381 class CommandOptions : public Options {
2382 typedef std::vector<std::string> option_vector;
2384 public:
2385 CommandOptions() = default;
2387 ~CommandOptions() override = default;
2389 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2390 ExecutionContext *execution_context) override {
2391 Status error;
2392 const int short_option = m_getopt_table[option_idx].val;
2393 bool success;
2395 switch (short_option) {
2396 case 'C':
2397 m_cascade = OptionArgParser::ToBoolean(option_arg, true, &success);
2398 if (!success)
2399 error.SetErrorStringWithFormat("invalid value for cascade: %s",
2400 option_arg.str().c_str());
2401 break;
2402 case 'c':
2403 m_expr_paths.push_back(std::string(option_arg));
2404 has_child_list = true;
2405 break;
2406 case 'p':
2407 m_skip_pointers = true;
2408 break;
2409 case 'r':
2410 m_skip_references = true;
2411 break;
2412 case 'w':
2413 m_category = std::string(option_arg);
2414 break;
2415 case 'x':
2416 m_regex = true;
2417 break;
2418 default:
2419 llvm_unreachable("Unimplemented option");
2422 return error;
2425 void OptionParsingStarting(ExecutionContext *execution_context) override {
2426 m_cascade = true;
2427 m_skip_pointers = false;
2428 m_skip_references = false;
2429 m_category = "default";
2430 m_expr_paths.clear();
2431 has_child_list = false;
2432 m_regex = false;
2435 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2436 return llvm::ArrayRef(g_type_filter_add_options);
2439 // Instance variables to hold the values for command options.
2441 bool m_cascade;
2442 bool m_skip_references;
2443 bool m_skip_pointers;
2444 bool m_input_python;
2445 option_vector m_expr_paths;
2446 std::string m_category;
2447 bool has_child_list;
2448 bool m_regex;
2450 typedef option_vector::iterator ExpressionPathsIterator;
2453 CommandOptions m_options;
2455 Options *GetOptions() override { return &m_options; }
2457 enum FilterFormatType { eRegularFilter, eRegexFilter };
2459 bool AddFilter(ConstString type_name, TypeFilterImplSP entry,
2460 FilterFormatType type, std::string category_name,
2461 Status *error) {
2462 lldb::TypeCategoryImplSP category;
2463 DataVisualization::Categories::GetCategory(
2464 ConstString(category_name.c_str()), category);
2466 if (type == eRegularFilter) {
2467 if (FixArrayTypeNameWithRegex(type_name))
2468 type = eRegexFilter;
2471 // Only check for conflicting synthetic child providers in the same category
2472 // if `type_name` is an actual type name. Matching a regex string against
2473 // registered regexes doesn't work.
2474 if (type == eRegularFilter) {
2475 // It's not generally possible to get a type object here. For example,
2476 // this command can be run before loading any binaries. Do just a
2477 // best-effort name-based lookup here to try to prevent conflicts.
2478 FormattersMatchCandidate candidate_type(
2479 type_name, nullptr, TypeImpl(), FormattersMatchCandidate::Flags());
2480 lldb::SyntheticChildrenSP entry;
2481 if (category->AnyMatches(candidate_type, eFormatCategoryItemSynth,
2482 false)) {
2483 if (error)
2484 error->SetErrorStringWithFormat("cannot add filter for type %s when "
2485 "synthetic is defined in same "
2486 "category!",
2487 type_name.AsCString());
2488 return false;
2492 FormatterMatchType match_type = eFormatterMatchExact;
2493 if (type == eRegexFilter) {
2494 match_type = eFormatterMatchRegex;
2495 RegularExpression typeRX(type_name.GetStringRef());
2496 if (!typeRX.IsValid()) {
2497 if (error)
2498 error->SetErrorString(
2499 "regex format error (maybe this is not really a regex?)");
2500 return false;
2503 category->AddTypeFilter(type_name.GetStringRef(), match_type, entry);
2504 return true;
2507 public:
2508 CommandObjectTypeFilterAdd(CommandInterpreter &interpreter)
2509 : CommandObjectParsed(interpreter, "type filter add",
2510 "Add a new filter for a type.", nullptr) {
2511 CommandArgumentEntry type_arg;
2512 CommandArgumentData type_style_arg;
2514 type_style_arg.arg_type = eArgTypeName;
2515 type_style_arg.arg_repetition = eArgRepeatPlus;
2517 type_arg.push_back(type_style_arg);
2519 m_arguments.push_back(type_arg);
2521 SetHelpLong(
2523 The following examples of 'type filter add' refer to this code snippet for context:
2525 class Foo {
2526 int a;
2527 int b;
2528 int c;
2529 int d;
2530 int e;
2531 int f;
2532 int g;
2533 int h;
2534 int i;
2536 Foo my_foo;
2538 Adding a simple filter:
2540 (lldb) type filter add --child a --child g Foo
2541 (lldb) frame variable my_foo
2544 "Produces output where only a and g are displayed. Other children of my_foo \
2545 (b, c, d, e, f, h and i) are available by asking for them explicitly:"
2548 (lldb) frame variable my_foo.b my_foo.c my_foo.i
2551 "The formatting option --raw on frame variable bypasses the filter, showing \
2552 all children of my_foo as if no filter was defined:"
2555 (lldb) frame variable my_foo --raw)");
2558 ~CommandObjectTypeFilterAdd() override = default;
2560 protected:
2561 void DoExecute(Args &command, CommandReturnObject &result) override {
2562 const size_t argc = command.GetArgumentCount();
2564 if (argc < 1) {
2565 result.AppendErrorWithFormat("%s takes one or more args.\n",
2566 m_cmd_name.c_str());
2567 return;
2570 if (m_options.m_expr_paths.empty()) {
2571 result.AppendErrorWithFormat("%s needs one or more children.\n",
2572 m_cmd_name.c_str());
2573 return;
2576 TypeFilterImplSP entry(new TypeFilterImpl(
2577 SyntheticChildren::Flags()
2578 .SetCascades(m_options.m_cascade)
2579 .SetSkipPointers(m_options.m_skip_pointers)
2580 .SetSkipReferences(m_options.m_skip_references)));
2582 // go through the expression paths
2583 CommandOptions::ExpressionPathsIterator begin,
2584 end = m_options.m_expr_paths.end();
2586 for (begin = m_options.m_expr_paths.begin(); begin != end; begin++)
2587 entry->AddExpressionPath(*begin);
2589 // now I have a valid provider, let's add it to every type
2591 lldb::TypeCategoryImplSP category;
2592 DataVisualization::Categories::GetCategory(
2593 ConstString(m_options.m_category.c_str()), category);
2595 Status error;
2597 WarnOnPotentialUnquotedUnsignedType(command, result);
2599 for (auto &arg_entry : command.entries()) {
2600 if (arg_entry.ref().empty()) {
2601 result.AppendError("empty typenames not allowed");
2602 return;
2605 ConstString typeCS(arg_entry.ref());
2606 if (!AddFilter(typeCS, entry,
2607 m_options.m_regex ? eRegexFilter : eRegularFilter,
2608 m_options.m_category, &error)) {
2609 result.AppendError(error.AsCString());
2610 return;
2614 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2618 // "type lookup"
2619 #define LLDB_OPTIONS_type_lookup
2620 #include "CommandOptions.inc"
2622 class CommandObjectTypeLookup : public CommandObjectRaw {
2623 protected:
2624 // this function is allowed to do a more aggressive job at guessing languages
2625 // than the expression parser is comfortable with - so leave the original
2626 // call alone and add one that is specific to type lookup
2627 lldb::LanguageType GuessLanguage(StackFrame *frame) {
2628 lldb::LanguageType lang_type = lldb::eLanguageTypeUnknown;
2630 if (!frame)
2631 return lang_type;
2633 lang_type = frame->GuessLanguage();
2634 if (lang_type != lldb::eLanguageTypeUnknown)
2635 return lang_type;
2637 Symbol *s = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
2638 if (s)
2639 lang_type = s->GetMangled().GuessLanguage();
2641 return lang_type;
2644 class CommandOptions : public OptionGroup {
2645 public:
2646 CommandOptions() = default;
2648 ~CommandOptions() override = default;
2650 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2651 return llvm::ArrayRef(g_type_lookup_options);
2654 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
2655 ExecutionContext *execution_context) override {
2656 Status error;
2658 const int short_option = g_type_lookup_options[option_idx].short_option;
2660 switch (short_option) {
2661 case 'h':
2662 m_show_help = true;
2663 break;
2665 case 'l':
2666 m_language = Language::GetLanguageTypeFromString(option_value);
2667 break;
2669 default:
2670 llvm_unreachable("Unimplemented option");
2673 return error;
2676 void OptionParsingStarting(ExecutionContext *execution_context) override {
2677 m_show_help = false;
2678 m_language = eLanguageTypeUnknown;
2681 // Options table: Required for subclasses of Options.
2683 bool m_show_help = false;
2684 lldb::LanguageType m_language = eLanguageTypeUnknown;
2687 OptionGroupOptions m_option_group;
2688 CommandOptions m_command_options;
2690 public:
2691 CommandObjectTypeLookup(CommandInterpreter &interpreter)
2692 : CommandObjectRaw(interpreter, "type lookup",
2693 "Lookup types and declarations in the current target, "
2694 "following language-specific naming conventions.",
2695 "type lookup <type-specifier>",
2696 eCommandRequiresTarget) {
2697 m_option_group.Append(&m_command_options);
2698 m_option_group.Finalize();
2701 ~CommandObjectTypeLookup() override = default;
2703 Options *GetOptions() override { return &m_option_group; }
2705 llvm::StringRef GetHelpLong() override {
2706 if (!m_cmd_help_long.empty())
2707 return m_cmd_help_long;
2709 StreamString stream;
2710 Language::ForEach([&](Language *lang) {
2711 if (const char *help = lang->GetLanguageSpecificTypeLookupHelp())
2712 stream.Printf("%s\n", help);
2713 return true;
2716 m_cmd_help_long = std::string(stream.GetString());
2717 return m_cmd_help_long;
2720 void DoExecute(llvm::StringRef raw_command_line,
2721 CommandReturnObject &result) override {
2722 if (raw_command_line.empty()) {
2723 result.AppendError(
2724 "type lookup cannot be invoked without a type name as argument");
2725 return;
2728 auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
2729 m_option_group.NotifyOptionParsingStarting(&exe_ctx);
2731 OptionsWithRaw args(raw_command_line);
2732 const char *name_of_type = args.GetRawPart().c_str();
2734 if (args.HasArgs())
2735 if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group,
2736 exe_ctx))
2737 return;
2739 ExecutionContextScope *best_scope = exe_ctx.GetBestExecutionContextScope();
2741 bool any_found = false;
2743 std::vector<Language *> languages;
2745 bool is_global_search = false;
2746 LanguageType guessed_language = lldb::eLanguageTypeUnknown;
2748 if ((is_global_search =
2749 (m_command_options.m_language == eLanguageTypeUnknown))) {
2750 Language::ForEach([&](Language *lang) {
2751 languages.push_back(lang);
2752 return true;
2754 } else {
2755 languages.push_back(Language::FindPlugin(m_command_options.m_language));
2758 // This is not the most efficient way to do this, but we support very few
2759 // languages so the cost of the sort is going to be dwarfed by the actual
2760 // lookup anyway
2761 if (StackFrame *frame = m_exe_ctx.GetFramePtr()) {
2762 guessed_language = GuessLanguage(frame);
2763 if (guessed_language != eLanguageTypeUnknown) {
2764 llvm::sort(
2765 languages.begin(), languages.end(),
2766 [guessed_language](Language *lang1, Language *lang2) -> bool {
2767 if (!lang1 || !lang2)
2768 return false;
2769 LanguageType lt1 = lang1->GetLanguageType();
2770 LanguageType lt2 = lang2->GetLanguageType();
2771 if (lt1 == guessed_language)
2772 return true; // make the selected frame's language come first
2773 if (lt2 == guessed_language)
2774 return false; // make the selected frame's language come first
2775 return (lt1 < lt2); // normal comparison otherwise
2780 bool is_first_language = true;
2782 for (Language *language : languages) {
2783 if (!language)
2784 continue;
2786 if (auto scavenger = language->GetTypeScavenger()) {
2787 Language::TypeScavenger::ResultSet search_results;
2788 if (scavenger->Find(best_scope, name_of_type, search_results) > 0) {
2789 for (const auto &search_result : search_results) {
2790 if (search_result && search_result->IsValid()) {
2791 any_found = true;
2792 search_result->DumpToStream(result.GetOutputStream(),
2793 this->m_command_options.m_show_help);
2798 // this is "type lookup SomeName" and we did find a match, so get out
2799 if (any_found && is_global_search)
2800 break;
2801 else if (is_first_language && is_global_search &&
2802 guessed_language != lldb::eLanguageTypeUnknown) {
2803 is_first_language = false;
2804 result.GetOutputStream().Printf(
2805 "no type was found in the current language %s matching '%s'; "
2806 "performing a global search across all languages\n",
2807 Language::GetNameForLanguageType(guessed_language), name_of_type);
2811 if (!any_found)
2812 result.AppendMessageWithFormat("no type was found matching '%s'\n",
2813 name_of_type);
2815 result.SetStatus(any_found ? lldb::eReturnStatusSuccessFinishResult
2816 : lldb::eReturnStatusSuccessFinishNoResult);
2820 template <typename FormatterType>
2821 class CommandObjectFormatterInfo : public CommandObjectRaw {
2822 public:
2823 typedef std::function<typename FormatterType::SharedPointer(ValueObject &)>
2824 DiscoveryFunction;
2825 CommandObjectFormatterInfo(CommandInterpreter &interpreter,
2826 const char *formatter_name,
2827 DiscoveryFunction discovery_func)
2828 : CommandObjectRaw(interpreter, "", "", "", eCommandRequiresFrame),
2829 m_formatter_name(formatter_name ? formatter_name : ""),
2830 m_discovery_function(discovery_func) {
2831 StreamString name;
2832 name.Printf("type %s info", formatter_name);
2833 SetCommandName(name.GetString());
2834 StreamString help;
2835 help.Printf("This command evaluates the provided expression and shows "
2836 "which %s is applied to the resulting value (if any).",
2837 formatter_name);
2838 SetHelp(help.GetString());
2839 StreamString syntax;
2840 syntax.Printf("type %s info <expr>", formatter_name);
2841 SetSyntax(syntax.GetString());
2844 ~CommandObjectFormatterInfo() override = default;
2846 protected:
2847 void DoExecute(llvm::StringRef command,
2848 CommandReturnObject &result) override {
2849 TargetSP target_sp = GetDebugger().GetSelectedTarget();
2850 Thread *thread = GetDefaultThread();
2851 if (!thread) {
2852 result.AppendError("no default thread");
2853 return;
2856 StackFrameSP frame_sp =
2857 thread->GetSelectedFrame(DoNoSelectMostRelevantFrame);
2858 ValueObjectSP result_valobj_sp;
2859 EvaluateExpressionOptions options;
2860 lldb::ExpressionResults expr_result = target_sp->EvaluateExpression(
2861 command, frame_sp.get(), result_valobj_sp, options);
2862 if (expr_result == eExpressionCompleted && result_valobj_sp) {
2863 result_valobj_sp =
2864 result_valobj_sp->GetQualifiedRepresentationIfAvailable(
2865 target_sp->GetPreferDynamicValue(),
2866 target_sp->GetEnableSyntheticValue());
2867 typename FormatterType::SharedPointer formatter_sp =
2868 m_discovery_function(*result_valobj_sp);
2869 if (formatter_sp) {
2870 std::string description(formatter_sp->GetDescription());
2871 result.GetOutputStream()
2872 << m_formatter_name << " applied to ("
2873 << result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>")
2874 << ") " << command << " is: " << description << "\n";
2875 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
2876 } else {
2877 result.GetOutputStream()
2878 << "no " << m_formatter_name << " applies to ("
2879 << result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>")
2880 << ") " << command << "\n";
2881 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
2883 } else {
2884 result.AppendError("failed to evaluate expression");
2888 private:
2889 std::string m_formatter_name;
2890 DiscoveryFunction m_discovery_function;
2893 class CommandObjectTypeFormat : public CommandObjectMultiword {
2894 public:
2895 CommandObjectTypeFormat(CommandInterpreter &interpreter)
2896 : CommandObjectMultiword(
2897 interpreter, "type format",
2898 "Commands for customizing value display formats.",
2899 "type format [<sub-command-options>] ") {
2900 LoadSubCommand(
2901 "add", CommandObjectSP(new CommandObjectTypeFormatAdd(interpreter)));
2902 LoadSubCommand("clear", CommandObjectSP(
2903 new CommandObjectTypeFormatClear(interpreter)));
2904 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeFormatDelete(
2905 interpreter)));
2906 LoadSubCommand(
2907 "list", CommandObjectSP(new CommandObjectTypeFormatList(interpreter)));
2908 LoadSubCommand(
2909 "info", CommandObjectSP(new CommandObjectFormatterInfo<TypeFormatImpl>(
2910 interpreter, "format",
2911 [](ValueObject &valobj) -> TypeFormatImpl::SharedPointer {
2912 return valobj.GetValueFormat();
2913 })));
2916 ~CommandObjectTypeFormat() override = default;
2919 class CommandObjectTypeSynth : public CommandObjectMultiword {
2920 public:
2921 CommandObjectTypeSynth(CommandInterpreter &interpreter)
2922 : CommandObjectMultiword(
2923 interpreter, "type synthetic",
2924 "Commands for operating on synthetic type representations.",
2925 "type synthetic [<sub-command-options>] ") {
2926 LoadSubCommand("add",
2927 CommandObjectSP(new CommandObjectTypeSynthAdd(interpreter)));
2928 LoadSubCommand(
2929 "clear", CommandObjectSP(new CommandObjectTypeSynthClear(interpreter)));
2930 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeSynthDelete(
2931 interpreter)));
2932 LoadSubCommand(
2933 "list", CommandObjectSP(new CommandObjectTypeSynthList(interpreter)));
2934 LoadSubCommand(
2935 "info",
2936 CommandObjectSP(new CommandObjectFormatterInfo<SyntheticChildren>(
2937 interpreter, "synthetic",
2938 [](ValueObject &valobj) -> SyntheticChildren::SharedPointer {
2939 return valobj.GetSyntheticChildren();
2940 })));
2943 ~CommandObjectTypeSynth() override = default;
2946 class CommandObjectTypeFilter : public CommandObjectMultiword {
2947 public:
2948 CommandObjectTypeFilter(CommandInterpreter &interpreter)
2949 : CommandObjectMultiword(interpreter, "type filter",
2950 "Commands for operating on type filters.",
2951 "type filter [<sub-command-options>] ") {
2952 LoadSubCommand(
2953 "add", CommandObjectSP(new CommandObjectTypeFilterAdd(interpreter)));
2954 LoadSubCommand("clear", CommandObjectSP(
2955 new CommandObjectTypeFilterClear(interpreter)));
2956 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeFilterDelete(
2957 interpreter)));
2958 LoadSubCommand(
2959 "list", CommandObjectSP(new CommandObjectTypeFilterList(interpreter)));
2962 ~CommandObjectTypeFilter() override = default;
2965 class CommandObjectTypeCategory : public CommandObjectMultiword {
2966 public:
2967 CommandObjectTypeCategory(CommandInterpreter &interpreter)
2968 : CommandObjectMultiword(interpreter, "type category",
2969 "Commands for operating on type categories.",
2970 "type category [<sub-command-options>] ") {
2971 LoadSubCommand(
2972 "define",
2973 CommandObjectSP(new CommandObjectTypeCategoryDefine(interpreter)));
2974 LoadSubCommand(
2975 "enable",
2976 CommandObjectSP(new CommandObjectTypeCategoryEnable(interpreter)));
2977 LoadSubCommand(
2978 "disable",
2979 CommandObjectSP(new CommandObjectTypeCategoryDisable(interpreter)));
2980 LoadSubCommand(
2981 "delete",
2982 CommandObjectSP(new CommandObjectTypeCategoryDelete(interpreter)));
2983 LoadSubCommand("list", CommandObjectSP(
2984 new CommandObjectTypeCategoryList(interpreter)));
2987 ~CommandObjectTypeCategory() override = default;
2990 class CommandObjectTypeSummary : public CommandObjectMultiword {
2991 public:
2992 CommandObjectTypeSummary(CommandInterpreter &interpreter)
2993 : CommandObjectMultiword(
2994 interpreter, "type summary",
2995 "Commands for editing variable summary display options.",
2996 "type summary [<sub-command-options>] ") {
2997 LoadSubCommand(
2998 "add", CommandObjectSP(new CommandObjectTypeSummaryAdd(interpreter)));
2999 LoadSubCommand("clear", CommandObjectSP(new CommandObjectTypeSummaryClear(
3000 interpreter)));
3001 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeSummaryDelete(
3002 interpreter)));
3003 LoadSubCommand(
3004 "list", CommandObjectSP(new CommandObjectTypeSummaryList(interpreter)));
3005 LoadSubCommand(
3006 "info", CommandObjectSP(new CommandObjectFormatterInfo<TypeSummaryImpl>(
3007 interpreter, "summary",
3008 [](ValueObject &valobj) -> TypeSummaryImpl::SharedPointer {
3009 return valobj.GetSummaryFormat();
3010 })));
3013 ~CommandObjectTypeSummary() override = default;
3016 // CommandObjectType
3018 CommandObjectType::CommandObjectType(CommandInterpreter &interpreter)
3019 : CommandObjectMultiword(interpreter, "type",
3020 "Commands for operating on the type system.",
3021 "type [<sub-command-options>]") {
3022 LoadSubCommand("category",
3023 CommandObjectSP(new CommandObjectTypeCategory(interpreter)));
3024 LoadSubCommand("filter",
3025 CommandObjectSP(new CommandObjectTypeFilter(interpreter)));
3026 LoadSubCommand("format",
3027 CommandObjectSP(new CommandObjectTypeFormat(interpreter)));
3028 LoadSubCommand("summary",
3029 CommandObjectSP(new CommandObjectTypeSummary(interpreter)));
3030 LoadSubCommand("synthetic",
3031 CommandObjectSP(new CommandObjectTypeSynth(interpreter)));
3032 LoadSubCommand("lookup",
3033 CommandObjectSP(new CommandObjectTypeLookup(interpreter)));
3036 CommandObjectType::~CommandObjectType() = default;