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