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