brintos

brintos / llvm-project-archived public Read only

0
0
Text · 97.6 KiB · 22ed5b8 Raw
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        [&regex, &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