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