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