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