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