[NFC][Coroutines] Use structured binding with llvm::enumerate in CoroSplit (#116879)
[llvm-project.git] / lldb / source / Commands / CommandObjectType.cpp
blobe4c6e374446e8277bcb7c1cca4aecc9a7cb2191b
1 //===-- CommandObjectType.cpp ---------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "CommandObjectType.h"
11 #include "lldb/Core/Debugger.h"
12 #include "lldb/Core/IOHandler.h"
13 #include "lldb/DataFormatters/DataVisualization.h"
14 #include "lldb/DataFormatters/FormatClasses.h"
15 #include "lldb/Host/Config.h"
16 #include "lldb/Host/OptionParser.h"
17 #include "lldb/Interpreter/CommandInterpreter.h"
18 #include "lldb/Interpreter/CommandObject.h"
19 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
20 #include "lldb/Interpreter/CommandReturnObject.h"
21 #include "lldb/Interpreter/OptionArgParser.h"
22 #include "lldb/Interpreter/OptionGroupFormat.h"
23 #include "lldb/Interpreter/OptionValueBoolean.h"
24 #include "lldb/Interpreter/OptionValueLanguage.h"
25 #include "lldb/Interpreter/OptionValueString.h"
26 #include "lldb/Interpreter/Options.h"
27 #include "lldb/Symbol/Symbol.h"
28 #include "lldb/Target/Language.h"
29 #include "lldb/Target/StackFrame.h"
30 #include "lldb/Target/Target.h"
31 #include "lldb/Target/Thread.h"
32 #include "lldb/Utility/ConstString.h"
33 #include "lldb/Utility/RegularExpression.h"
34 #include "lldb/Utility/StringList.h"
36 #include "llvm/ADT/STLExtras.h"
38 #include <algorithm>
39 #include <functional>
40 #include <memory>
42 using namespace lldb;
43 using namespace lldb_private;
45 class ScriptAddOptions {
46 public:
47 TypeSummaryImpl::Flags m_flags;
48 StringList m_target_types;
49 FormatterMatchType m_match_type;
50 ConstString m_name;
51 std::string m_category;
53 ScriptAddOptions(const TypeSummaryImpl::Flags &flags,
54 FormatterMatchType match_type, ConstString name,
55 std::string catg)
56 : m_flags(flags), m_match_type(match_type), m_name(name),
57 m_category(catg) {}
59 typedef std::shared_ptr<ScriptAddOptions> SharedPointer;
62 class SynthAddOptions {
63 public:
64 bool m_skip_pointers;
65 bool m_skip_references;
66 bool m_cascade;
67 FormatterMatchType m_match_type;
68 StringList m_target_types;
69 std::string m_category;
71 SynthAddOptions(bool sptr, bool sref, bool casc,
72 FormatterMatchType match_type, std::string catg)
73 : m_skip_pointers(sptr), m_skip_references(sref), m_cascade(casc),
74 m_match_type(match_type), m_category(catg) {}
76 typedef std::shared_ptr<SynthAddOptions> SharedPointer;
79 static bool WarnOnPotentialUnquotedUnsignedType(Args &command,
80 CommandReturnObject &result) {
81 if (command.empty())
82 return false;
84 for (auto entry : llvm::enumerate(command.entries().drop_back())) {
85 if (entry.value().ref() != "unsigned")
86 continue;
87 auto next = command.entries()[entry.index() + 1].ref();
88 if (next == "int" || next == "short" || next == "char" || next == "long") {
89 result.AppendWarningWithFormat(
90 "unsigned %s being treated as two types. if you meant the combined "
91 "type "
92 "name use quotes, as in \"unsigned %s\"\n",
93 next.str().c_str(), next.str().c_str());
94 return true;
97 return false;
100 const char *FormatCategoryToString(FormatCategoryItem item, bool long_name) {
101 switch (item) {
102 case eFormatCategoryItemSummary:
103 return "summary";
104 case eFormatCategoryItemFilter:
105 return "filter";
106 case eFormatCategoryItemSynth:
107 if (long_name)
108 return "synthetic child provider";
109 return "synthetic";
110 case eFormatCategoryItemFormat:
111 return "format";
113 llvm_unreachable("Fully covered switch above!");
116 #define LLDB_OPTIONS_type_summary_add
117 #include "CommandOptions.inc"
119 class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
120 public IOHandlerDelegateMultiline {
121 private:
122 class CommandOptions : public Options {
123 public:
124 CommandOptions(CommandInterpreter &interpreter) {}
126 ~CommandOptions() override = default;
128 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
129 ExecutionContext *execution_context) override;
131 void OptionParsingStarting(ExecutionContext *execution_context) override;
133 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
134 return llvm::ArrayRef(g_type_summary_add_options);
137 // Instance variables to hold the values for command options.
139 TypeSummaryImpl::Flags m_flags;
140 FormatterMatchType m_match_type = eFormatterMatchExact;
141 std::string m_format_string;
142 ConstString m_name;
143 std::string m_python_script;
144 std::string m_python_function;
145 bool m_is_add_script = false;
146 std::string m_category;
149 CommandOptions m_options;
151 Options *GetOptions() override { return &m_options; }
153 bool Execute_ScriptSummary(Args &command, CommandReturnObject &result);
155 bool Execute_StringSummary(Args &command, CommandReturnObject &result);
157 public:
158 CommandObjectTypeSummaryAdd(CommandInterpreter &interpreter);
160 ~CommandObjectTypeSummaryAdd() override = default;
162 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
163 static const char *g_summary_addreader_instructions =
164 "Enter your Python command(s). Type 'DONE' to end.\n"
165 "def function (valobj,internal_dict):\n"
166 " \"\"\"valobj: an SBValue which you want to provide a summary "
167 "for\n"
168 " internal_dict: an LLDB support object not to be used\"\"\"\n";
170 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
171 if (output_sp && interactive) {
172 output_sp->PutCString(g_summary_addreader_instructions);
173 output_sp->Flush();
177 void IOHandlerInputComplete(IOHandler &io_handler,
178 std::string &data) override {
179 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
181 #if LLDB_ENABLE_PYTHON
182 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
183 if (interpreter) {
184 StringList lines;
185 lines.SplitIntoLines(data);
186 if (lines.GetSize() > 0) {
187 ScriptAddOptions *options_ptr =
188 ((ScriptAddOptions *)io_handler.GetUserData());
189 if (options_ptr) {
190 ScriptAddOptions::SharedPointer options(
191 options_ptr); // this will ensure that we get rid of the pointer
192 // when going out of scope
194 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
195 if (interpreter) {
196 std::string funct_name_str;
197 if (interpreter->GenerateTypeScriptFunction(lines,
198 funct_name_str)) {
199 if (funct_name_str.empty()) {
200 error_sp->Printf("unable to obtain a valid function name from "
201 "the script interpreter.\n");
202 error_sp->Flush();
203 } else {
204 // now I have a valid function name, let's add this as script
205 // for every type in the list
207 TypeSummaryImplSP script_format;
208 script_format = std::make_shared<ScriptSummaryFormat>(
209 options->m_flags, funct_name_str.c_str(),
210 lines.CopyList(" ").c_str());
212 Status error;
214 for (const std::string &type_name : options->m_target_types) {
215 AddSummary(ConstString(type_name), script_format,
216 options->m_match_type, options->m_category,
217 &error);
218 if (error.Fail()) {
219 error_sp->Printf("error: %s", error.AsCString());
220 error_sp->Flush();
224 if (options->m_name) {
225 CommandObjectTypeSummaryAdd::AddNamedSummary(
226 options->m_name, script_format, &error);
227 if (error.Fail()) {
228 CommandObjectTypeSummaryAdd::AddNamedSummary(
229 options->m_name, script_format, &error);
230 if (error.Fail()) {
231 error_sp->Printf("error: %s", error.AsCString());
232 error_sp->Flush();
234 } else {
235 error_sp->Printf("error: %s", error.AsCString());
236 error_sp->Flush();
238 } else {
239 if (error.AsCString()) {
240 error_sp->Printf("error: %s", error.AsCString());
241 error_sp->Flush();
245 } else {
246 error_sp->Printf("error: unable to generate a function.\n");
247 error_sp->Flush();
249 } else {
250 error_sp->Printf("error: no script interpreter.\n");
251 error_sp->Flush();
253 } else {
254 error_sp->Printf("error: internal synchronization information "
255 "missing or invalid.\n");
256 error_sp->Flush();
258 } else {
259 error_sp->Printf("error: empty function, didn't add python command.\n");
260 error_sp->Flush();
262 } else {
263 error_sp->Printf(
264 "error: script interpreter missing, didn't add python command.\n");
265 error_sp->Flush();
267 #endif
268 io_handler.SetIsDone(true);
271 bool AddSummary(ConstString type_name, lldb::TypeSummaryImplSP entry,
272 FormatterMatchType match_type, std::string category,
273 Status *error = nullptr);
275 bool AddNamedSummary(ConstString summary_name, lldb::TypeSummaryImplSP entry,
276 Status *error = nullptr);
278 protected:
279 void DoExecute(Args &command, CommandReturnObject &result) override;
282 static const char *g_synth_addreader_instructions =
283 "Enter your Python command(s). Type 'DONE' to end.\n"
284 "You must define a Python class with these methods:\n"
285 " def __init__(self, valobj, internal_dict):\n"
286 " def num_children(self):\n"
287 " def get_child_at_index(self, index):\n"
288 " def get_child_index(self, name):\n"
289 " def update(self):\n"
290 " '''Optional'''\n"
291 "class synthProvider:\n";
293 #define LLDB_OPTIONS_type_synth_add
294 #include "CommandOptions.inc"
296 class CommandObjectTypeSynthAdd : public CommandObjectParsed,
297 public IOHandlerDelegateMultiline {
298 private:
299 class CommandOptions : public Options {
300 public:
301 CommandOptions() = default;
303 ~CommandOptions() override = default;
305 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
306 ExecutionContext *execution_context) override {
307 Status error;
308 const int short_option = m_getopt_table[option_idx].val;
309 bool success;
311 switch (short_option) {
312 case 'C':
313 m_cascade = OptionArgParser::ToBoolean(option_arg, true, &success);
314 if (!success)
315 error = Status::FromErrorStringWithFormat(
316 "invalid value for cascade: %s", option_arg.str().c_str());
317 break;
318 case 'P':
319 handwrite_python = true;
320 break;
321 case 'l':
322 m_class_name = std::string(option_arg);
323 is_class_based = true;
324 break;
325 case 'p':
326 m_skip_pointers = true;
327 break;
328 case 'r':
329 m_skip_references = true;
330 break;
331 case 'w':
332 m_category = std::string(option_arg);
333 break;
334 case 'x':
335 if (m_match_type == eFormatterMatchCallback)
336 error = Status::FromErrorString(
337 "can't use --regex and --recognizer-function at the same time");
338 else
339 m_match_type = eFormatterMatchRegex;
340 break;
341 case '\x01':
342 if (m_match_type == eFormatterMatchRegex)
343 error = Status::FromErrorString(
344 "can't use --regex and --recognizer-function at the same time");
345 else
346 m_match_type = eFormatterMatchCallback;
347 break;
348 default:
349 llvm_unreachable("Unimplemented option");
352 return error;
355 void OptionParsingStarting(ExecutionContext *execution_context) override {
356 m_cascade = true;
357 m_class_name = "";
358 m_skip_pointers = false;
359 m_skip_references = false;
360 m_category = "default";
361 is_class_based = false;
362 handwrite_python = false;
363 m_match_type = eFormatterMatchExact;
366 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
367 return llvm::ArrayRef(g_type_synth_add_options);
370 // Instance variables to hold the values for command options.
372 bool m_cascade;
373 bool m_skip_references;
374 bool m_skip_pointers;
375 std::string m_class_name;
376 bool m_input_python;
377 std::string m_category;
378 bool is_class_based;
379 bool handwrite_python;
380 FormatterMatchType m_match_type;
383 CommandOptions m_options;
385 Options *GetOptions() override { return &m_options; }
387 bool Execute_HandwritePython(Args &command, CommandReturnObject &result);
389 bool Execute_PythonClass(Args &command, CommandReturnObject &result);
391 protected:
392 void DoExecute(Args &command, CommandReturnObject &result) override {
393 WarnOnPotentialUnquotedUnsignedType(command, result);
395 if (m_options.handwrite_python)
396 Execute_HandwritePython(command, result);
397 else if (m_options.is_class_based)
398 Execute_PythonClass(command, result);
399 else {
400 result.AppendError("must either provide a children list, a Python class "
401 "name, or use -P and type a Python class "
402 "line-by-line");
406 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
407 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
408 if (output_sp && interactive) {
409 output_sp->PutCString(g_synth_addreader_instructions);
410 output_sp->Flush();
414 void IOHandlerInputComplete(IOHandler &io_handler,
415 std::string &data) override {
416 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
418 #if LLDB_ENABLE_PYTHON
419 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
420 if (interpreter) {
421 StringList lines;
422 lines.SplitIntoLines(data);
423 if (lines.GetSize() > 0) {
424 SynthAddOptions *options_ptr =
425 ((SynthAddOptions *)io_handler.GetUserData());
426 if (options_ptr) {
427 SynthAddOptions::SharedPointer options(
428 options_ptr); // this will ensure that we get rid of the pointer
429 // when going out of scope
431 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
432 if (interpreter) {
433 std::string class_name_str;
434 if (interpreter->GenerateTypeSynthClass(lines, class_name_str)) {
435 if (class_name_str.empty()) {
436 error_sp->Printf(
437 "error: unable to obtain a proper name for the class.\n");
438 error_sp->Flush();
439 } else {
440 // everything should be fine now, let's add the synth provider
441 // class
443 SyntheticChildrenSP synth_provider;
444 synth_provider = std::make_shared<ScriptedSyntheticChildren>(
445 SyntheticChildren::Flags()
446 .SetCascades(options->m_cascade)
447 .SetSkipPointers(options->m_skip_pointers)
448 .SetSkipReferences(options->m_skip_references),
449 class_name_str.c_str());
451 lldb::TypeCategoryImplSP category;
452 DataVisualization::Categories::GetCategory(
453 ConstString(options->m_category.c_str()), category);
455 Status error;
457 for (const std::string &type_name : options->m_target_types) {
458 if (!type_name.empty()) {
459 if (AddSynth(ConstString(type_name), synth_provider,
460 options->m_match_type, options->m_category,
461 &error)) {
462 error_sp->Printf("error: %s\n", error.AsCString());
463 error_sp->Flush();
464 break;
466 } else {
467 error_sp->Printf("error: invalid type name.\n");
468 error_sp->Flush();
469 break;
473 } else {
474 error_sp->Printf("error: unable to generate a class.\n");
475 error_sp->Flush();
477 } else {
478 error_sp->Printf("error: no script interpreter.\n");
479 error_sp->Flush();
481 } else {
482 error_sp->Printf("error: internal synchronization data missing.\n");
483 error_sp->Flush();
485 } else {
486 error_sp->Printf("error: empty function, didn't add python command.\n");
487 error_sp->Flush();
489 } else {
490 error_sp->Printf(
491 "error: script interpreter missing, didn't add python command.\n");
492 error_sp->Flush();
495 #endif
496 io_handler.SetIsDone(true);
499 public:
500 CommandObjectTypeSynthAdd(CommandInterpreter &interpreter);
502 ~CommandObjectTypeSynthAdd() override = default;
504 bool AddSynth(ConstString type_name, lldb::SyntheticChildrenSP entry,
505 FormatterMatchType match_type, std::string category_name,
506 Status *error);
509 // CommandObjectTypeFormatAdd
511 #define LLDB_OPTIONS_type_format_add
512 #include "CommandOptions.inc"
514 class CommandObjectTypeFormatAdd : public CommandObjectParsed {
515 private:
516 class CommandOptions : public OptionGroup {
517 public:
518 CommandOptions() = default;
520 ~CommandOptions() override = default;
522 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
523 return llvm::ArrayRef(g_type_format_add_options);
526 void OptionParsingStarting(ExecutionContext *execution_context) override {
527 m_cascade = true;
528 m_skip_pointers = false;
529 m_skip_references = false;
530 m_regex = false;
531 m_category.assign("default");
532 m_custom_type_name.clear();
535 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
536 ExecutionContext *execution_context) override {
537 Status error;
538 const int short_option =
539 g_type_format_add_options[option_idx].short_option;
540 bool success;
542 switch (short_option) {
543 case 'C':
544 m_cascade = OptionArgParser::ToBoolean(option_value, true, &success);
545 if (!success)
546 error = Status::FromErrorStringWithFormat(
547 "invalid value for cascade: %s", option_value.str().c_str());
548 break;
549 case 'p':
550 m_skip_pointers = true;
551 break;
552 case 'w':
553 m_category.assign(std::string(option_value));
554 break;
555 case 'r':
556 m_skip_references = true;
557 break;
558 case 'x':
559 m_regex = true;
560 break;
561 case 't':
562 m_custom_type_name.assign(std::string(option_value));
563 break;
564 default:
565 llvm_unreachable("Unimplemented option");
568 return error;
571 // Instance variables to hold the values for command options.
573 bool m_cascade;
574 bool m_skip_references;
575 bool m_skip_pointers;
576 bool m_regex;
577 std::string m_category;
578 std::string m_custom_type_name;
581 OptionGroupOptions m_option_group;
582 OptionGroupFormat m_format_options;
583 CommandOptions m_command_options;
585 Options *GetOptions() override { return &m_option_group; }
587 public:
588 CommandObjectTypeFormatAdd(CommandInterpreter &interpreter)
589 : CommandObjectParsed(interpreter, "type format add",
590 "Add a new formatting style for a type.", nullptr),
591 m_format_options(eFormatInvalid) {
592 AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus);
594 SetHelpLong(
596 The following examples of 'type format add' refer to this code snippet for context:
598 typedef int Aint;
599 typedef float Afloat;
600 typedef Aint Bint;
601 typedef Afloat Bfloat;
603 Aint ix = 5;
604 Bint iy = 5;
606 Afloat fx = 3.14;
607 BFloat fy = 3.14;
609 Adding default formatting:
611 (lldb) type format add -f hex AInt
612 (lldb) frame variable iy
615 " Produces hexadecimal display of iy, because no formatter is available for Bint and \
616 the one for Aint is used instead."
619 To prevent this use the cascade option '-C no' to prevent evaluation of typedef chains:
622 (lldb) type format add -f hex -C no AInt
624 Similar reasoning applies to this:
626 (lldb) type format add -f hex -C no float -p
629 " All float values and float references are now formatted as hexadecimal, but not \
630 pointers to floats. Nor will it change the default display for Afloat and Bfloat objects.");
632 // Add the "--format" to all options groups
633 m_option_group.Append(&m_format_options,
634 OptionGroupFormat::OPTION_GROUP_FORMAT,
635 LLDB_OPT_SET_1);
636 m_option_group.Append(&m_command_options);
637 m_option_group.Finalize();
640 ~CommandObjectTypeFormatAdd() override = default;
642 protected:
643 void DoExecute(Args &command, CommandReturnObject &result) override {
644 const size_t argc = command.GetArgumentCount();
646 if (argc < 1) {
647 result.AppendErrorWithFormat("%s takes one or more args.\n",
648 m_cmd_name.c_str());
649 return;
652 const Format format = m_format_options.GetFormat();
653 if (format == eFormatInvalid &&
654 m_command_options.m_custom_type_name.empty()) {
655 result.AppendErrorWithFormat("%s needs a valid format.\n",
656 m_cmd_name.c_str());
657 return;
660 TypeFormatImplSP entry;
662 if (m_command_options.m_custom_type_name.empty())
663 entry = std::make_shared<TypeFormatImpl_Format>(
664 format, TypeFormatImpl::Flags()
665 .SetCascades(m_command_options.m_cascade)
666 .SetSkipPointers(m_command_options.m_skip_pointers)
667 .SetSkipReferences(m_command_options.m_skip_references));
668 else
669 entry = std::make_shared<TypeFormatImpl_EnumType>(
670 ConstString(m_command_options.m_custom_type_name.c_str()),
671 TypeFormatImpl::Flags()
672 .SetCascades(m_command_options.m_cascade)
673 .SetSkipPointers(m_command_options.m_skip_pointers)
674 .SetSkipReferences(m_command_options.m_skip_references));
676 // now I have a valid format, let's add it to every type
678 TypeCategoryImplSP category_sp;
679 DataVisualization::Categories::GetCategory(
680 ConstString(m_command_options.m_category), category_sp);
681 if (!category_sp)
682 return;
684 WarnOnPotentialUnquotedUnsignedType(command, result);
686 for (auto &arg_entry : command.entries()) {
687 if (arg_entry.ref().empty()) {
688 result.AppendError("empty typenames not allowed");
689 return;
692 FormatterMatchType match_type = eFormatterMatchExact;
693 if (m_command_options.m_regex) {
694 match_type = eFormatterMatchRegex;
695 RegularExpression typeRX(arg_entry.ref());
696 if (!typeRX.IsValid()) {
697 result.AppendError(
698 "regex format error (maybe this is not really a regex?)");
699 return;
702 category_sp->AddTypeFormat(arg_entry.ref(), match_type, entry);
705 result.SetStatus(eReturnStatusSuccessFinishNoResult);
709 #define LLDB_OPTIONS_type_formatter_delete
710 #include "CommandOptions.inc"
712 class CommandObjectTypeFormatterDelete : public CommandObjectParsed {
713 protected:
714 class CommandOptions : public Options {
715 public:
716 CommandOptions() = default;
718 ~CommandOptions() override = default;
720 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
721 ExecutionContext *execution_context) override {
722 Status error;
723 const int short_option = m_getopt_table[option_idx].val;
725 switch (short_option) {
726 case 'a':
727 m_delete_all = true;
728 break;
729 case 'w':
730 m_category = std::string(option_arg);
731 break;
732 case 'l':
733 m_language = Language::GetLanguageTypeFromString(option_arg);
734 break;
735 default:
736 llvm_unreachable("Unimplemented option");
739 return error;
742 void OptionParsingStarting(ExecutionContext *execution_context) override {
743 m_delete_all = false;
744 m_category = "default";
745 m_language = lldb::eLanguageTypeUnknown;
748 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
749 return llvm::ArrayRef(g_type_formatter_delete_options);
752 // Instance variables to hold the values for command options.
754 bool m_delete_all;
755 std::string m_category;
756 lldb::LanguageType m_language;
759 CommandOptions m_options;
760 FormatCategoryItem m_formatter_kind;
762 Options *GetOptions() override { return &m_options; }
764 static constexpr const char *g_short_help_template =
765 "Delete an existing %s for a type.";
767 static constexpr const char *g_long_help_template =
768 "Delete an existing %s for a type. Unless you specify a "
769 "specific category or all categories, only the "
770 "'default' category is searched. The names must be exactly as "
771 "shown in the 'type %s list' output";
773 public:
774 CommandObjectTypeFormatterDelete(CommandInterpreter &interpreter,
775 FormatCategoryItem formatter_kind)
776 : CommandObjectParsed(interpreter,
777 FormatCategoryToString(formatter_kind, false)),
778 m_formatter_kind(formatter_kind) {
779 AddSimpleArgumentList(eArgTypeName);
781 const char *kind = FormatCategoryToString(formatter_kind, true);
782 const char *short_kind = FormatCategoryToString(formatter_kind, false);
784 StreamString s;
785 s.Printf(g_short_help_template, kind);
786 SetHelp(s.GetData());
787 s.Clear();
788 s.Printf(g_long_help_template, kind, short_kind);
789 SetHelpLong(s.GetData());
790 s.Clear();
791 s.Printf("type %s delete", short_kind);
792 SetCommandName(s.GetData());
795 ~CommandObjectTypeFormatterDelete() override = default;
797 void
798 HandleArgumentCompletion(CompletionRequest &request,
799 OptionElementVector &opt_element_vector) override {
800 if (request.GetCursorIndex())
801 return;
803 DataVisualization::Categories::ForEach(
804 [this, &request](const lldb::TypeCategoryImplSP &category_sp) {
805 category_sp->AutoComplete(request, m_formatter_kind);
806 return true;
810 protected:
811 virtual bool FormatterSpecificDeletion(ConstString typeCS) { return false; }
813 void DoExecute(Args &command, CommandReturnObject &result) override {
814 const size_t argc = command.GetArgumentCount();
816 if (argc != 1) {
817 result.AppendErrorWithFormat("%s takes 1 arg.\n", m_cmd_name.c_str());
818 return;
821 const char *typeA = command.GetArgumentAtIndex(0);
822 ConstString typeCS(typeA);
824 if (!typeCS) {
825 result.AppendError("empty typenames not allowed");
826 return;
829 if (m_options.m_delete_all) {
830 DataVisualization::Categories::ForEach(
831 [this, typeCS](const lldb::TypeCategoryImplSP &category_sp) -> bool {
832 category_sp->Delete(typeCS, m_formatter_kind);
833 return true;
835 result.SetStatus(eReturnStatusSuccessFinishNoResult);
836 return;
839 bool delete_category = false;
840 bool extra_deletion = false;
842 if (m_options.m_language != lldb::eLanguageTypeUnknown) {
843 lldb::TypeCategoryImplSP category;
844 DataVisualization::Categories::GetCategory(m_options.m_language,
845 category);
846 if (category)
847 delete_category = category->Delete(typeCS, m_formatter_kind);
848 extra_deletion = FormatterSpecificDeletion(typeCS);
849 } else {
850 lldb::TypeCategoryImplSP category;
851 DataVisualization::Categories::GetCategory(
852 ConstString(m_options.m_category.c_str()), category);
853 if (category)
854 delete_category = category->Delete(typeCS, m_formatter_kind);
855 extra_deletion = FormatterSpecificDeletion(typeCS);
858 if (delete_category || extra_deletion) {
859 result.SetStatus(eReturnStatusSuccessFinishNoResult);
860 } else {
861 result.AppendErrorWithFormat("no custom formatter for %s.\n", typeA);
866 #define LLDB_OPTIONS_type_formatter_clear
867 #include "CommandOptions.inc"
869 class CommandObjectTypeFormatterClear : public CommandObjectParsed {
870 private:
871 class CommandOptions : public Options {
872 public:
873 CommandOptions() = default;
875 ~CommandOptions() override = default;
877 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
878 ExecutionContext *execution_context) override {
879 Status error;
880 const int short_option = m_getopt_table[option_idx].val;
882 switch (short_option) {
883 case 'a':
884 m_delete_all = true;
885 break;
886 default:
887 llvm_unreachable("Unimplemented option");
890 return error;
893 void OptionParsingStarting(ExecutionContext *execution_context) override {
894 m_delete_all = false;
897 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
898 return llvm::ArrayRef(g_type_formatter_clear_options);
901 // Instance variables to hold the values for command options.
902 bool m_delete_all;
905 CommandOptions m_options;
906 FormatCategoryItem m_formatter_kind;
908 Options *GetOptions() override { return &m_options; }
910 public:
911 CommandObjectTypeFormatterClear(CommandInterpreter &interpreter,
912 FormatCategoryItem formatter_kind,
913 const char *name, const char *help)
914 : CommandObjectParsed(interpreter, name, help, nullptr),
915 m_formatter_kind(formatter_kind) {
916 AddSimpleArgumentList(eArgTypeName, eArgRepeatOptional);
919 ~CommandObjectTypeFormatterClear() override = default;
921 protected:
922 virtual void FormatterSpecificDeletion() {}
924 void DoExecute(Args &command, CommandReturnObject &result) override {
925 if (m_options.m_delete_all) {
926 DataVisualization::Categories::ForEach(
927 [this](const TypeCategoryImplSP &category_sp) -> bool {
928 category_sp->Clear(m_formatter_kind);
929 return true;
931 } else {
932 lldb::TypeCategoryImplSP category;
933 if (command.GetArgumentCount() > 0) {
934 const char *cat_name = command.GetArgumentAtIndex(0);
935 ConstString cat_nameCS(cat_name);
936 DataVisualization::Categories::GetCategory(cat_nameCS, category);
937 } else {
938 DataVisualization::Categories::GetCategory(ConstString(nullptr),
939 category);
941 category->Clear(m_formatter_kind);
944 FormatterSpecificDeletion();
946 result.SetStatus(eReturnStatusSuccessFinishResult);
950 // CommandObjectTypeFormatDelete
952 class CommandObjectTypeFormatDelete : public CommandObjectTypeFormatterDelete {
953 public:
954 CommandObjectTypeFormatDelete(CommandInterpreter &interpreter)
955 : CommandObjectTypeFormatterDelete(
956 interpreter, eFormatCategoryItemFormat) {}
958 ~CommandObjectTypeFormatDelete() override = default;
961 // CommandObjectTypeFormatClear
963 class CommandObjectTypeFormatClear : public CommandObjectTypeFormatterClear {
964 public:
965 CommandObjectTypeFormatClear(CommandInterpreter &interpreter)
966 : CommandObjectTypeFormatterClear(interpreter, eFormatCategoryItemFormat,
967 "type format clear",
968 "Delete all existing format styles.") {}
971 #define LLDB_OPTIONS_type_formatter_list
972 #include "CommandOptions.inc"
974 template <typename FormatterType>
975 class CommandObjectTypeFormatterList : public CommandObjectParsed {
976 typedef typename FormatterType::SharedPointer FormatterSharedPointer;
978 class CommandOptions : public Options {
979 public:
980 CommandOptions()
981 : Options(), m_category_regex("", ""),
982 m_category_language(lldb::eLanguageTypeUnknown,
983 lldb::eLanguageTypeUnknown) {}
985 ~CommandOptions() override = default;
987 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
988 ExecutionContext *execution_context) override {
989 Status error;
990 const int short_option = m_getopt_table[option_idx].val;
991 switch (short_option) {
992 case 'w':
993 m_category_regex.SetCurrentValue(option_arg);
994 m_category_regex.SetOptionWasSet();
995 break;
996 case 'l':
997 error = m_category_language.SetValueFromString(option_arg);
998 if (error.Success())
999 m_category_language.SetOptionWasSet();
1000 break;
1001 default:
1002 llvm_unreachable("Unimplemented option");
1005 return error;
1008 void OptionParsingStarting(ExecutionContext *execution_context) override {
1009 m_category_regex.Clear();
1010 m_category_language.Clear();
1013 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1014 return llvm::ArrayRef(g_type_formatter_list_options);
1017 // Instance variables to hold the values for command options.
1019 OptionValueString m_category_regex;
1020 OptionValueLanguage m_category_language;
1023 CommandOptions m_options;
1025 Options *GetOptions() override { return &m_options; }
1027 public:
1028 CommandObjectTypeFormatterList(CommandInterpreter &interpreter,
1029 const char *name, const char *help)
1030 : CommandObjectParsed(interpreter, name, help, nullptr), m_options() {
1031 AddSimpleArgumentList(eArgTypeName, eArgRepeatOptional);
1034 ~CommandObjectTypeFormatterList() override = default;
1036 protected:
1037 virtual bool FormatterSpecificList(CommandReturnObject &result) {
1038 return false;
1041 static bool ShouldListItem(llvm::StringRef s, RegularExpression *regex) {
1042 // If we have a regex, it can match two kinds of results:
1043 // - An item created with that same regex string (exact string match), so
1044 // the user can list it using the same string it used at creation time.
1045 // - Items that match the regex.
1046 // No regex means list everything.
1047 return regex == nullptr || s == regex->GetText() || regex->Execute(s);
1050 void DoExecute(Args &command, CommandReturnObject &result) override {
1051 const size_t argc = command.GetArgumentCount();
1053 std::unique_ptr<RegularExpression> category_regex;
1054 std::unique_ptr<RegularExpression> formatter_regex;
1056 if (m_options.m_category_regex.OptionWasSet()) {
1057 category_regex = std::make_unique<RegularExpression>(
1058 m_options.m_category_regex.GetCurrentValueAsRef());
1059 if (!category_regex->IsValid()) {
1060 result.AppendErrorWithFormat(
1061 "syntax error in category regular expression '%s'",
1062 m_options.m_category_regex.GetCurrentValueAsRef().str().c_str());
1063 return;
1067 if (argc == 1) {
1068 const char *arg = command.GetArgumentAtIndex(0);
1069 formatter_regex = std::make_unique<RegularExpression>(arg);
1070 if (!formatter_regex->IsValid()) {
1071 result.AppendErrorWithFormat("syntax error in regular expression '%s'",
1072 arg);
1073 return;
1077 bool any_printed = false;
1079 auto category_closure =
1080 [&result, &formatter_regex,
1081 &any_printed](const lldb::TypeCategoryImplSP &category) -> void {
1082 result.GetOutputStream().Printf(
1083 "-----------------------\nCategory: %s%s\n-----------------------\n",
1084 category->GetName(), category->IsEnabled() ? "" : " (disabled)");
1086 TypeCategoryImpl::ForEachCallback<FormatterType> print_formatter =
1087 [&result, &formatter_regex,
1088 &any_printed](const TypeMatcher &type_matcher,
1089 const FormatterSharedPointer &format_sp) -> bool {
1090 if (ShouldListItem(type_matcher.GetMatchString().GetStringRef(),
1091 formatter_regex.get())) {
1092 any_printed = true;
1093 result.GetOutputStream().Printf(
1094 "%s: %s\n", type_matcher.GetMatchString().GetCString(),
1095 format_sp->GetDescription().c_str());
1097 return true;
1099 category->ForEach(print_formatter);
1102 if (m_options.m_category_language.OptionWasSet()) {
1103 lldb::TypeCategoryImplSP category_sp;
1104 DataVisualization::Categories::GetCategory(
1105 m_options.m_category_language.GetCurrentValue(), category_sp);
1106 if (category_sp)
1107 category_closure(category_sp);
1108 } else {
1109 DataVisualization::Categories::ForEach(
1110 [&category_regex, &category_closure](
1111 const lldb::TypeCategoryImplSP &category) -> bool {
1112 if (ShouldListItem(category->GetName(), category_regex.get())) {
1113 category_closure(category);
1115 return true;
1118 any_printed = FormatterSpecificList(result) | any_printed;
1121 if (any_printed)
1122 result.SetStatus(eReturnStatusSuccessFinishResult);
1123 else {
1124 result.GetOutputStream().PutCString("no matching results found.\n");
1125 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1130 // CommandObjectTypeFormatList
1132 class CommandObjectTypeFormatList
1133 : public CommandObjectTypeFormatterList<TypeFormatImpl> {
1134 public:
1135 CommandObjectTypeFormatList(CommandInterpreter &interpreter)
1136 : CommandObjectTypeFormatterList(interpreter, "type format list",
1137 "Show a list of current formats.") {}
1140 Status CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue(
1141 uint32_t option_idx, llvm::StringRef option_arg,
1142 ExecutionContext *execution_context) {
1143 Status error;
1144 const int short_option = m_getopt_table[option_idx].val;
1145 bool success;
1147 switch (short_option) {
1148 case 'C':
1149 m_flags.SetCascades(OptionArgParser::ToBoolean(option_arg, true, &success));
1150 if (!success)
1151 error = Status::FromErrorStringWithFormat("invalid value for cascade: %s",
1152 option_arg.str().c_str());
1153 break;
1154 case 'e':
1155 m_flags.SetDontShowChildren(false);
1156 break;
1157 case 'h':
1158 m_flags.SetHideEmptyAggregates(true);
1159 break;
1160 case 'v':
1161 m_flags.SetDontShowValue(true);
1162 break;
1163 case 'c':
1164 m_flags.SetShowMembersOneLiner(true);
1165 break;
1166 case 's':
1167 m_format_string = std::string(option_arg);
1168 break;
1169 case 'p':
1170 m_flags.SetSkipPointers(true);
1171 break;
1172 case 'r':
1173 m_flags.SetSkipReferences(true);
1174 break;
1175 case 'x':
1176 if (m_match_type == eFormatterMatchCallback)
1177 error = Status::FromErrorString(
1178 "can't use --regex and --recognizer-function at the same time");
1179 else
1180 m_match_type = eFormatterMatchRegex;
1181 break;
1182 case '\x01':
1183 if (m_match_type == eFormatterMatchRegex)
1184 error = Status::FromErrorString(
1185 "can't use --regex and --recognizer-function at the same time");
1186 else
1187 m_match_type = eFormatterMatchCallback;
1188 break;
1189 case 'n':
1190 m_name.SetString(option_arg);
1191 break;
1192 case 'o':
1193 m_python_script = std::string(option_arg);
1194 m_is_add_script = true;
1195 break;
1196 case 'F':
1197 m_python_function = std::string(option_arg);
1198 m_is_add_script = true;
1199 break;
1200 case 'P':
1201 m_is_add_script = true;
1202 break;
1203 case 'w':
1204 m_category = std::string(option_arg);
1205 break;
1206 case 'O':
1207 m_flags.SetHideItemNames(true);
1208 break;
1209 default:
1210 llvm_unreachable("Unimplemented option");
1213 return error;
1216 void CommandObjectTypeSummaryAdd::CommandOptions::OptionParsingStarting(
1217 ExecutionContext *execution_context) {
1218 m_flags.Clear().SetCascades().SetDontShowChildren().SetDontShowValue(false);
1219 m_flags.SetShowMembersOneLiner(false)
1220 .SetSkipPointers(false)
1221 .SetSkipReferences(false)
1222 .SetHideItemNames(false);
1224 m_match_type = eFormatterMatchExact;
1225 m_name.Clear();
1226 m_python_script = "";
1227 m_python_function = "";
1228 m_format_string = "";
1229 m_is_add_script = false;
1230 m_category = "default";
1233 #if LLDB_ENABLE_PYTHON
1235 bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary(
1236 Args &command, CommandReturnObject &result) {
1237 const size_t argc = command.GetArgumentCount();
1239 if (argc < 1 && !m_options.m_name) {
1240 result.AppendErrorWithFormat("%s takes one or more args.\n",
1241 m_cmd_name.c_str());
1242 return false;
1245 TypeSummaryImplSP script_format;
1247 if (!m_options.m_python_function
1248 .empty()) // we have a Python function ready to use
1250 const char *funct_name = m_options.m_python_function.c_str();
1251 if (!funct_name || !funct_name[0]) {
1252 result.AppendError("function name empty.\n");
1253 return false;
1256 std::string code =
1257 (" " + m_options.m_python_function + "(valobj,internal_dict)");
1259 script_format = std::make_shared<ScriptSummaryFormat>(
1260 m_options.m_flags, funct_name, code.c_str());
1262 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1264 if (interpreter && !interpreter->CheckObjectExists(funct_name))
1265 result.AppendWarningWithFormat(
1266 "The provided function \"%s\" does not exist - "
1267 "please define it before attempting to use this summary.\n",
1268 funct_name);
1269 } else if (!m_options.m_python_script
1270 .empty()) // we have a quick 1-line script, just use it
1272 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1273 if (!interpreter) {
1274 result.AppendError("script interpreter missing - unable to generate "
1275 "function wrapper.\n");
1276 return false;
1278 StringList funct_sl;
1279 funct_sl << m_options.m_python_script.c_str();
1280 std::string funct_name_str;
1281 if (!interpreter->GenerateTypeScriptFunction(funct_sl, funct_name_str)) {
1282 result.AppendError("unable to generate function wrapper.\n");
1283 return false;
1285 if (funct_name_str.empty()) {
1286 result.AppendError(
1287 "script interpreter failed to generate a valid function name.\n");
1288 return false;
1291 std::string code = " " + m_options.m_python_script;
1293 script_format = std::make_shared<ScriptSummaryFormat>(
1294 m_options.m_flags, funct_name_str.c_str(), code.c_str());
1295 } else {
1296 // Use an IOHandler to grab Python code from the user
1297 auto options = std::make_unique<ScriptAddOptions>(
1298 m_options.m_flags, m_options.m_match_type, m_options.m_name,
1299 m_options.m_category);
1301 for (auto &entry : command.entries()) {
1302 if (entry.ref().empty()) {
1303 result.AppendError("empty typenames not allowed");
1304 return false;
1307 options->m_target_types << std::string(entry.ref());
1310 m_interpreter.GetPythonCommandsFromIOHandler(
1311 " ", // Prompt
1312 *this, // IOHandlerDelegate
1313 options.release()); // Baton for the "io_handler" that will be passed
1314 // back into our IOHandlerDelegate functions
1315 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1317 return result.Succeeded();
1320 // if I am here, script_format must point to something good, so I can add
1321 // that as a script summary to all interested parties
1323 Status error;
1325 for (auto &entry : command.entries()) {
1326 AddSummary(ConstString(entry.ref()), script_format, m_options.m_match_type,
1327 m_options.m_category, &error);
1328 if (error.Fail()) {
1329 result.AppendError(error.AsCString());
1330 return false;
1334 if (m_options.m_name) {
1335 AddNamedSummary(m_options.m_name, script_format, &error);
1336 if (error.Fail()) {
1337 result.AppendError(error.AsCString());
1338 result.AppendError("added to types, but not given a name");
1339 return false;
1343 return result.Succeeded();
1346 #endif
1348 bool CommandObjectTypeSummaryAdd::Execute_StringSummary(
1349 Args &command, CommandReturnObject &result) {
1350 const size_t argc = command.GetArgumentCount();
1352 if (argc < 1 && !m_options.m_name) {
1353 result.AppendErrorWithFormat("%s takes one or more args.\n",
1354 m_cmd_name.c_str());
1355 return false;
1358 if (!m_options.m_flags.GetShowMembersOneLiner() &&
1359 m_options.m_format_string.empty()) {
1360 result.AppendError("empty summary strings not allowed");
1361 return false;
1364 const char *format_cstr = (m_options.m_flags.GetShowMembersOneLiner()
1365 ? ""
1366 : m_options.m_format_string.c_str());
1368 // ${var%S} is an endless recursion, prevent it
1369 if (strcmp(format_cstr, "${var%S}") == 0) {
1370 result.AppendError("recursive summary not allowed");
1371 return false;
1374 std::unique_ptr<StringSummaryFormat> string_format(
1375 new StringSummaryFormat(m_options.m_flags, format_cstr));
1376 if (!string_format) {
1377 result.AppendError("summary creation failed");
1378 return false;
1380 if (string_format->m_error.Fail()) {
1381 result.AppendErrorWithFormat("syntax error: %s",
1382 string_format->m_error.AsCString("<unknown>"));
1383 return false;
1385 lldb::TypeSummaryImplSP entry(string_format.release());
1387 // now I have a valid format, let's add it to every type
1388 Status error;
1389 for (auto &arg_entry : command.entries()) {
1390 if (arg_entry.ref().empty()) {
1391 result.AppendError("empty typenames not allowed");
1392 return false;
1394 ConstString typeCS(arg_entry.ref());
1396 AddSummary(typeCS, entry, m_options.m_match_type, m_options.m_category,
1397 &error);
1399 if (error.Fail()) {
1400 result.AppendError(error.AsCString());
1401 return false;
1405 if (m_options.m_name) {
1406 AddNamedSummary(m_options.m_name, entry, &error);
1407 if (error.Fail()) {
1408 result.AppendError(error.AsCString());
1409 result.AppendError("added to types, but not given a name");
1410 return false;
1414 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1415 return result.Succeeded();
1418 CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd(
1419 CommandInterpreter &interpreter)
1420 : CommandObjectParsed(interpreter, "type summary add",
1421 "Add a new summary style for a type.", nullptr),
1422 IOHandlerDelegateMultiline("DONE"), m_options(interpreter) {
1423 AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus);
1425 SetHelpLong(
1427 The following examples of 'type summary add' refer to this code snippet for context:
1429 struct JustADemo
1431 int* ptr;
1432 float value;
1433 JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {}
1435 JustADemo demo_instance(42, 3.14);
1437 typedef JustADemo NewDemo;
1438 NewDemo new_demo_instance(42, 3.14);
1440 (lldb) type summary add --summary-string "the answer is ${*var.ptr}" JustADemo
1442 Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42"
1444 (lldb) type summary add --summary-string "the answer is ${*var.ptr}, and the question is ${var.value}" JustADemo
1446 Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42 and the question is 3.14"
1449 "Alternatively, you could define formatting for all pointers to integers and \
1450 rely on that when formatting JustADemo to obtain the same result:"
1453 (lldb) type summary add --summary-string "${var%V} -> ${*var}" "int *"
1454 (lldb) type summary add --summary-string "the answer is ${var.ptr}, and the question is ${var.value}" JustADemo
1457 "Type summaries are automatically applied to derived typedefs, so the examples \
1458 above apply to both JustADemo and NewDemo. The cascade option can be used to \
1459 suppress this behavior:"
1462 (lldb) type summary add --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo -C no
1464 The summary will now be used for values of JustADemo but not NewDemo.
1467 "By default summaries are shown for pointers and references to values of the \
1468 specified type. To suppress formatting for pointers use the -p option, or apply \
1469 the corresponding -r option to suppress formatting for references:"
1472 (lldb) type summary add -p -r --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo
1475 "One-line summaries including all fields in a type can be inferred without supplying an \
1476 explicit summary string by passing the -c option:"
1479 (lldb) type summary add -c JustADemo
1480 (lldb) frame variable demo_instance
1481 (ptr=<address>, value=3.14)
1484 "Type summaries normally suppress the nested display of individual fields. To \
1485 supply a summary to supplement the default structure add the -e option:"
1488 (lldb) type summary add -e --summary-string "*ptr = ${*var.ptr}" JustADemo
1491 "Now when displaying JustADemo values the int* is displayed, followed by the \
1492 standard LLDB sequence of children, one per line:"
1495 *ptr = 42 {
1496 ptr = <address>
1497 value = 3.14
1501 "You can also add summaries written in Python. These scripts use lldb public API to \
1502 gather information from your variables and produce a meaningful summary. To start a \
1503 multi-line script use the -P option. The function declaration will be displayed along with \
1504 a comment describing the two arguments. End your script with the word 'DONE' on a line by \
1505 itself:"
1508 (lldb) type summary add JustADemo -P
1509 def function (valobj,internal_dict):
1510 """valobj: an SBValue which you want to provide a summary for
1511 internal_dict: an LLDB support object not to be used"""
1512 value = valobj.GetChildMemberWithName('value');
1513 return 'My value is ' + value.GetValue();
1514 DONE
1516 Alternatively, the -o option can be used when providing a simple one-line Python script:
1518 (lldb) type summary add JustADemo -o "value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();")");
1521 void CommandObjectTypeSummaryAdd::DoExecute(Args &command,
1522 CommandReturnObject &result) {
1523 WarnOnPotentialUnquotedUnsignedType(command, result);
1525 if (m_options.m_is_add_script) {
1526 #if LLDB_ENABLE_PYTHON
1527 Execute_ScriptSummary(command, result);
1528 #else
1529 result.AppendError("python is disabled");
1530 #endif
1531 return;
1534 Execute_StringSummary(command, result);
1537 static bool FixArrayTypeNameWithRegex(ConstString &type_name) {
1538 llvm::StringRef type_name_ref(type_name.GetStringRef());
1540 if (type_name_ref.ends_with("[]")) {
1541 std::string type_name_str(type_name.GetCString());
1542 type_name_str.resize(type_name_str.length() - 2);
1543 if (type_name_str.back() != ' ')
1544 type_name_str.append(" ?\\[[0-9]+\\]");
1545 else
1546 type_name_str.append("\\[[0-9]+\\]");
1547 type_name.SetCString(type_name_str.c_str());
1548 return true;
1550 return false;
1553 bool CommandObjectTypeSummaryAdd::AddNamedSummary(ConstString summary_name,
1554 TypeSummaryImplSP entry,
1555 Status *error) {
1556 // system named summaries do not exist (yet?)
1557 DataVisualization::NamedSummaryFormats::Add(summary_name, entry);
1558 return true;
1561 bool CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name,
1562 TypeSummaryImplSP entry,
1563 FormatterMatchType match_type,
1564 std::string category_name,
1565 Status *error) {
1566 lldb::TypeCategoryImplSP category;
1567 DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()),
1568 category);
1570 if (match_type == eFormatterMatchExact) {
1571 if (FixArrayTypeNameWithRegex(type_name))
1572 match_type = eFormatterMatchRegex;
1575 if (match_type == eFormatterMatchRegex) {
1576 match_type = eFormatterMatchRegex;
1577 RegularExpression typeRX(type_name.GetStringRef());
1578 if (!typeRX.IsValid()) {
1579 if (error)
1580 *error = Status::FromErrorString(
1581 "regex format error (maybe this is not really a regex?)");
1582 return false;
1586 if (match_type == eFormatterMatchCallback) {
1587 const char *function_name = type_name.AsCString();
1588 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1589 if (interpreter && !interpreter->CheckObjectExists(function_name)) {
1590 *error = Status::FromErrorStringWithFormat(
1591 "The provided recognizer function \"%s\" does not exist - "
1592 "please define it before attempting to use this summary.\n",
1593 function_name);
1594 return false;
1597 category->AddTypeSummary(type_name.GetStringRef(), match_type, entry);
1598 return true;
1601 // CommandObjectTypeSummaryDelete
1603 class CommandObjectTypeSummaryDelete : public CommandObjectTypeFormatterDelete {
1604 public:
1605 CommandObjectTypeSummaryDelete(CommandInterpreter &interpreter)
1606 : CommandObjectTypeFormatterDelete(
1607 interpreter, eFormatCategoryItemSummary) {}
1609 ~CommandObjectTypeSummaryDelete() override = default;
1611 protected:
1612 bool FormatterSpecificDeletion(ConstString typeCS) override {
1613 if (m_options.m_language != lldb::eLanguageTypeUnknown)
1614 return false;
1615 return DataVisualization::NamedSummaryFormats::Delete(typeCS);
1619 class CommandObjectTypeSummaryClear : public CommandObjectTypeFormatterClear {
1620 public:
1621 CommandObjectTypeSummaryClear(CommandInterpreter &interpreter)
1622 : CommandObjectTypeFormatterClear(interpreter, eFormatCategoryItemSummary,
1623 "type summary clear",
1624 "Delete all existing summaries.") {}
1626 protected:
1627 void FormatterSpecificDeletion() override {
1628 DataVisualization::NamedSummaryFormats::Clear();
1632 // CommandObjectTypeSummaryList
1634 class CommandObjectTypeSummaryList
1635 : public CommandObjectTypeFormatterList<TypeSummaryImpl> {
1636 public:
1637 CommandObjectTypeSummaryList(CommandInterpreter &interpreter)
1638 : CommandObjectTypeFormatterList(interpreter, "type summary list",
1639 "Show a list of current summaries.") {}
1641 protected:
1642 bool FormatterSpecificList(CommandReturnObject &result) override {
1643 if (DataVisualization::NamedSummaryFormats::GetCount() > 0) {
1644 result.GetOutputStream().Printf("Named summaries:\n");
1645 DataVisualization::NamedSummaryFormats::ForEach(
1646 [&result](const TypeMatcher &type_matcher,
1647 const TypeSummaryImplSP &summary_sp) -> bool {
1648 result.GetOutputStream().Printf(
1649 "%s: %s\n", type_matcher.GetMatchString().GetCString(),
1650 summary_sp->GetDescription().c_str());
1651 return true;
1653 return true;
1655 return false;
1659 // CommandObjectTypeCategoryDefine
1660 #define LLDB_OPTIONS_type_category_define
1661 #include "CommandOptions.inc"
1663 class CommandObjectTypeCategoryDefine : public CommandObjectParsed {
1664 class CommandOptions : public Options {
1665 public:
1666 CommandOptions()
1667 : m_define_enabled(false, false),
1668 m_cate_language(eLanguageTypeUnknown, eLanguageTypeUnknown) {}
1670 ~CommandOptions() override = default;
1672 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1673 ExecutionContext *execution_context) override {
1674 Status error;
1675 const int short_option = m_getopt_table[option_idx].val;
1677 switch (short_option) {
1678 case 'e':
1679 m_define_enabled.SetValueFromString(llvm::StringRef("true"));
1680 break;
1681 case 'l':
1682 error = m_cate_language.SetValueFromString(option_arg);
1683 break;
1684 default:
1685 llvm_unreachable("Unimplemented option");
1688 return error;
1691 void OptionParsingStarting(ExecutionContext *execution_context) override {
1692 m_define_enabled.Clear();
1693 m_cate_language.Clear();
1696 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1697 return llvm::ArrayRef(g_type_category_define_options);
1700 // Instance variables to hold the values for command options.
1702 OptionValueBoolean m_define_enabled;
1703 OptionValueLanguage m_cate_language;
1706 CommandOptions m_options;
1708 Options *GetOptions() override { return &m_options; }
1710 public:
1711 CommandObjectTypeCategoryDefine(CommandInterpreter &interpreter)
1712 : CommandObjectParsed(interpreter, "type category define",
1713 "Define a new category as a source of formatters.",
1714 nullptr) {
1715 AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus);
1718 ~CommandObjectTypeCategoryDefine() override = default;
1720 protected:
1721 void DoExecute(Args &command, CommandReturnObject &result) override {
1722 const size_t argc = command.GetArgumentCount();
1724 if (argc < 1) {
1725 result.AppendErrorWithFormat("%s takes 1 or more args.\n",
1726 m_cmd_name.c_str());
1727 return;
1730 for (auto &entry : command.entries()) {
1731 TypeCategoryImplSP category_sp;
1732 if (DataVisualization::Categories::GetCategory(ConstString(entry.ref()),
1733 category_sp) &&
1734 category_sp) {
1735 category_sp->AddLanguage(m_options.m_cate_language.GetCurrentValue());
1736 if (m_options.m_define_enabled.GetCurrentValue())
1737 DataVisualization::Categories::Enable(category_sp,
1738 TypeCategoryMap::Default);
1742 result.SetStatus(eReturnStatusSuccessFinishResult);
1746 // CommandObjectTypeCategoryEnable
1747 #define LLDB_OPTIONS_type_category_enable
1748 #include "CommandOptions.inc"
1750 class CommandObjectTypeCategoryEnable : public CommandObjectParsed {
1751 class CommandOptions : public Options {
1752 public:
1753 CommandOptions() = default;
1755 ~CommandOptions() override = default;
1757 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1758 ExecutionContext *execution_context) override {
1759 Status error;
1760 const int short_option = m_getopt_table[option_idx].val;
1762 switch (short_option) {
1763 case 'l':
1764 if (!option_arg.empty()) {
1765 m_language = Language::GetLanguageTypeFromString(option_arg);
1766 if (m_language == lldb::eLanguageTypeUnknown)
1767 error = Status::FromErrorStringWithFormat(
1768 "unrecognized language '%s'", option_arg.str().c_str());
1770 break;
1771 default:
1772 llvm_unreachable("Unimplemented option");
1775 return error;
1778 void OptionParsingStarting(ExecutionContext *execution_context) override {
1779 m_language = lldb::eLanguageTypeUnknown;
1782 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1783 return llvm::ArrayRef(g_type_category_enable_options);
1786 // Instance variables to hold the values for command options.
1788 lldb::LanguageType m_language;
1791 CommandOptions m_options;
1793 Options *GetOptions() override { return &m_options; }
1795 public:
1796 CommandObjectTypeCategoryEnable(CommandInterpreter &interpreter)
1797 : CommandObjectParsed(interpreter, "type category enable",
1798 "Enable a category as a source of formatters.",
1799 nullptr) {
1800 AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus);
1803 ~CommandObjectTypeCategoryEnable() override = default;
1805 protected:
1806 void DoExecute(Args &command, CommandReturnObject &result) override {
1807 const size_t argc = command.GetArgumentCount();
1809 if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) {
1810 result.AppendErrorWithFormat("%s takes arguments and/or a language",
1811 m_cmd_name.c_str());
1812 return;
1815 if (argc == 1 && strcmp(command.GetArgumentAtIndex(0), "*") == 0) {
1816 DataVisualization::Categories::EnableStar();
1817 } else if (argc > 0) {
1818 for (int i = argc - 1; i >= 0; i--) {
1819 const char *typeA = command.GetArgumentAtIndex(i);
1820 ConstString typeCS(typeA);
1822 if (!typeCS) {
1823 result.AppendError("empty category name not allowed");
1824 return;
1826 DataVisualization::Categories::Enable(typeCS);
1827 lldb::TypeCategoryImplSP cate;
1828 if (DataVisualization::Categories::GetCategory(typeCS, cate) && cate) {
1829 if (cate->GetCount() == 0) {
1830 result.AppendWarning("empty category enabled (typo?)");
1836 if (m_options.m_language != lldb::eLanguageTypeUnknown)
1837 DataVisualization::Categories::Enable(m_options.m_language);
1839 result.SetStatus(eReturnStatusSuccessFinishResult);
1843 // CommandObjectTypeCategoryDelete
1845 class CommandObjectTypeCategoryDelete : public CommandObjectParsed {
1846 public:
1847 CommandObjectTypeCategoryDelete(CommandInterpreter &interpreter)
1848 : CommandObjectParsed(interpreter, "type category delete",
1849 "Delete a category and all associated formatters.",
1850 nullptr) {
1851 AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus);
1854 ~CommandObjectTypeCategoryDelete() override = default;
1856 protected:
1857 void DoExecute(Args &command, CommandReturnObject &result) override {
1858 const size_t argc = command.GetArgumentCount();
1860 if (argc < 1) {
1861 result.AppendErrorWithFormat("%s takes 1 or more arg.\n",
1862 m_cmd_name.c_str());
1863 return;
1866 bool success = true;
1868 // the order is not relevant here
1869 for (int i = argc - 1; i >= 0; i--) {
1870 const char *typeA = command.GetArgumentAtIndex(i);
1871 ConstString typeCS(typeA);
1873 if (!typeCS) {
1874 result.AppendError("empty category name not allowed");
1875 return;
1877 if (!DataVisualization::Categories::Delete(typeCS))
1878 success = false; // keep deleting even if we hit an error
1880 if (success) {
1881 result.SetStatus(eReturnStatusSuccessFinishResult);
1882 } else {
1883 result.AppendError("cannot delete one or more categories\n");
1888 // CommandObjectTypeCategoryDisable
1889 #define LLDB_OPTIONS_type_category_disable
1890 #include "CommandOptions.inc"
1892 class CommandObjectTypeCategoryDisable : public CommandObjectParsed {
1893 class CommandOptions : public Options {
1894 public:
1895 CommandOptions() = default;
1897 ~CommandOptions() override = default;
1899 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1900 ExecutionContext *execution_context) override {
1901 Status error;
1902 const int short_option = m_getopt_table[option_idx].val;
1904 switch (short_option) {
1905 case 'l':
1906 if (!option_arg.empty()) {
1907 m_language = Language::GetLanguageTypeFromString(option_arg);
1908 if (m_language == lldb::eLanguageTypeUnknown)
1909 error = Status::FromErrorStringWithFormat(
1910 "unrecognized language '%s'", option_arg.str().c_str());
1912 break;
1913 default:
1914 llvm_unreachable("Unimplemented option");
1917 return error;
1920 void OptionParsingStarting(ExecutionContext *execution_context) override {
1921 m_language = lldb::eLanguageTypeUnknown;
1924 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1925 return llvm::ArrayRef(g_type_category_disable_options);
1928 // Instance variables to hold the values for command options.
1930 lldb::LanguageType m_language;
1933 CommandOptions m_options;
1935 Options *GetOptions() override { return &m_options; }
1937 public:
1938 CommandObjectTypeCategoryDisable(CommandInterpreter &interpreter)
1939 : CommandObjectParsed(interpreter, "type category disable",
1940 "Disable a category as a source of formatters.",
1941 nullptr) {
1942 AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus);
1945 ~CommandObjectTypeCategoryDisable() override = default;
1947 protected:
1948 void DoExecute(Args &command, CommandReturnObject &result) override {
1949 const size_t argc = command.GetArgumentCount();
1951 if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) {
1952 result.AppendErrorWithFormat("%s takes arguments and/or a language",
1953 m_cmd_name.c_str());
1954 return;
1957 if (argc == 1 && strcmp(command.GetArgumentAtIndex(0), "*") == 0) {
1958 DataVisualization::Categories::DisableStar();
1959 } else if (argc > 0) {
1960 // the order is not relevant here
1961 for (int i = argc - 1; i >= 0; i--) {
1962 const char *typeA = command.GetArgumentAtIndex(i);
1963 ConstString typeCS(typeA);
1965 if (!typeCS) {
1966 result.AppendError("empty category name not allowed");
1967 return;
1969 DataVisualization::Categories::Disable(typeCS);
1973 if (m_options.m_language != lldb::eLanguageTypeUnknown)
1974 DataVisualization::Categories::Disable(m_options.m_language);
1976 result.SetStatus(eReturnStatusSuccessFinishResult);
1980 // CommandObjectTypeCategoryList
1982 class CommandObjectTypeCategoryList : public CommandObjectParsed {
1983 public:
1984 CommandObjectTypeCategoryList(CommandInterpreter &interpreter)
1985 : CommandObjectParsed(interpreter, "type category list",
1986 "Provide a list of all existing categories.",
1987 nullptr) {
1988 AddSimpleArgumentList(eArgTypeName, eArgRepeatOptional);
1991 ~CommandObjectTypeCategoryList() override = default;
1993 void
1994 HandleArgumentCompletion(CompletionRequest &request,
1995 OptionElementVector &opt_element_vector) override {
1996 if (request.GetCursorIndex())
1997 return;
1998 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1999 GetCommandInterpreter(), lldb::eTypeCategoryNameCompletion, request,
2000 nullptr);
2003 protected:
2004 void DoExecute(Args &command, CommandReturnObject &result) override {
2005 const size_t argc = command.GetArgumentCount();
2007 std::unique_ptr<RegularExpression> regex;
2009 if (argc == 1) {
2010 const char *arg = command.GetArgumentAtIndex(0);
2011 regex = std::make_unique<RegularExpression>(arg);
2012 if (!regex->IsValid()) {
2013 result.AppendErrorWithFormat(
2014 "syntax error in category regular expression '%s'", arg);
2015 return;
2017 } else if (argc != 0) {
2018 result.AppendErrorWithFormat("%s takes 0 or one arg.\n",
2019 m_cmd_name.c_str());
2020 return;
2023 DataVisualization::Categories::ForEach(
2024 [&regex, &result](const lldb::TypeCategoryImplSP &category_sp) -> bool {
2025 if (regex) {
2026 bool escape = true;
2027 if (regex->GetText() == category_sp->GetName()) {
2028 escape = false;
2029 } else if (regex->Execute(category_sp->GetName())) {
2030 escape = false;
2033 if (escape)
2034 return true;
2037 result.GetOutputStream().Printf(
2038 "Category: %s\n", category_sp->GetDescription().c_str());
2040 return true;
2043 result.SetStatus(eReturnStatusSuccessFinishResult);
2047 // CommandObjectTypeFilterList
2049 class CommandObjectTypeFilterList
2050 : public CommandObjectTypeFormatterList<TypeFilterImpl> {
2051 public:
2052 CommandObjectTypeFilterList(CommandInterpreter &interpreter)
2053 : CommandObjectTypeFormatterList(interpreter, "type filter list",
2054 "Show a list of current filters.") {}
2057 // CommandObjectTypeSynthList
2059 class CommandObjectTypeSynthList
2060 : public CommandObjectTypeFormatterList<SyntheticChildren> {
2061 public:
2062 CommandObjectTypeSynthList(CommandInterpreter &interpreter)
2063 : CommandObjectTypeFormatterList(
2064 interpreter, "type synthetic list",
2065 "Show a list of current synthetic providers.") {}
2068 // CommandObjectTypeFilterDelete
2070 class CommandObjectTypeFilterDelete : public CommandObjectTypeFormatterDelete {
2071 public:
2072 CommandObjectTypeFilterDelete(CommandInterpreter &interpreter)
2073 : CommandObjectTypeFormatterDelete(
2074 interpreter, eFormatCategoryItemFilter) {}
2076 ~CommandObjectTypeFilterDelete() override = default;
2079 // CommandObjectTypeSynthDelete
2081 class CommandObjectTypeSynthDelete : public CommandObjectTypeFormatterDelete {
2082 public:
2083 CommandObjectTypeSynthDelete(CommandInterpreter &interpreter)
2084 : CommandObjectTypeFormatterDelete(
2085 interpreter, eFormatCategoryItemSynth) {}
2087 ~CommandObjectTypeSynthDelete() override = default;
2091 // CommandObjectTypeFilterClear
2093 class CommandObjectTypeFilterClear : public CommandObjectTypeFormatterClear {
2094 public:
2095 CommandObjectTypeFilterClear(CommandInterpreter &interpreter)
2096 : CommandObjectTypeFormatterClear(interpreter, eFormatCategoryItemFilter,
2097 "type filter clear",
2098 "Delete all existing filter.") {}
2101 // CommandObjectTypeSynthClear
2103 class CommandObjectTypeSynthClear : public CommandObjectTypeFormatterClear {
2104 public:
2105 CommandObjectTypeSynthClear(CommandInterpreter &interpreter)
2106 : CommandObjectTypeFormatterClear(
2107 interpreter, eFormatCategoryItemSynth, "type synthetic clear",
2108 "Delete all existing synthetic providers.") {}
2111 bool CommandObjectTypeSynthAdd::Execute_HandwritePython(
2112 Args &command, CommandReturnObject &result) {
2113 auto options = std::make_unique<SynthAddOptions>(
2114 m_options.m_skip_pointers, m_options.m_skip_references,
2115 m_options.m_cascade, m_options.m_match_type, m_options.m_category);
2117 for (auto &entry : command.entries()) {
2118 if (entry.ref().empty()) {
2119 result.AppendError("empty typenames not allowed");
2120 return false;
2123 options->m_target_types << std::string(entry.ref());
2126 m_interpreter.GetPythonCommandsFromIOHandler(
2127 " ", // Prompt
2128 *this, // IOHandlerDelegate
2129 options.release()); // Baton for the "io_handler" that will be passed back
2130 // into our IOHandlerDelegate functions
2131 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2132 return result.Succeeded();
2135 bool CommandObjectTypeSynthAdd::Execute_PythonClass(
2136 Args &command, CommandReturnObject &result) {
2137 const size_t argc = command.GetArgumentCount();
2139 if (argc < 1) {
2140 result.AppendErrorWithFormat("%s takes one or more args.\n",
2141 m_cmd_name.c_str());
2142 return false;
2145 if (m_options.m_class_name.empty() && !m_options.m_input_python) {
2146 result.AppendErrorWithFormat("%s needs either a Python class name or -P to "
2147 "directly input Python code.\n",
2148 m_cmd_name.c_str());
2149 return false;
2152 SyntheticChildrenSP entry;
2154 ScriptedSyntheticChildren *impl = new ScriptedSyntheticChildren(
2155 SyntheticChildren::Flags()
2156 .SetCascades(m_options.m_cascade)
2157 .SetSkipPointers(m_options.m_skip_pointers)
2158 .SetSkipReferences(m_options.m_skip_references),
2159 m_options.m_class_name.c_str());
2161 entry.reset(impl);
2163 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
2165 if (interpreter &&
2166 !interpreter->CheckObjectExists(impl->GetPythonClassName()))
2167 result.AppendWarning("The provided class does not exist - please define it "
2168 "before attempting to use this synthetic provider");
2170 // now I have a valid provider, let's add it to every type
2172 lldb::TypeCategoryImplSP category;
2173 DataVisualization::Categories::GetCategory(
2174 ConstString(m_options.m_category.c_str()), category);
2176 Status error;
2178 for (auto &arg_entry : command.entries()) {
2179 if (arg_entry.ref().empty()) {
2180 result.AppendError("empty typenames not allowed");
2181 return false;
2184 ConstString typeCS(arg_entry.ref());
2185 if (!AddSynth(typeCS, entry, m_options.m_match_type, m_options.m_category,
2186 &error)) {
2187 result.AppendError(error.AsCString());
2188 return false;
2192 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2193 return result.Succeeded();
2196 CommandObjectTypeSynthAdd::CommandObjectTypeSynthAdd(
2197 CommandInterpreter &interpreter)
2198 : CommandObjectParsed(interpreter, "type synthetic add",
2199 "Add a new synthetic provider for a type.", nullptr),
2200 IOHandlerDelegateMultiline("DONE"), m_options() {
2201 AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus);
2204 bool CommandObjectTypeSynthAdd::AddSynth(ConstString type_name,
2205 SyntheticChildrenSP entry,
2206 FormatterMatchType match_type,
2207 std::string category_name,
2208 Status *error) {
2209 lldb::TypeCategoryImplSP category;
2210 DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()),
2211 category);
2213 if (match_type == eFormatterMatchExact) {
2214 if (FixArrayTypeNameWithRegex(type_name))
2215 match_type = eFormatterMatchRegex;
2218 // Only check for conflicting filters in the same category if `type_name` is
2219 // an actual type name. Matching a regex string against registered regexes
2220 // doesn't work.
2221 if (match_type == eFormatterMatchExact) {
2222 // It's not generally possible to get a type object here. For example, this
2223 // command can be run before loading any binaries. Do just a best-effort
2224 // name-based lookup here to try to prevent conflicts.
2225 FormattersMatchCandidate candidate_type(type_name, nullptr, TypeImpl(),
2226 FormattersMatchCandidate::Flags());
2227 if (category->AnyMatches(candidate_type, eFormatCategoryItemFilter,
2228 false)) {
2229 if (error)
2230 *error = Status::FromErrorStringWithFormat(
2231 "cannot add synthetic for type %s when "
2232 "filter is defined in same category!",
2233 type_name.AsCString());
2234 return false;
2238 if (match_type == eFormatterMatchRegex) {
2239 RegularExpression typeRX(type_name.GetStringRef());
2240 if (!typeRX.IsValid()) {
2241 if (error)
2242 *error = Status::FromErrorString(
2243 "regex format error (maybe this is not really a regex?)");
2244 return false;
2248 if (match_type == eFormatterMatchCallback) {
2249 const char *function_name = type_name.AsCString();
2250 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
2251 if (interpreter && !interpreter->CheckObjectExists(function_name)) {
2252 *error = Status::FromErrorStringWithFormat(
2253 "The provided recognizer function \"%s\" does not exist - "
2254 "please define it before attempting to use this summary.\n",
2255 function_name);
2256 return false;
2260 category->AddTypeSynthetic(type_name.GetStringRef(), match_type, entry);
2261 return true;
2264 #define LLDB_OPTIONS_type_filter_add
2265 #include "CommandOptions.inc"
2267 class CommandObjectTypeFilterAdd : public CommandObjectParsed {
2268 private:
2269 class CommandOptions : public Options {
2270 typedef std::vector<std::string> option_vector;
2272 public:
2273 CommandOptions() = default;
2275 ~CommandOptions() override = default;
2277 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2278 ExecutionContext *execution_context) override {
2279 Status error;
2280 const int short_option = m_getopt_table[option_idx].val;
2281 bool success;
2283 switch (short_option) {
2284 case 'C':
2285 m_cascade = OptionArgParser::ToBoolean(option_arg, true, &success);
2286 if (!success)
2287 error = Status::FromErrorStringWithFormat(
2288 "invalid value for cascade: %s", option_arg.str().c_str());
2289 break;
2290 case 'c':
2291 m_expr_paths.push_back(std::string(option_arg));
2292 has_child_list = true;
2293 break;
2294 case 'p':
2295 m_skip_pointers = true;
2296 break;
2297 case 'r':
2298 m_skip_references = true;
2299 break;
2300 case 'w':
2301 m_category = std::string(option_arg);
2302 break;
2303 case 'x':
2304 m_regex = true;
2305 break;
2306 default:
2307 llvm_unreachable("Unimplemented option");
2310 return error;
2313 void OptionParsingStarting(ExecutionContext *execution_context) override {
2314 m_cascade = true;
2315 m_skip_pointers = false;
2316 m_skip_references = false;
2317 m_category = "default";
2318 m_expr_paths.clear();
2319 has_child_list = false;
2320 m_regex = false;
2323 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2324 return llvm::ArrayRef(g_type_filter_add_options);
2327 // Instance variables to hold the values for command options.
2329 bool m_cascade;
2330 bool m_skip_references;
2331 bool m_skip_pointers;
2332 bool m_input_python;
2333 option_vector m_expr_paths;
2334 std::string m_category;
2335 bool has_child_list;
2336 bool m_regex;
2338 typedef option_vector::iterator ExpressionPathsIterator;
2341 CommandOptions m_options;
2343 Options *GetOptions() override { return &m_options; }
2345 enum FilterFormatType { eRegularFilter, eRegexFilter };
2347 bool AddFilter(ConstString type_name, TypeFilterImplSP entry,
2348 FilterFormatType type, std::string category_name,
2349 Status *error) {
2350 lldb::TypeCategoryImplSP category;
2351 DataVisualization::Categories::GetCategory(
2352 ConstString(category_name.c_str()), category);
2354 if (type == eRegularFilter) {
2355 if (FixArrayTypeNameWithRegex(type_name))
2356 type = eRegexFilter;
2359 // Only check for conflicting synthetic child providers in the same category
2360 // if `type_name` is an actual type name. Matching a regex string against
2361 // registered regexes doesn't work.
2362 if (type == eRegularFilter) {
2363 // It's not generally possible to get a type object here. For example,
2364 // this command can be run before loading any binaries. Do just a
2365 // best-effort name-based lookup here to try to prevent conflicts.
2366 FormattersMatchCandidate candidate_type(
2367 type_name, nullptr, TypeImpl(), FormattersMatchCandidate::Flags());
2368 lldb::SyntheticChildrenSP entry;
2369 if (category->AnyMatches(candidate_type, eFormatCategoryItemSynth,
2370 false)) {
2371 if (error)
2372 *error = Status::FromErrorStringWithFormat(
2373 "cannot add filter for type %s when "
2374 "synthetic is defined in same "
2375 "category!",
2376 type_name.AsCString());
2377 return false;
2381 FormatterMatchType match_type = eFormatterMatchExact;
2382 if (type == eRegexFilter) {
2383 match_type = eFormatterMatchRegex;
2384 RegularExpression typeRX(type_name.GetStringRef());
2385 if (!typeRX.IsValid()) {
2386 if (error)
2387 *error = Status::FromErrorString(
2388 "regex format error (maybe this is not really a regex?)");
2389 return false;
2392 category->AddTypeFilter(type_name.GetStringRef(), match_type, entry);
2393 return true;
2396 public:
2397 CommandObjectTypeFilterAdd(CommandInterpreter &interpreter)
2398 : CommandObjectParsed(interpreter, "type filter add",
2399 "Add a new filter for a type.", nullptr) {
2400 AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus);
2402 SetHelpLong(
2404 The following examples of 'type filter add' refer to this code snippet for context:
2406 class Foo {
2407 int a;
2408 int b;
2409 int c;
2410 int d;
2411 int e;
2412 int f;
2413 int g;
2414 int h;
2415 int i;
2417 Foo my_foo;
2419 Adding a simple filter:
2421 (lldb) type filter add --child a --child g Foo
2422 (lldb) frame variable my_foo
2425 "Produces output where only a and g are displayed. Other children of my_foo \
2426 (b, c, d, e, f, h and i) are available by asking for them explicitly:"
2429 (lldb) frame variable my_foo.b my_foo.c my_foo.i
2432 "The formatting option --raw on frame variable bypasses the filter, showing \
2433 all children of my_foo as if no filter was defined:"
2436 (lldb) frame variable my_foo --raw)");
2439 ~CommandObjectTypeFilterAdd() override = default;
2441 protected:
2442 void DoExecute(Args &command, CommandReturnObject &result) override {
2443 const size_t argc = command.GetArgumentCount();
2445 if (argc < 1) {
2446 result.AppendErrorWithFormat("%s takes one or more args.\n",
2447 m_cmd_name.c_str());
2448 return;
2451 if (m_options.m_expr_paths.empty()) {
2452 result.AppendErrorWithFormat("%s needs one or more children.\n",
2453 m_cmd_name.c_str());
2454 return;
2457 TypeFilterImplSP entry(new TypeFilterImpl(
2458 SyntheticChildren::Flags()
2459 .SetCascades(m_options.m_cascade)
2460 .SetSkipPointers(m_options.m_skip_pointers)
2461 .SetSkipReferences(m_options.m_skip_references)));
2463 // go through the expression paths
2464 CommandOptions::ExpressionPathsIterator begin,
2465 end = m_options.m_expr_paths.end();
2467 for (begin = m_options.m_expr_paths.begin(); begin != end; begin++)
2468 entry->AddExpressionPath(*begin);
2470 // now I have a valid provider, let's add it to every type
2472 lldb::TypeCategoryImplSP category;
2473 DataVisualization::Categories::GetCategory(
2474 ConstString(m_options.m_category.c_str()), category);
2476 Status error;
2478 WarnOnPotentialUnquotedUnsignedType(command, result);
2480 for (auto &arg_entry : command.entries()) {
2481 if (arg_entry.ref().empty()) {
2482 result.AppendError("empty typenames not allowed");
2483 return;
2486 ConstString typeCS(arg_entry.ref());
2487 if (!AddFilter(typeCS, entry,
2488 m_options.m_regex ? eRegexFilter : eRegularFilter,
2489 m_options.m_category, &error)) {
2490 result.AppendError(error.AsCString());
2491 return;
2495 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2499 // "type lookup"
2500 #define LLDB_OPTIONS_type_lookup
2501 #include "CommandOptions.inc"
2503 class CommandObjectTypeLookup : public CommandObjectRaw {
2504 protected:
2505 // this function is allowed to do a more aggressive job at guessing languages
2506 // than the expression parser is comfortable with - so leave the original
2507 // call alone and add one that is specific to type lookup
2508 lldb::LanguageType GuessLanguage(StackFrame *frame) {
2509 lldb::LanguageType lang_type = lldb::eLanguageTypeUnknown;
2511 if (!frame)
2512 return lang_type;
2514 lang_type = frame->GuessLanguage().AsLanguageType();
2515 if (lang_type != lldb::eLanguageTypeUnknown)
2516 return lang_type;
2518 Symbol *s = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
2519 if (s)
2520 lang_type = s->GetMangled().GuessLanguage();
2522 return lang_type;
2525 class CommandOptions : public OptionGroup {
2526 public:
2527 CommandOptions() = default;
2529 ~CommandOptions() override = default;
2531 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2532 return llvm::ArrayRef(g_type_lookup_options);
2535 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
2536 ExecutionContext *execution_context) override {
2537 Status error;
2539 const int short_option = g_type_lookup_options[option_idx].short_option;
2541 switch (short_option) {
2542 case 'h':
2543 m_show_help = true;
2544 break;
2546 case 'l':
2547 m_language = Language::GetLanguageTypeFromString(option_value);
2548 break;
2550 default:
2551 llvm_unreachable("Unimplemented option");
2554 return error;
2557 void OptionParsingStarting(ExecutionContext *execution_context) override {
2558 m_show_help = false;
2559 m_language = eLanguageTypeUnknown;
2562 // Options table: Required for subclasses of Options.
2564 bool m_show_help = false;
2565 lldb::LanguageType m_language = eLanguageTypeUnknown;
2568 OptionGroupOptions m_option_group;
2569 CommandOptions m_command_options;
2571 public:
2572 CommandObjectTypeLookup(CommandInterpreter &interpreter)
2573 : CommandObjectRaw(interpreter, "type lookup",
2574 "Lookup types and declarations in the current target, "
2575 "following language-specific naming conventions.",
2576 "type lookup <type-specifier>",
2577 eCommandRequiresTarget) {
2578 m_option_group.Append(&m_command_options);
2579 m_option_group.Finalize();
2582 ~CommandObjectTypeLookup() override = default;
2584 Options *GetOptions() override { return &m_option_group; }
2586 llvm::StringRef GetHelpLong() override {
2587 if (!m_cmd_help_long.empty())
2588 return m_cmd_help_long;
2590 StreamString stream;
2591 Language::ForEach([&](Language *lang) {
2592 if (const char *help = lang->GetLanguageSpecificTypeLookupHelp())
2593 stream.Printf("%s\n", help);
2594 return true;
2597 m_cmd_help_long = std::string(stream.GetString());
2598 return m_cmd_help_long;
2601 void DoExecute(llvm::StringRef raw_command_line,
2602 CommandReturnObject &result) override {
2603 if (raw_command_line.empty()) {
2604 result.AppendError(
2605 "type lookup cannot be invoked without a type name as argument");
2606 return;
2609 auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
2610 m_option_group.NotifyOptionParsingStarting(&exe_ctx);
2612 OptionsWithRaw args(raw_command_line);
2613 const char *name_of_type = args.GetRawPart().c_str();
2615 if (args.HasArgs())
2616 if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group,
2617 exe_ctx))
2618 return;
2620 ExecutionContextScope *best_scope = exe_ctx.GetBestExecutionContextScope();
2622 bool any_found = false;
2624 std::vector<Language *> languages;
2626 bool is_global_search = false;
2627 LanguageType guessed_language = lldb::eLanguageTypeUnknown;
2629 if ((is_global_search =
2630 (m_command_options.m_language == eLanguageTypeUnknown))) {
2631 Language::ForEach([&](Language *lang) {
2632 languages.push_back(lang);
2633 return true;
2635 } else {
2636 languages.push_back(Language::FindPlugin(m_command_options.m_language));
2639 // This is not the most efficient way to do this, but we support very few
2640 // languages so the cost of the sort is going to be dwarfed by the actual
2641 // lookup anyway
2642 if (StackFrame *frame = m_exe_ctx.GetFramePtr()) {
2643 guessed_language = GuessLanguage(frame);
2644 if (guessed_language != eLanguageTypeUnknown) {
2645 llvm::sort(
2646 languages.begin(), languages.end(),
2647 [guessed_language](Language *lang1, Language *lang2) -> bool {
2648 if (!lang1 || !lang2)
2649 return false;
2650 LanguageType lt1 = lang1->GetLanguageType();
2651 LanguageType lt2 = lang2->GetLanguageType();
2652 if (lt1 == lt2)
2653 return false;
2654 if (lt1 == guessed_language)
2655 return true; // make the selected frame's language come first
2656 if (lt2 == guessed_language)
2657 return false; // make the selected frame's language come first
2658 return (lt1 < lt2); // normal comparison otherwise
2663 bool is_first_language = true;
2665 for (Language *language : languages) {
2666 if (!language)
2667 continue;
2669 if (auto scavenger = language->GetTypeScavenger()) {
2670 Language::TypeScavenger::ResultSet search_results;
2671 if (scavenger->Find(best_scope, name_of_type, search_results) > 0) {
2672 for (const auto &search_result : search_results) {
2673 if (search_result && search_result->IsValid()) {
2674 any_found = true;
2675 search_result->DumpToStream(result.GetOutputStream(),
2676 this->m_command_options.m_show_help);
2681 // this is "type lookup SomeName" and we did find a match, so get out
2682 if (any_found && is_global_search)
2683 break;
2684 else if (is_first_language && is_global_search &&
2685 guessed_language != lldb::eLanguageTypeUnknown) {
2686 is_first_language = false;
2687 result.GetOutputStream().Printf(
2688 "no type was found in the current language %s matching '%s'; "
2689 "performing a global search across all languages\n",
2690 Language::GetNameForLanguageType(guessed_language), name_of_type);
2694 if (!any_found)
2695 result.AppendMessageWithFormat("no type was found matching '%s'\n",
2696 name_of_type);
2698 result.SetStatus(any_found ? lldb::eReturnStatusSuccessFinishResult
2699 : lldb::eReturnStatusSuccessFinishNoResult);
2703 template <typename FormatterType>
2704 class CommandObjectFormatterInfo : public CommandObjectRaw {
2705 public:
2706 typedef std::function<typename FormatterType::SharedPointer(ValueObject &)>
2707 DiscoveryFunction;
2708 CommandObjectFormatterInfo(CommandInterpreter &interpreter,
2709 const char *formatter_name,
2710 DiscoveryFunction discovery_func)
2711 : CommandObjectRaw(interpreter, "", "", "", eCommandRequiresFrame),
2712 m_formatter_name(formatter_name ? formatter_name : ""),
2713 m_discovery_function(discovery_func) {
2714 StreamString name;
2715 name.Printf("type %s info", formatter_name);
2716 SetCommandName(name.GetString());
2717 StreamString help;
2718 help.Printf("This command evaluates the provided expression and shows "
2719 "which %s is applied to the resulting value (if any).",
2720 formatter_name);
2721 SetHelp(help.GetString());
2722 StreamString syntax;
2723 syntax.Printf("type %s info <expr>", formatter_name);
2724 SetSyntax(syntax.GetString());
2727 ~CommandObjectFormatterInfo() override = default;
2729 protected:
2730 void DoExecute(llvm::StringRef command,
2731 CommandReturnObject &result) override {
2732 TargetSP target_sp = GetDebugger().GetSelectedTarget();
2733 Thread *thread = GetDefaultThread();
2734 if (!thread) {
2735 result.AppendError("no default thread");
2736 return;
2739 StackFrameSP frame_sp =
2740 thread->GetSelectedFrame(DoNoSelectMostRelevantFrame);
2741 ValueObjectSP result_valobj_sp;
2742 EvaluateExpressionOptions options;
2743 lldb::ExpressionResults expr_result = target_sp->EvaluateExpression(
2744 command, frame_sp.get(), result_valobj_sp, options);
2745 if (expr_result == eExpressionCompleted && result_valobj_sp) {
2746 result_valobj_sp =
2747 result_valobj_sp->GetQualifiedRepresentationIfAvailable(
2748 target_sp->GetPreferDynamicValue(),
2749 target_sp->GetEnableSyntheticValue());
2750 typename FormatterType::SharedPointer formatter_sp =
2751 m_discovery_function(*result_valobj_sp);
2752 if (formatter_sp) {
2753 std::string description(formatter_sp->GetDescription());
2754 result.GetOutputStream()
2755 << m_formatter_name << " applied to ("
2756 << result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>")
2757 << ") " << command << " is: " << description << "\n";
2758 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
2759 } else {
2760 result.GetOutputStream()
2761 << "no " << m_formatter_name << " applies to ("
2762 << result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>")
2763 << ") " << command << "\n";
2764 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
2766 } else {
2767 result.AppendError("failed to evaluate expression");
2771 private:
2772 std::string m_formatter_name;
2773 DiscoveryFunction m_discovery_function;
2776 class CommandObjectTypeFormat : public CommandObjectMultiword {
2777 public:
2778 CommandObjectTypeFormat(CommandInterpreter &interpreter)
2779 : CommandObjectMultiword(
2780 interpreter, "type format",
2781 "Commands for customizing value display formats.",
2782 "type format [<sub-command-options>] ") {
2783 LoadSubCommand(
2784 "add", CommandObjectSP(new CommandObjectTypeFormatAdd(interpreter)));
2785 LoadSubCommand("clear", CommandObjectSP(
2786 new CommandObjectTypeFormatClear(interpreter)));
2787 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeFormatDelete(
2788 interpreter)));
2789 LoadSubCommand(
2790 "list", CommandObjectSP(new CommandObjectTypeFormatList(interpreter)));
2791 LoadSubCommand(
2792 "info", CommandObjectSP(new CommandObjectFormatterInfo<TypeFormatImpl>(
2793 interpreter, "format",
2794 [](ValueObject &valobj) -> TypeFormatImpl::SharedPointer {
2795 return valobj.GetValueFormat();
2796 })));
2799 ~CommandObjectTypeFormat() override = default;
2802 class CommandObjectTypeSynth : public CommandObjectMultiword {
2803 public:
2804 CommandObjectTypeSynth(CommandInterpreter &interpreter)
2805 : CommandObjectMultiword(
2806 interpreter, "type synthetic",
2807 "Commands for operating on synthetic type representations.",
2808 "type synthetic [<sub-command-options>] ") {
2809 LoadSubCommand("add",
2810 CommandObjectSP(new CommandObjectTypeSynthAdd(interpreter)));
2811 LoadSubCommand(
2812 "clear", CommandObjectSP(new CommandObjectTypeSynthClear(interpreter)));
2813 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeSynthDelete(
2814 interpreter)));
2815 LoadSubCommand(
2816 "list", CommandObjectSP(new CommandObjectTypeSynthList(interpreter)));
2817 LoadSubCommand(
2818 "info",
2819 CommandObjectSP(new CommandObjectFormatterInfo<SyntheticChildren>(
2820 interpreter, "synthetic",
2821 [](ValueObject &valobj) -> SyntheticChildren::SharedPointer {
2822 return valobj.GetSyntheticChildren();
2823 })));
2826 ~CommandObjectTypeSynth() override = default;
2829 class CommandObjectTypeFilter : public CommandObjectMultiword {
2830 public:
2831 CommandObjectTypeFilter(CommandInterpreter &interpreter)
2832 : CommandObjectMultiword(interpreter, "type filter",
2833 "Commands for operating on type filters.",
2834 "type filter [<sub-command-options>] ") {
2835 LoadSubCommand(
2836 "add", CommandObjectSP(new CommandObjectTypeFilterAdd(interpreter)));
2837 LoadSubCommand("clear", CommandObjectSP(
2838 new CommandObjectTypeFilterClear(interpreter)));
2839 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeFilterDelete(
2840 interpreter)));
2841 LoadSubCommand(
2842 "list", CommandObjectSP(new CommandObjectTypeFilterList(interpreter)));
2845 ~CommandObjectTypeFilter() override = default;
2848 class CommandObjectTypeCategory : public CommandObjectMultiword {
2849 public:
2850 CommandObjectTypeCategory(CommandInterpreter &interpreter)
2851 : CommandObjectMultiword(interpreter, "type category",
2852 "Commands for operating on type categories.",
2853 "type category [<sub-command-options>] ") {
2854 LoadSubCommand(
2855 "define",
2856 CommandObjectSP(new CommandObjectTypeCategoryDefine(interpreter)));
2857 LoadSubCommand(
2858 "enable",
2859 CommandObjectSP(new CommandObjectTypeCategoryEnable(interpreter)));
2860 LoadSubCommand(
2861 "disable",
2862 CommandObjectSP(new CommandObjectTypeCategoryDisable(interpreter)));
2863 LoadSubCommand(
2864 "delete",
2865 CommandObjectSP(new CommandObjectTypeCategoryDelete(interpreter)));
2866 LoadSubCommand("list", CommandObjectSP(
2867 new CommandObjectTypeCategoryList(interpreter)));
2870 ~CommandObjectTypeCategory() override = default;
2873 class CommandObjectTypeSummary : public CommandObjectMultiword {
2874 public:
2875 CommandObjectTypeSummary(CommandInterpreter &interpreter)
2876 : CommandObjectMultiword(
2877 interpreter, "type summary",
2878 "Commands for editing variable summary display options.",
2879 "type summary [<sub-command-options>] ") {
2880 LoadSubCommand(
2881 "add", CommandObjectSP(new CommandObjectTypeSummaryAdd(interpreter)));
2882 LoadSubCommand("clear", CommandObjectSP(new CommandObjectTypeSummaryClear(
2883 interpreter)));
2884 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeSummaryDelete(
2885 interpreter)));
2886 LoadSubCommand(
2887 "list", CommandObjectSP(new CommandObjectTypeSummaryList(interpreter)));
2888 LoadSubCommand(
2889 "info", CommandObjectSP(new CommandObjectFormatterInfo<TypeSummaryImpl>(
2890 interpreter, "summary",
2891 [](ValueObject &valobj) -> TypeSummaryImpl::SharedPointer {
2892 return valobj.GetSummaryFormat();
2893 })));
2896 ~CommandObjectTypeSummary() override = default;
2899 // CommandObjectType
2901 CommandObjectType::CommandObjectType(CommandInterpreter &interpreter)
2902 : CommandObjectMultiword(interpreter, "type",
2903 "Commands for operating on the type system.",
2904 "type [<sub-command-options>]") {
2905 LoadSubCommand("category",
2906 CommandObjectSP(new CommandObjectTypeCategory(interpreter)));
2907 LoadSubCommand("filter",
2908 CommandObjectSP(new CommandObjectTypeFilter(interpreter)));
2909 LoadSubCommand("format",
2910 CommandObjectSP(new CommandObjectTypeFormat(interpreter)));
2911 LoadSubCommand("summary",
2912 CommandObjectSP(new CommandObjectTypeSummary(interpreter)));
2913 LoadSubCommand("synthetic",
2914 CommandObjectSP(new CommandObjectTypeSynth(interpreter)));
2915 LoadSubCommand("lookup",
2916 CommandObjectSP(new CommandObjectTypeLookup(interpreter)));
2919 CommandObjectType::~CommandObjectType() = default;