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