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