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