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